Repository navigation
fix(actions-lock): support the v0.0.3 per-dependency hostname field - #938
Conversation
#934 added v0.0.3 to the version allow-list, but the line parser still rejected the one field v0.0.3 introduces (github/actions-lockfile schema/lockfile-v0.0.3.json): an optional, single-quoted `hostname:` on each dependency. Any producer-written hostname therefore failed closed as :malformed_dependency_entry. Parse it the way the format specifies for github.com: - omitted -> the home host; every dependency now records `hostname`, defaulting to "github.com" (v0.0.2 included, as the reference parser does in memory); - 'github.com' -> accepted; - a well-formed '*.ghe.com' tenant -> {:unsupported_dependency_hostname, h}. owner_id/repo_id are host-scoped and the owner/repo@ref association keys carry no host, so a tenant pin cannot be validated here; - non-canonical, unquoted, empty, or duplicate -> malformed / duplicate; - `hostname` in a v0.0.2 lock -> {:hostname_not_in_version, "v0.0.2"}. Versions after v0.0.3 still fail closed with :unsupported_version. Adds a verbatim fixture of hyperpolymath/standards' .github/workflows/actions.lock at b3ce78e (sha256 d61f6436...), covered by a new .reuse/dep5 entry, plus caller-level tests for workflow_audit and workflow_hardening. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KUZiEB43T3E9fJAXqwbSDm
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📜 Recent review details
📝 Summary
Merge Risk: ⚪ Minimal · up to
|
|
Generated by Claude Code |
|
steps:
- name: Checkout
uses: actions/checkout@<same ref as the other jobs in this file>
with:
sparse-checkout: .github/workflows/security-policy.yml
sparse-checkout-cone-mode: false
- name: "Self-check — no orphan jobs (every job is in this needs list)"Use exactly the ref the sibling jobs already use, so the workflow's Generated by Claude Code |
|
Add Carrot credits or activate Agent usage billing to use Autofix |
|
The task could not be completed. Open the task for details or retry. |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
The CI failures may require manual intervention. View agent analysis |
…lf-check (#939) ## Problem `Security Status` (`security-status` in `.github/workflows/security-policy.yml`) fails on `main` and on every PR: for example main runs 39357599189, 39339043314, 39323370164 and 39276944530, and job 118603122869 on #938. Its first step, "Self-check — no orphan jobs", runs `awk`/`sed` over `.github/workflows/security-policy.yml`, but the job has no checkout step. So the step exits 2 with `awk: fatal: cannot open file '.github/workflows/security-policy.yml'`, and the job fails whatever the scans found. ## Change - Adds a sparse checkout of just that file as the job's first step (`sparse-checkout: .github/workflows/security-policy.yml`, `sparse-checkout-cone-mode: false`, `persist-credentials: false`). - Uses `actions/checkout@v7.0.1`, the same ref every sibling job in this file uses. That ref is already in this workflow's `actions.lock` entry, so the lockfile is unchanged and did not need regenerating. - Leaves `needs:` and `if: always()` alone. ## Validation (local) - Ran the self-check script on the edited file. It prints `jobs in workflow: 9` and then `ok: every non-aggregator job is named in the aggregator's needs`. - Ran `actionlint` 1.7.7 on the file before and after the change: no findings either time. Done when, on this PR: Security Status is green, its self-check log shows the `ok:` line, and `governance / Actions lockfile verify` stays green. --- _Generated by [Claude Code](https://claude.ai/code/session_01SYkPCGtUuCvgyns6KgzyMX)_ Co-authored-by: Claude <noreply@anthropic.com>
… support) (#1315) ## Problem `governance / Validate Hypatia Baseline` is red on `main` (`b3ce78e`, run 39340237981) and on every open PR, including #1309, #1310 and #1311. The only blocking findings are: ``` invalid_actions_lock (workflow_audit, high): {:line, 4, {:unsupported_version, "v0.0.3"}} invalid_actions_lock (workflow_hardening, high): actions.lock failed closed: {:line, 4, {:unsupported_version, "v0.0.3"}} ``` The baseline job does not build Hypatia HEAD. Both `governance-reusable.yml` and `hypatia-scan-reusable.yml` default `hypatia-ref` to the vetted SHA `51ab6496…` (2026-10-01), and that commit's lockfile parser accepts only `v0.0.2`. `gh actions-lock` now writes `v0.0.3`. The lockfile is tool-owned, and this finding is deliberately not baselinable (#1239, #1305), so the scanner pin is what has to move. ## Change Both `hypatia-ref` defaults move from `51ab6496bf47e30a0576d503df31fec30f3cfe56` to `aa34a4cc6ba39d873710ff39763fdb9cde715f9d`. They move together, as their descriptions require. `aa34a4cc` is hypatia `main` after hyperpolymath/hypatia#938, which adds proper `v0.0.3` support, including the one field `v0.0.3` introduces (the optional per-dependency `hostname`). Unknown versions still fail closed. No `uses:` ref changes, so `actions.lock` is untouched. ## Blast radius (measured, not assumed) The bump carries every Hypatia commit since `51ab6496` (23 of them, including the `research_extensions` rules and hyperpolymath/hypatia#922's finding-shape change), and a pin move broke every caller once before (hyperpolymath/hypatia#895). So I replayed the `validate-hypatia-baseline` step locally at both pins on three repos: scan, path relativisation, then `apply-baseline.sh` with `BLOCKING_THRESHOLD=info`. | Repo | Kept at `51ab6496` | Kept at `aa34a4cc` | Change | |---|---|---|---| | standards (`d55304a`) | 2 × `invalid_actions_lock` | **0** | gate passes | | echidna | 2 × `invalid_actions_lock`, 1 `DependencyPinning` | same 3 | none* | | hypatia | 2 × `invalid_actions_lock` + 28 pre-existing (RE001/4/5, WH013) | the 28 | −2 | (The table leaves out `GS002`/`GS005`, which come from my detached local checkouts.) - On all three repos the raw findings only *lose* `invalid_actions_lock` and the derived `DependencyPinning`. There is no new finding type and no severity change. - All emitted severities stay inside `hypatia-scan-reusable.yml`'s accepted set. The new `support`/`evidence`/`level` finding fields are additive, and the only `.level` the reusable reads is the SARIF one. - \*echidna's lockfile now parses, but it has two real dangling edges (`slsa-framework/slsa-github-generator@f7dd8c54…` and `hyperpolymath/panic-attack@b689a74d…` are listed under `workflows:` with no top-level record, the startup-failure case `scripts/close-lock.sh` documents). That is an echidna repair, not something this PR changes. ## Checks run locally - `scripts/tests/governance-reusable-contract-test.sh`: PASS - `scripts/tests/hypatia-blocking-gate-test.sh`: PASS - `scripts/tests/apply-baseline-test.sh`: 52 passed, 0 failed - `scripts/tests/check-workflow-duplicate-keys-test.sh`: 17 passed, 0 failed with mikefarah yq v4.47.2 (checksum-verified). It fails 13/4 on `main` too when only the Python `yq` is on PATH. `scripts/check-workflow-duplicate-keys.sh` on both files: clean. - `actionlint` 1.7.7 on both files: output identical to `main`. - `yq '.on.workflow_call.inputs."hypatia-ref".default'` → `aa34a4cc…` in both files. ## After merge Open PRs (#1309, #1310, #1311) need `main` merged into them. Re-running their failed jobs won't help, because a re-run reuses the PR's old merge commit, which still carries `51ab6496`. --- _Generated by [Claude Code](https://claude.ai/code/session_01KUZiEB43T3E9fJAXqwbSDm)_ Co-authored-by: Claude <noreply@anthropic.com>
…940) ## Summary PR 1 of a stack that triages the 30 findings `governance / Validate Hypatia Baseline` reports on every PR (e.g. #938 job 118601725176, #939 job 118615176756). The gate doesn't run this repo's scanner. It builds hypatia at the reusable's default `hypatia-ref`, **`51ab649`**. That commit's `ActionsLock` parser accepts only v0.0.2, so this repo's tool-owned v0.0.3 `actions.lock` fails closed as 2 high findings: ``` invalid_actions_lock (workflow_audit) {:line, 4, {:unsupported_version, "v0.0.3"}} invalid_actions_lock (workflow_hardening) actions.lock failed closed: {:line, 4, ...} ``` The parser was already fixed by #938 (`aa34a4c`). This PR passes `hypatia-ref: aa34a4c…` to both standards reusables (`governance.yml`, `hypatia-scan.yml`). - `uses:` refs are unchanged, so `actions.lock` is untouched. - The value matches hyperpolymath/standards#1315, which moves the estate default to the same SHA. - Once the standards callers are re-pinned past #1315 (a `gh actions-lock` run), this input is redundant and should be dropped. ## Type of change - [x] 🔧 Build / CI / tooling ## How has this been verified? - Both reusables at the pinned `333b06a0` declare a `hypatia-ref` string input (`git show 333b06a0:.github/workflows/{governance,hypatia-scan}-reusable.yml`). - `yq` reads `hypatia-ref: aa34a4c…` from both callers. `actionlint` 1.7.7 is clean on both files, before and after. - The blast radius at `aa34a4c` was measured in standards#1315 by replaying the baseline step: on this repo it removes the 2 `invalid_actions_lock` findings and adds nothing. **The gate stays red on this PR** because of the 28 other findings. The stacked PRs fix those at their source: - WH013 rule precision for PAT-authenticated writes, plus the `inbox-steward-intake.yml` repair (masked pushes, and appended text that corrupts `.hypatia-baseline.json`); - RE005 rule precision for `trap` cleanup, plus two real masks removed; - RE004 digest pins; - RE001 harden-runner in block mode, which needs an owner `gh actions-lock` run. ## Checklist - [ ] My commits are **signed**. The session's signing shim is platform-mediated; GitHub signs the squash merge. - [x] I ran the project's own checks/tests locally and they pass (actionlint; no Elixir change). - [x] New files carry the correct SPDX (no new files). - [x] Docs are updated, and no public claim now overstates what the code does. - [x] I have not introduced a soundness hole. ## Notes for reviewers The pin now lives in two places (here and the standards default) until the re-pin. The comment in `governance.yml` says when to drop it. --- _Generated by [Claude Code](https://claude.ai/code/session_01CYR5bf5FBLS7cXQK72aVNM)_ Co-authored-by: Claude <noreply@anthropic.com>
Brings in #938 (ActionsLock v0.0.3 per-dependency hostname), #939 (security-status checks out the workflow file before its self-check) and #940 (hypatia-ref aa34a4c passed to the standards scanner reusables). Conflicts: - lib/rules/actions_lock.ex: this branch and #938 each added v0.0.3 hostname handling; the textual merge kept both, leaving this branch's clauses unreachable behind #938's. #938's parser is taken whole (it checks the hostname grammar, the version and duplicates), and this branch's one other addition, workflow_refs/2 (PI004 per workflow), is re-applied on top. - test/rules/actions_lock_test.exs: a hostname line in a v0.0.2 lock is {:hostname_not_in_version, "v0.0.2"} under #938, not :malformed_dependency_entry. - .github/workflows/hypatia-scan.yml: #940's `with: hypatia-ref` input and this branch's secrets comment, both kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xn9nqHVbUTRLgBdedoXAc8
…stale reusable pins upstream (#446) ## Summary `.github/workflows/actions.lock` (v0.0.3) was not transitively closed. It listed two job-level reusable refs under `workflows:`, and neither had a top-level record: - `slsa-framework/slsa-github-generator@f7dd8c54…` (`generator-generic-ossf-slsa3-publish.yml`) - `hyperpolymath/panic-attack@b689a74…` (`security-scan.yml`) Since hyperpolymath/hypatia#938 (scanner `aa34a4cc`), Hypatia reports this as `invalid_actions_lock` / `{:workflow_dependencies_missing, …}` in both `workflow_audit` and `workflow_hardening`. That keeps `governance / Validate Hypatia Baseline` red once the hypatia-ref bump from hyperpolymath/standards#1315 lands. **Why the lock couldn't simply be regenerated.** I ran the estate repair chain (`gh actions-lock` → `relock-sha-keys` → `complete-job-refs` → `close-lock` → `prune-stale`, standards `3c00687a`) on main's pins. close-lock stops with exit 3 on two leaf refs: - `dtolnay/rust-toolchain@e2a55d2…`: pinned by standards@75bd5994 `mirror-reusable.yml` - `dtolnay/rust-toolchain@02cb101e…`: pinned by panic-attack@b689a74 `scan-and-report.yml` dtolnay moved its `v1` tag, so no tag names either commit any more. close-lock correctly refuses to write a self-SHA leaf (cf. standards cf8f9121). Upstream main of both repos now pins `683b588`, the current `v1`. The fix is therefore to move the stale caller pins, then run the chain again. ## Changes - `security-scan.yml`: panic-attack `scan-and-report.yml` `b689a74` → `8955f615`. Only one line changes in the called file: the dtolnay pin. - `governance`, `hypatia-scan`, `mirror`, `scorecard`, `secret-scanner`, `spark-theatre-gate`: standards reusables `75bd5994` → `3c00687a` (standards#1315). This also brings in `hypatia-ref` `aa34a4cc`. The `workflow_call` inputs and secrets are unchanged; `hypatia-scan-reusable` gains a `verdict` output. - `actions.lock`: the chain's output for this exact tree, regenerated in CI (sha256 `58d32e2d…`). It was not edited by hand. - Deleted `zz-one-off-lock-regen.yml`, a scratch workflow left behind by #441. It was reused on this branch to run the chain (this session has no GitHub API access), then removed. ## RSR Quality Checklist ### Required - [x] Tests pass: no code changes; lock checks below - [x] Code is formatted: workflow lines changed only in their pin and comment - [x] Linter is clean: `actionlint` clean on all workflows - [x] No banned language patterns - [x] No `unsafe` blocks without `// SAFETY:` comments: n/a - [x] No banned functions: n/a - [x] SPDX license headers present on all new/modified source files - [x] No secrets, credentials, or `.env` files included ### As Applicable - [ ] Docs/deeds/roadmap: n/a (CI pins only) ## Testing Measured in [run 39423933176](https://github.com/hyperpolymath/echidna/actions/runs/39423933176), on three variants of the caller pins: | Variant | close-lock | check-lock-sync, gate @75bd59 and @3c00687a | Hypatia@aa34a4cc `invalid_actions_lock` | |---|---|---|---| | v0: pins as on main | 2 unresolvable | pass | 2 → 2 | | v1: panic-attack bump only | 1 unresolvable (`e2a55d2`) | pass | 2 → 2 | | **v2: this PR** | **0 dangling** (re-run idempotent) | **pass** | **2 → 0** | - Locally, on the final tree: `check-lock-sync.sh` passes, and an independent count of edges with no matching key gives 0. - Known gap: raw `gh actions-lock --verify` (v0.2.0) fails on every variant, main's current lock included. It cannot see job-level reusable `uses:`, so it calls exactly the records close-lock requires "unused". The estate verifier `update-actions-lock.sh --verify-local` (what the governance gate runs) accepts that coverage and passes. With the maintainer's agreement, that wrapper counts as the verify criterion here. - Risk to watch on this PR's CI: callers now run 17 newer standards commits, so Governance or Hypatia may surface new baseline findings unrelated to the lock. --- _Generated by [Claude Code](https://claude.ai/code/session_015jzCHZx4Rt65NDaGLDrjLp)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
## Summary This is the last step of the baseline-gate stack. `governance.yml` and `hypatia-scan.yml` pass `hypatia-ref: aa34a4c` (#940), which predates the rule fixes that clear this repo's own false positives. This PR moves both to **hypatia `main` at `23dc74d`**, which contains: - #938: ActionsLock accepts v0.0.3 locks (already in `aa34a4c`); - #942: WH013 judges writes per job and skips PAT/app-token writes. This clears `estate-rescan.yml`; `inbox-steward-intake.yml` was also repaired in #943; - #947: RE005 skips `trap` handlers, and job extraction survives comments between jobs. `uses:` refs are unchanged, so `actions.lock` is untouched. ## What this PR's governance run will show This PR's own `governance / Validate Hypatia Baseline` run is the measurement: it builds the scanner at `23dc74d`. The jump from `aa34a4c` also brings #931's new rules (WF026, WF027, PIN-003), which haven't been measured on this repo yet. hex.pm is blocked in my session, so I can't build the escript to pre-run them. **Expected remaining findings, by class:** - **RE001 (harden-runner):** most of the original 18 jobs, including the 2 dispatched label workflows, which must stay action-free. - These need an owner decision; the harden-runner steps were removed again in #948 because the lock has no record. - **WH013, RE004, RE005, `invalid_actions_lock`:** expected 0. I'll post the measured list here once the run completes. ## Type of change - [x] 🔧 Build / CI / tooling ## How has this been verified? - `actionlint` 1.7.7 is clean on both files. - `23dc74d` is `origin/main` at the time of writing. `git log aa34a4c..23dc74d` contains #942, #947, #945, #931, #941 and #936. ## Checklist - [ ] My commits are **signed**. The session's signing shim is platform-mediated. - [x] I ran the project's own checks/tests locally and they pass. - [x] New files carry the correct SPDX (none added). - [x] Docs are updated (the pin comment names what it carries). - [x] I have not introduced a soundness hole. --- _Generated by [Claude Code](https://claude.ai/code/session_01CYR5bf5FBLS7cXQK72aVNM)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Problem
#934 added
v0.0.3toActionsLock's version allow-list, but changed nothing else. v0.0.3 adds one field: an optional, single-quotedhostname:on each dependency (source: github/actions-lockfileschema/lockfile-v0.0.3.jsonand its README). The line parser rejects that line as:malformed_dependency_entry. Any v0.0.3 lock that carries ahostnametherefore fails closed asinvalid_actions_lock, in bothworkflow_auditandworkflow_hardening.The only change from v0.0.2 to v0.0.3 is
hostname(confirmed by diffing the two schemas). Its rules for github.com:github.comon github.com);github.com→ allowed;github.comor a lowercase<tenant>.ghe.com.Change
lib/rules/actions_lock.ex, the single parser both rule modules call:hostnamelinehostname: "github.com"(v0.0.2 too, as the reference parser does in memory)hostname: 'github.com'hostname: 'octocorp.ghe.com'{:unsupported_dependency_hostname, h}. Fails closed becauseowner_id/repo_idare host-scoped and theowner/repo@refassociation keys carry no hostGitHub.com,https://…,:443,'',a.b.ghe.com, …), unquoted or double-quoted:malformed_dependency_hostnamehostname{:duplicate_dependency_field, _, :hostname}hostnamein av0.0.2lock{:hostname_not_in_version, "v0.0.2"}version: 'v0.0.4'/v0.1.0/v1.0.0{:unsupported_version, v}Tests:
test/fixtures/actions_lock/standards-b3ce78e-v0.0.3.lock: a byte-for-byte copy of hyperpolymath/standards'.github/workflows/actions.lockatb3ce78e(sha256d61f6436…). It is licensed through a new.reuse/dep5entry that also says not to hand-edit it.workflow_audit_test.exsandworkflow_hardening_test.exs.Verification
Run locally with Elixir 1.17.3 / OTP 25. hex.pm is blocked in the session, so deps were built from their GitHub tags at the
mix.lockversions.mix test: 1837 tests, 0 failures, 242 excluded (:verisim_data, as usual). Baseline onmainwas 1826 / 0.main's parser, 10 of the 11 new tests fail. The one that passes is the regression guard for later versions.mix format --check-formatted: clean for all touched files.b3ce78ewithHYPATIA_FORMAT=json ./hypatia-cli.sh scan, then replayed thevalidate-hypatia-baselinestep locally (path relativisation plus standards' ownapply-baseline.sh,BLOCKING_THRESHOLD=info):51ab649: gate fails, and the only kept findings are the twoinvalid_actions_lock … {:unsupported_version, "v0.0.3"}. This reproduces run 39340237981.invalid_actions_lockfindings are gone, and nothing else changed.Note for the standards side
standards' governance gate does not build Hypatia HEAD.
governance-reusable.ymldefaultshypatia-refto the vetted SHA51ab6496…(2026-10-01), which predates #934. So this PR alone does not turn standards green. Thehypatia-refdefault (andhypatia-scan-reusable.yml's, which it is kept in step with) has to move to a commit that includes v0.0.3 support. That should be this PR's merge commit, ormainif this PR is not taken.Generated by Claude Code