Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ jobs:
- name: Verify screenshots, original requests and recordings
run: python3 scripts/ci/check-media-report.py

- name: Verify the native-stage proof block and record
run: python3 scripts/ci/check-native-stage-proof.py

- name: Install dependencies
run: npm ci

Expand Down
6 changes: 3 additions & 3 deletions reports/conloca-2026-10/index.html

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions reports/conloca-2026-10/native-stage-proof.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"purpose": "Verification record for the 7 November native-stage proof block of the Conloca October report; a private temporary artifact, not a public rehost.",
"verifiedAt": "2026-11-07T13:45:00Z",
"head": "9d469170dbe5504704dae7b6a32d4825cdb11765",
"build": "ce4948f9558870dce11f07102a643e2807c73395",
"stageUrls": [
"https://site.pr404.conloca.com/",
"https://app.pr404.conloca.com/",
"https://storybook.pr404.conloca.com/"
],
"runUrl": "https://github.com/conloca/private/actions/runs/42375596312",
"runId": 42375596312,
"artifactId": 13576130686,
"artifactUrl": "https://github.com/conloca/private/actions/runs/42375596312/artifacts/13576130686",
"artifactSha256": "85cef4edb76cfb7f3292c93c060e57e1e9cdb6625ea5738be4cc5d5ce1859cf5",
"artifactSize": 519359,
"artifactExpiresAt": "2026-11-21T13:18:03Z",
"videos": [
{
"id": "cms",
"width": 1280,
"height": 800,
"durationSeconds": 5.6,
"frames": 140,
"sha256": "7c7739c6526730c3ea906b852e7f2ce7a0d7df39d218a6147954b6cea2257f2a"
},
{
"id": "app",
"width": 390,
"height": 844,
"durationSeconds": 4.88,
"frames": 122,
"sha256": "1fcf67580aec5acd7bd74c70b20d565b229f5d1f9c9f92ea53e2baa181105e00"
}
],
"kind": "private-temporary-ci-artifact-not-embedded"
}
2 changes: 1 addition & 1 deletion scripts/ci/check-media-report.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ def test_public_record_and_pages_hold_no_private_identifiers(self):
self.assertNotIn(b, blob, b)

def test_links_on_the_pages_stay_on_allowed_origins(self):
allowed = ("https://github.com/", "https://tasks.glide.vc/", "https://conloca.com", "https://site.pr489.conloca.com/", "https://linear.app/")
allowed = ("https://github.com/", "https://tasks.glide.vc/", "https://conloca.com", "https://site.pr489.conloca.com/", "https://site.pr404.conloca.com/", "https://app.pr404.conloca.com/", "https://storybook.pr404.conloca.com/", "https://linear.app/")
for key, page in self.pages.items():
for url in Links(page).urls:
if url.startswith("http"):
Expand Down
104 changes: 104 additions & 0 deletions scripts/ci/check-native-stage-proof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""Contract for the 7 November native-stage proof block on the Conloca October report.

The block and reports/conloca-2026-10/native-stage-proof.json must agree. The October period and the
October counts stay untouched; the November addendum is a separate, dated block.

Run: python3 scripts/ci/check-native-stage-proof.py
"""

import json
import re
import sys
import unittest
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
from _report_html import Links, VisibleText # noqa: E402

ROOT = Path(__file__).resolve().parents[2]
DIR = ROOT / "reports/conloca-2026-10"
HEAD = "9d469170dbe5504704dae7b6a32d4825cdb11765"
RUN = "https://github.com/conloca/private/actions/runs/42375596312"
ARTIFACT = "https://github.com/conloca/private/actions/runs/42375596312/artifacts/13576130686"
STAGES = ["https://site.pr404.conloca.com/", "https://app.pr404.conloca.com/", "https://storybook.pr404.conloca.com/"]


class NativeStageProof(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.raw = (DIR / "index.html").read_text(encoding="utf-8")
cls.rec = json.loads((DIR / "native-stage-proof.json").read_text(encoding="utf-8"))
cls.block = cls.raw.split('id="native-stage-proof"', 1)[1].split("</section>", 1)[0]
cls.text = VisibleText(cls.block).raw

def test_three_direct_stage_links_and_nothing_else_for_stages(self):
urls = [u for u in Links(self.block).urls if "pr404.conloca.com" in u]
self.assertEqual(urls, STAGES)
self.assertEqual(self.rec["stageUrls"], STAGES)
for label in ("Landing", "CMS app", "Storybook"):
self.assertIn(label, self.text)

def test_run_and_artifact_links_are_distinct_and_exact(self):
urls = Links(self.block).urls
self.assertIn(RUN, urls)
self.assertIn(ARTIFACT, urls)
self.assertNotEqual(self.rec["runUrl"], self.rec["artifactUrl"])
self.assertEqual((self.rec["runUrl"], self.rec["artifactUrl"]), (RUN, ARTIFACT))
self.assertEqual(self.rec["runId"], 42375596312)
self.assertEqual(self.rec["artifactId"], 13576130686)
self.assertIn("https://github.com/conloca/private/pull/404", urls)

def test_artifact_is_labelled_private_and_temporary_and_not_embedded(self):
low = self.text.casefold()
for word in ("access-restricted", "temporary", "2026-11-21", "not full product acceptance", "deployed on pr404; not merged"):
self.assertIn(word, low)
self.assertIn("not a permanent video archive", low)
self.assertNotRegex(self.block, r"<video\b|<source\b|<iframe\b|<img\b|\.webm|\.png|\.zip")
self.assertRegex(self.rec["kind"], r"private")

def test_record_holds_exact_head_build_hashes_and_no_private_payload(self):
r = self.rec
self.assertEqual(r["head"], HEAD)
self.assertEqual(r["build"], "ce4948f9558870dce11f07102a643e2807c73395")
self.assertEqual(r["verifiedAt"][:10], "2026-11-07")
self.assertEqual((r["artifactSize"], r["artifactExpiresAt"]), (519359, "2026-11-21T13:18:03Z"))
self.assertEqual(r["artifactSha256"], "85cef4edb76cfb7f3292c93c060e57e1e9cdb6625ea5738be4cc5d5ce1859cf5")
v = {x["id"]: x for x in r["videos"]}
self.assertEqual(len(v), 2)
self.assertEqual((v["cms"]["width"], v["cms"]["height"], v["cms"]["durationSeconds"], v["cms"]["frames"]), (1280, 800, 5.6, 140))
self.assertEqual((v["app"]["width"], v["app"]["height"], v["app"]["durationSeconds"], v["app"]["frames"]), (390, 844, 4.88, 122))
self.assertEqual(v["cms"]["sha256"], "7c7739c6526730c3ea906b852e7f2ce7a0d7df39d218a6147954b6cea2257f2a")
self.assertEqual(v["app"]["sha256"], "1fcf67580aec5acd7bd74c70b20d565b229f5d1f9c9f92ea53e2baa181105e00")
self.assertEqual(set(r), {"purpose", "verifiedAt", "head", "build", "stageUrls", "runUrl", "runId", "artifactId", "artifactUrl", "artifactSha256", "artifactSize", "artifactExpiresAt", "videos", "kind"})
blob = json.dumps(r)
for banned in ("cookie", "storageState", "/home/", "token", "catalogue"):
self.assertNotIn(banned, blob)

def test_october_period_and_counts_survive_and_november_is_separate(self):
page = self.raw
for needle in ("October 2026", "Conloca: October 2026"):
self.assertIn(needle, page)
ev = {s: json.loads((ROOT / "reports" / s / "media-evidence.json").read_text()) for s in ("hyper-2026-10", "state-lib-2026-10", "conloca-2026-10")}
self.assertEqual(sum(len(e["images"]) for e in ev.values()), 36)
self.assertEqual(sum(len(e["originalRequests"]) for e in ev.values()), 26)
self.assertEqual(sum(len(e["videos"]) for e in ev.values()), 4)
mine = ev["conloca-2026-10"]
self.assertEqual(len(re.findall(r'class="owner-request"', page)), len(mine["originalRequests"]))
self.assertEqual(len(re.findall(r"<img\b", page)), len(mine["images"]))
self.assertEqual(len(re.findall(r"<video\b", page)), len(mine["videos"]))
self.assertNotIn("keeps no video or trace artifact", page)
proof = page.split('id="proof"', 1)[1]
self.assertIn("four clips", VisibleText(proof).raw)
self.assertIn("production browser checks", VisibleText(proof).raw)
self.assertNotIn("November 2026 · Ultra", page)
self.assertEqual(self.block.count("class=\"outcome\""), 0)

def test_block_is_inside_the_static_html_and_before_proof_link_list(self):
self.assertLess(self.raw.index('id="coverage"'), self.raw.index('id="native-stage-proof"'))
self.assertIn('href: "#native-stage-proof"', self.raw)
self.assertNotIn("display:none", self.block.replace(" ", ""))
self.assertNotIn("<details open", self.block)


if __name__ == "__main__":
unittest.main()
5 changes: 4 additions & 1 deletion scripts/ci/check-own-results.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ def test_new_workflows_not_presented_as_merged(self):
def test_all_ci_links_have_source_receipts(self):
receipts = {r["url"] for r in self.data.get("checks", [])}
for slug in self.data["reports"]:
for url in Links((ROOT / "reports" / slug / "index.html").read_text()).urls:
page = (ROOT / "reports" / slug / "index.html").read_text()
# The November native-stage block is covered by its own record and contract (check-native-stage-proof.py).
page = re.sub(r'<section class="report-section" id="native-stage-proof">.*?</section>', "", page, flags=re.S)
for url in Links(page).urls:
if "/actions/runs/" in url:
self.assertIn(url, receipts)

Expand Down
Loading