From 7be5122e0b53fce638bc9c080e08d4317e3da73c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 12 Sep 2026 14:44:03 +0000 Subject: [PATCH] Harden CI: the live-E2E jobs install from a hash-pinned set ci.yml's `e2e-critical` and `live-openclaw-e2e` each installed their Python deps from a loose `pip install a b c` line, so every run resolved whatever the index served that minute with no integrity check on any artifact. Both now install with `pip install --require-hashes` from a file under .github/requirements/, which refuses anything not listed with a matching hash. Neither needed a new requirements file. Both jobs' dependency sets are already covered by sets this repository generated and proves in CI: e2e-critical -> playwright-e2e.txt (e2e-nightly, quarantine-sweep) live-openclaw-e2e -> ci-tests.txt (seven sibling jobs in this file) Both files are Python 3.11 sets and both of these jobs pin 3.11 with setup-python, so this reuses a pin that is already exercised rather than introducing hashes that have never been resolved on a runner. That version match is the reason `api-tests` and `lint` are NOT in this batch even though they hold the remaining loose installs in this file. `api-tests` runs a 3.9 leg and `lint` is 3.9 only, while ci-tests.txt pins cffi==2.1.1 and cryptography==50.0.1 -- both 3.10+ only. Pointing them here would take those legs red. They need a 3.9-compatible set, which is its own change. The install-from-source and install-from-wheel smoke jobs (`pip-install`, `wheel-install`, `eval-suite`) are deliberately left loose: resolving clawmetry's own dependencies from the index is the thing they exist to test. Verified on Linux / CPython 3.11.15, matching what both jobs pin with setup-python on ubuntu-latest: `pip install --require-hashes -r` each file into a clean venv succeeds, and every module the two `run:` lines previously named imports from the resulting environment. All 40 workflow files still parse. tests/test_workflow_yaml_valid.py + tests/test_ci_workflow_invocations_are_real.py: 594 passed / 369 skipped, unchanged from before this edit -- in particular the conftest-import guard still ASSERTS for both jobs rather than skipping, which is what moving package names into a `-r` file would otherwise have retired. No permissions blocks were touched. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ndb2qBqQjscpQY4KjXJxXA --- .github/workflows/ci.yml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4caa010977..a709adb8a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1212,7 +1212,15 @@ jobs: # duckdb is in requirements.txt and used by the dashboard's local # event store; without it the server crashes on import and the # health check silently times out. - run: pip install flask pytest pytest-playwright requests duckdb + # + # playwright-e2e.txt is the hash-pinned set the other Playwright jobs + # (e2e-nightly, quarantine-sweep) already install from, and it carries + # every package this line resolved loosely -- Flask, pytest, + # pytest-playwright, requests, duckdb -- at the same Python 3.11 this + # job pins. + run: >- + pip install --require-hashes + -r .github/requirements/playwright-e2e.txt - name: Cache Playwright browsers uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: @@ -1554,7 +1562,13 @@ jobs: with: gateway-token: moat-live-e2e-token - name: Install Python deps - run: pip install flask pytest waitress duckdb cryptography requests + # ci-tests.txt is the hash-pinned set seven sibling jobs in this file + # already install from, and it carries every package this line resolved + # loosely -- Flask, pytest, waitress, duckdb, cryptography, requests -- + # at the same Python 3.11 this job pins. + run: >- + pip install --require-hashes + -r .github/requirements/ci-tests.txt - name: Run live OpenClaw E2E env: # User-provided key (private repo secret) so OpenClaw can make a