Skip to content

verify-action-build: credit in-tree binaries the rebuild reproduces - #1206

Open
potiuk wants to merge 1 commit into
apache:mainfrom
potiuk:verify-intree-rebuild-credit
Open

verify-action-build: credit in-tree binaries the rebuild reproduces#1206
potiuk wants to merge 1 commit into
apache:mainfrom
potiuk:verify-intree-rebuild-credit

Conversation

@potiuk

@potiuk potiuk commented Aug 27, 2026

Copy link
Copy Markdown
Member

Code change

Summary

The in-tree binary check could only verify a binary against GitHub release provenance - a SLSA attestation or a SHA256SUMS asset. A binary a bundler copied into dist/ out of a dependency has neither and never will, so the check rejected build output.

Surfaced by #1195 (1Password/load-secrets-action v5.0.1). Its dist/core_bg.wasm is ncc output copied from @1password/sdk-core@0.5.0, which package-lock.json pins with a sha512 integrity hash - the provenance chain exists, it is just npm's rather than the action's. (Upstream 1Password/load-secrets-action#186 asks them to publish attestations; this makes us able to verify it either way.)

  • Delete bundler-copied binaries (.wasm, .node, .so, .dll, .dylib, .exe) from the output directory before the rebuild, exactly as the minified JS already is (build_action.Dockerfile).
  • Credit any that come back byte-identical: the rebuild regenerated them from the lockfile-pinned dependency tree, the same guarantee the JS rebuild check gives (security.py, verification.py).
  • A fully-reproduced action now skips the tag and SHA256SUMS lookups entirely.
  • README updated.

Binaries the rebuild does not reproduce - a committed launcher like runs-on/action's main-linux-amd64 - are unaffected and still require attestation or SHA256SUMS.

This does not by itself turn #1195 green. That PR also fails Binary download verification on three tc.downloadTool calls that fetch the op CLI with no checksum (upstream 1Password/load-secrets-action#168) - untouched by the v5.0.1 bump, and the same shape is present in the already-approved v5.0.0. That finding needs its own decision.

Type of change

  • Bug fix
  • Enhancement to existing code
  • Documentation update

Testing

  • uv run pytest utils/tests/ - 332 passed.

  • New tests for the reproduction match: identical credited, differing not credited, missing-from-rebuild not credited, nested paths, non-binaries ignored, missing dirs.

  • New analyze_in_tree_binaries tests: a reproduced binary passes without any release lookup being attempted, an unreproduced one still fails, and the credit does not leak to a sibling launcher binary.

  • Verified end to end against the real action. The verify workflow does not run on this PR - it touches neither actions.yml nor the dependabot composite, so its checks are pre-commit, test, rat, zizmor, CodeQL and the Analyze jobs. (An earlier version of this body wrongly said verify covers it.) Ran manually on this branch with Docker:

    cd utils
    GITHUB_TOKEN=$(gh auth token) uv run python -m verify_action_build \
      1Password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 --ci
    
    ───────── In-tree Binary Check ─────────
      ✓ 1 binary(ies) reproduced byte-for-byte by the clean rebuild
        (bundler-copied dependency assets):
        ✓ dist/core_bg.wasm
    

    The summary row goes from In-tree binary check ✗ unverified binaries in repo on main to ✓ ... verified via rebuild / attestation / SHA256SUMS. The ncc rebuild does re-emit the wasm byte-identically, which was the open risk in the deletion step.


Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting

The in-tree binary check only knew how to verify a binary against GitHub
release provenance - a SLSA attestation or a SHA256SUMS asset. A bundler-
copied dependency asset has neither and never will: 1Password/load-secrets-
action's dist/core_bg.wasm is ncc output copied from @1password/sdk-core,
pinned by sha512 integrity in package-lock.json, so PR apache#1195 hard-failed on
a binary whose provenance chain is npm's rather than the action's.

Delete those binaries from the output directory before the rebuild, as the
minified JS already is, and credit any that come back byte-identical. That
is the same guarantee the JS rebuild check gives. A fully-reproduced action
now skips the release lookups entirely; everything else is unchanged.

Generated-by: Claude Code (Opus 5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant