Scope browser OS acquisition to the runner's signed Ubuntu sources

An unrelated Microsoft repository returned 403 during fresh-index admission and stopped a browser shard before any test could run. Load the hosted runner's existing Ubuntu Deb822 definition for browser packages, preserving its mirrors and signature policy. Fail when that definition is missing, unreadable or empty and keep strict index and archive hash checks.

Exercise the real apt parser, exclusion of unrelated feeds, missing definitions and incomplete index failures in private acquisition directories. Register the package helper and policy with their exact verification routes, and update the fixture helper's governance assertion to its scoped proof contract.
This commit is contained in:
rcourtman
2026-10-25 04:00:03 +00:00
parent 473926b495
commit 64c0a3f9df
5 changed files with 136 additions and 7 deletions
@@ -1998,6 +1998,8 @@ Windows lifecycle controls or macOS installer and logging checks on native CI.
105. `scripts/dependency_advisory_watch.py`
106. `tests/integration/scripts/settings-scroll-audit.mjs`
107. `tests/integration/scripts/managed-local-backend.mjs`
108. `scripts/browser_os_packages.py`
109. `scripts/playwright-apt.conf`
`scripts/installtests/run_unix_contracts.py` is the canonical exhaustive native Unix installer execution runner. Its dedicated verification files are `scripts/installtests/native_unix_contract_runner_test.go` and `scripts/tests/test_native_installer_contract_runner.py`. Script-smoke discovery and the native Go wrapper execute that same Python control suite, so phase inventory, failure propagation and real compiled-Go exit behavior retain one verification source.
@@ -8323,9 +8325,15 @@ packages for Chromium and WebKit from the runner's Azure mirror. From
minute ran past their 10 and 30 minute budgets before any test started. The
jobs now restore the newest saved package set with `actions/cache/restore`
(v6.1.0, pinned by SHA) and admit it through `scripts/browser_os_packages.py`:
after a bounded `apt-get update`, a cached `.deb` reaches apt's archive
after a bounded `apt-get update` scoped to the runner's existing Ubuntu
Deb822 source definition, a cached `.deb` reaches apt's archive
directory only when the SHA256 of the private copy it installs equals a signed
index value for the package, version, and architecture named by its filename.
The original Ubuntu mirror and `Signed-By` settings remain authoritative.
An absent, unreadable or empty distribution definition fails acquisition.
Unrelated vendor feeds do not participate in browser OS acquisition. Failed
Ubuntu index updates still fail, and TLS, signature and archive-hash validation
remain enforced. This policy changes no host repository definition files.
That check is ours, because apt reuses an archive-directory file after
checking only its size.
After a successful install, and before any journey runs, the helper rebuilds
@@ -4668,6 +4668,7 @@
"pulse-pro:scripts/tests/test_validate_paid_runtime_distribution.py",
"pulse-pro:scripts/validate_paid_runtime_distribution.py",
"scripts/backfill-release-assets.sh",
"scripts/browser_os_packages.py",
"scripts/build-release-binaries.sh",
"scripts/build-release.sh",
"scripts/build-secure-runtime-qualification.sh",
@@ -4697,6 +4698,7 @@
"scripts/installtests/testdata/secure_runtime_docker_fixture.go",
"scripts/lib/hot-dev-auth.sh",
"scripts/lib/hot-dev-runtime.sh",
"scripts/playwright-apt.conf",
"scripts/prepare-release-container-context.sh",
"scripts/pulse-auto-update.sh",
"scripts/release-preflight-worker.sh",
@@ -5357,6 +5359,21 @@
"scripts/tests/test_go_mod_download.py"
]
},
{
"id": "browser-os-acquisition",
"label": "signed Ubuntu browser dependency acquisition proof",
"match_prefixes": [],
"match_files": [
"scripts/browser_os_packages.py",
"scripts/playwright-apt.conf"
],
"allow_same_subsystem_tests": false,
"test_prefixes": [],
"exact_files": [
"scripts/tests/test_browser_os_packages.py",
"scripts/tests/test_playwright_acquisition.py"
]
},
{
"id": "e2e-image-distribution",
"label": "same-run source-bound E2E image distribution proof",
+7 -2
View File
@@ -1,5 +1,10 @@
// Bound apt transport inside disposable GitHub E2E runners. Do not replace
// repositories, disable TLS/signatures or accept an incomplete index as success.
// Browser OS dependencies come from the hosted Ubuntu runner's existing
// distribution definition. Preserve its mirrors and Signed-By settings while
// keeping unrelated vendor feeds outside this acquisition. Do not disable
// TLS/signatures or accept an incomplete Ubuntu index as success.
Dir::Etc::sourcelist "/etc/apt/sources.list.d/ubuntu.sources";
Dir::Etc::sourceparts "-";
APT::Update::Pre-Invoke:: "test -r /etc/apt/sources.list.d/ubuntu.sources && test -s /etc/apt/sources.list.d/ubuntu.sources";
Acquire::http::Timeout "30";
Acquire::https::Timeout "30";
Acquire::Retries "2";
@@ -100,7 +100,6 @@ class DevRuntimeGovernanceTest(unittest.TestCase):
"tests/integration/README.md",
"tests/integration/QUICK_START.md",
"tests/integration/playwright.config.ts",
"tests/integration/tests/helpers.ts",
"tests/integration/tests/runtime-defaults.ts",
]
)
@@ -128,6 +127,34 @@ class DevRuntimeGovernanceTest(unittest.TestCase):
match["verification_requirement"]["exact_files"],
)
def test_lookup_maps_browser_helpers_to_scoped_fixture_proof(self) -> None:
result = lookup_paths(["tests/integration/tests/helpers.ts"])
self.assertEqual(result["unowned_runtime_files"], [])
match = result["files"][0]["matches"][0]
self.assertEqual(match["subsystem"], "deployment-installability")
proof = match["verification_requirement"]
self.assertEqual(proof["id"], "browser-fixture-helpers")
self.assertIn("tests/integration/scripts/fixture-auth.test.mjs", proof["exact_files"])
self.assertIn("tests/integration/scripts/organization-fixtures.test.mjs", proof["exact_files"])
self.assertFalse(proof["allow_same_subsystem_tests"])
def test_lookup_maps_browser_acquisition_to_signed_package_proof(self) -> None:
result = lookup_paths(["scripts/playwright-apt.conf", "scripts/browser_os_packages.py"])
self.assertEqual(result["unowned_runtime_files"], [])
for entry in result["files"]:
self.assertEqual(entry["classification"], "runtime")
self.assertEqual(len(entry["matches"]), 1)
match = entry["matches"][0]
self.assertEqual(match["subsystem"], "deployment-installability")
proof = match["verification_requirement"]
self.assertEqual(proof["id"], "browser-os-acquisition")
self.assertEqual(proof["exact_files"], [
"scripts/tests/test_browser_os_packages.py",
"scripts/tests/test_playwright_acquisition.py",
])
self.assertFalse(proof["allow_same_subsystem_tests"])
self.assertEqual(proof["test_prefixes"], [])
def test_lookup_maps_release_promotion_workflows_to_installability(self) -> None:
result = lookup_paths(
[
+75 -3
View File
@@ -21,6 +21,7 @@ INSTALL_POLICY = (
# successful install is cached even when later journeys fail.
CACHE_PIN = "55cc8345863c7cc4c66a329aec7e433d2d1c52a9"
CACHE_DIR = '"$HOME/.cache/pulse-browser-os-packages"'
UBUNTU_SOURCES = "/etc/apt/sources.list.d/ubuntu.sources"
def job_block(workflow, job):
@@ -158,7 +159,7 @@ class PlaywrightAcquisitionTest(unittest.TestCase):
self.assertTrue(result.failures)
self.assertFalse(result.errors)
def test_real_apt_parser_loads_only_the_four_expected_controls(self):
def test_real_apt_parser_loads_only_the_expected_controls(self):
with tempfile.TemporaryDirectory() as temp:
config = Path(temp) / "apt.conf"
config.write_text(
@@ -169,6 +170,9 @@ class PlaywrightAcquisitionTest(unittest.TestCase):
capture_output=True, text=True, timeout=10, check=True,
).stdout
expected = {
"Dir::Etc::sourcelist": UBUNTU_SOURCES,
"Dir::Etc::sourceparts": "-",
"APT::Update::Pre-Invoke::": f"test -r {UBUNTU_SOURCES} && test -s {UBUNTU_SOURCES}",
"Acquire::http::Timeout": "30",
"Acquire::https::Timeout": "30",
"Acquire::Retries": "2",
@@ -181,6 +185,72 @@ class PlaywrightAcquisitionTest(unittest.TestCase):
self.assertNotIn("AllowUnauthenticated", parsed)
self.assertNotIn("Verify-Peer", parsed)
def test_real_apt_preserves_ubuntu_sources_and_excludes_unrelated_feeds(self):
# Print acquisition URIs without contacting a repository or touching
# host state. Both configurations retain the same signed Ubuntu source;
# the adverse control also admits an unrelated, unreachable vendor feed.
with tempfile.TemporaryDirectory() as temp:
root = Path(temp)
parts = root / "sources.list.d"
parts.mkdir()
ubuntu = parts / "ubuntu.sources"
definition = (
"Types: deb\nURIs: http://127.0.0.1:1/ubuntu/\n"
"Suites: noble\nComponents: main\nArchitectures: amd64\n"
"Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\n"
)
ubuntu.write_text(definition)
(parts / "unrelated-vendor.list").write_text(
"deb http://127.0.0.1:1/vendor/ stable main\n"
)
(root / "lists/partial").mkdir(parents=True)
(root / "cache/archives/partial").mkdir(parents=True)
prefix = (
'Dir::Etc::parts "-";\nDir::Etc::main "-";\n'
f'Dir::Etc::sourcelist "-";\nDir::Etc::sourceparts "{parts}";\n'
f'Dir::State::lists "{root / "lists"}";\n'
f'Dir::Cache "{root / "cache"}";\n'
'Dir::State::status "/dev/null";\nDebug::NoLocking "true";\n'
)
policy = POLICY.read_text().replace(UBUNTU_SOURCES, str(ubuntu))
config = root / "apt.conf"
for scoped in (True, False):
selected = policy
if not scoped:
selected = re.sub(r'^Dir::Etc::source(?:list|parts) .*;\n', '', selected, flags=re.M)
config.write_text(prefix + selected)
result = subprocess.run(
["apt-get", "update", "--print-uris"],
env={**os.environ, "APT_CONFIG": str(config), "LC_ALL": "C"},
capture_output=True, text=True, timeout=10, check=True,
)
with self.subTest(scoped=scoped):
self.assertIn("http://127.0.0.1:1/ubuntu/", result.stdout)
self.assertEqual("http://127.0.0.1:1/vendor/" in result.stdout, not scoped)
self.assertEqual(ubuntu.read_text(), definition)
def test_missing_ubuntu_definition_fails_before_acquisition(self):
with tempfile.TemporaryDirectory() as temp:
root = Path(temp)
(root / "lists/partial").mkdir(parents=True)
(root / "cache/archives/partial").mkdir(parents=True)
missing = root / "missing.sources"
config = root / "apt.conf"
config.write_text(
'Dir::Etc::parts "-";\nDir::Etc::main "-";\n'
f'Dir::State::lists "{root / "lists"}";\n'
f'Dir::Cache "{root / "cache"}";\n'
'Dir::State::status "/dev/null";\nDebug::NoLocking "true";\n'
+ POLICY.read_text().replace(UBUNTU_SOURCES, str(missing))
)
result = subprocess.run(
["apt-get", "update"],
env={**os.environ, "APT_CONFIG": str(config), "LC_ALL": "C"},
capture_output=True, text=True, timeout=10,
)
self.assertEqual(result.returncode, 100, result.stdout + result.stderr)
self.assertIn("Pre-Invoke", result.stderr)
def test_incomplete_index_is_a_real_apt_failure_not_a_warning_pass(self):
# An unlistening reserved loopback port gives a definite transport
# failure. No external request, privileged apt operation, host list,
@@ -201,10 +271,12 @@ class PlaywrightAcquisitionTest(unittest.TestCase):
'Dir::State::status "/dev/null";\nDebug::NoLocking "true";\n'
)
for strict, expected_exit in ((True, 100), (False, 0)):
policy = POLICY.read_text()
policy = POLICY.read_text().replace(UBUNTU_SOURCES, str(sources))
if not strict:
policy = policy.replace('APT::Update::Error-Mode "any";', "")
config.write_text(prefix + policy)
# The controlled source overrides only the distribution path.
# Keep this a private loopback failure after policy is loaded.
config.write_text(policy + prefix)
result = subprocess.run(
["apt-get", "update"],
env={**os.environ, "APT_CONFIG": str(config), "LC_ALL": "C"},