fix(release): prevent Playwright runner download fallback

Exact admission attempted to fetch playwright@1.63.0 when the mounted runner was unavailable. Invoke the npm-ci-installed CLI directly so missing or inaccessible dependencies fail closed without substituting a registry package. Preserve the existing container identity and gates; this does not claim to resolve the observed EACCES. Exercise shell arguments and failure propagation with a mocked Docker command.

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-09-07 00:22:56 +01:00
parent a5cbbaf1d4
commit ae1ac6ae95
3 changed files with 48 additions and 1 deletions
@@ -2145,6 +2145,17 @@ artifact-selection behaviour.
secrets, and seed hosted approvals through a single explicit tenant runtime
restart when a release proof needs transactionally visible approval state.
Browser execution must invoke the npm-ci-installed
`/work/node_modules/@playwright/test/cli.js` directly with Node inside the
selected Playwright image. Missing or inaccessible mounted dependencies
must fail admission rather than trigger an npx registry download of a
substitute runner. Preserve the existing container UID/GID, mount, image
version selection and exit status. The executed-shell fixture in
`scripts/release_control/internal/release_preflight_test.py` verifies the
runner path, argument quoting, container identity and failure propagation
with mocked Docker; it is not browser qualification or proof that the
retained spawn-sh EACCES failure has been repaired.
## Forbidden Paths
1. Leaving deployment bootstrap, installer, or update-runtime files unowned under broad monitoring or generic API ownership
+4 -1
View File
@@ -257,6 +257,9 @@ else
--tag pulse:test \
.
fi
# Use only the npm-ci-installed runner. npx may fetch a different version when
# the mounted dependency tree is missing or inaccessible, masking the actual
# admission failure and breaking parity with the selected browser image.
run_playwright() {
docker run --rm \
--network host \
@@ -269,7 +272,7 @@ run_playwright() {
--volume "$REPOSITORY_DIR/tests/integration:/work" \
--workdir /work \
"$PLAYWRIGHT_IMAGE" \
npx playwright test "$@"
node /work/node_modules/@playwright/test/cli.js test "$@"
}
run_rehearsal_smoke() {
@@ -264,6 +264,39 @@ class ReleasePreflightTest(unittest.TestCase):
self.assertIn('--env "PLAYWRIGHT_BASE_URL=${PULSE_E2E_BASE_URL}"', worker)
self.assertNotIn("localhost:7655", worker)
def test_browser_uses_installed_runner_and_preserves_failure(self) -> None:
worker = (ROOT / "scripts/release-preflight-worker.sh").read_text()
function = re.search(
r"run_playwright\(\) \{.*?\n\}", worker, flags=re.DOTALL
).group(0)
# Exercise the real shell function without starting Docker or a browser.
# A failed container must propagate, not become a successful admission.
for status in (0, 13):
with self.subTest(status=status):
result = subprocess.run(
["bash", "-c", """
docker() { printf '%s\n' "$@"; return """ + str(status) + """; }
REPOSITORY_DIR='/tmp/worker with spaces/repo'
PLAYWRIGHT_IMAGE='mcr.microsoft.com/playwright:v1.61.1-noble'
PULSE_E2E_BASE_URL='http://localhost:27655'
""" + function + """
run_playwright 'tests/a test.spec.ts' --project=chromium
"""],
text=True, capture_output=True, check=False,
)
self.assertEqual(result.returncode, status, result.stderr)
args = result.stdout.splitlines()
self.assertEqual(args[-5:], [
"node", "/work/node_modules/@playwright/test/cli.js",
"test", "tests/a test.spec.ts", "--project=chromium",
])
self.assertNotIn("npx", args)
self.assertEqual(args[args.index("--volume") + 1],
"/tmp/worker with spaces/repo/tests/integration:/work")
self.assertEqual(args[args.index("--user") + 1],
f"{os.getuid()}:{os.getgid()}")
self.assertIn("mcr.microsoft.com/playwright:v1.61.1-noble", args)
def test_worker_serializes_resource_intensive_test_suites(self) -> None:
worker = (ROOT / "scripts/release-preflight-worker.sh").read_text()
scheduling_block = re.search(