feat(supply-chain): attest Python lock provenance before install - #1369
feat(supply-chain): attest Python lock provenance before install#1369seonghobae wants to merge 26 commits into
Conversation
|
Caution Review failedAn error occurred during the review process. Please try again later. 📝 WalkthroughWalkthroughAdded an offline Python lock provenance validator. It checks exact pins, SHA-256 hashes, generator metadata, and lock paths. It produces deterministic JSON receipts, exposes CLI results, adds contract tests, documents the contract, and publishes receipts in CI. ChangesPython lock provenance
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: 🟠 High · up to This PR gates dependency installation on a Python lock-provenance receipt, but the current behavior can omit included requirements from validation, reject valid lock-generation commands, read outside-repository paths, and fail to guarantee validation and receipt handling around installation. That could produce incomplete provenance evidence or expose file content in CI, so the PR should not merge until these issues are fixed. Sequence Diagram(s)sequenceDiagram
participant ApplicationCI
participant python_lock_provenance.py
participant GITHUB_STEP_SUMMARY
ApplicationCI->>python_lock_provenance.py: run --json
python_lock_provenance.py-->>ApplicationCI: validation receipt and exit status
ApplicationCI->>GITHUB_STEP_SUMMARY: append formatted JSON receipt
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
PR governance metadata gate is not ready for
|
Dismissed as predecessor-head changes-request evidence: this review was anchored to df3efe5, while the current head is 1b99119. All five published findings are resolved on the current head, including failure-receipt publication, job-scoped CI ordering tests, repository-root path containment, requirements.in parsing, and extras-aware manual pins. This dismissal is not approval; current-head independent approval and all live required gates remain mandatory, and Build/Publish is still in progress.
|
@coderabbitai review Please review the unchanged current head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
requested_head='1b991190d69e6a8dc028d51b64d92fca319c5f04'
git fetch origin develop --quiet
printf '%s\n' '== Revision verification =='
git rev-parse HEAD
git rev-parse "$requested_head^{commit}"
git merge-base "$requested_head" origin/develop
printf '%s\n' '== Changed files against live develop =='
git diff --name-status "$(git merge-base "$requested_head" origin/develop)" "$requested_head"
printf '%s\n' '== Diff stat =='
git diff --stat "$(git merge-base "$requested_head" origin/develop)" "$requested_head"
printf '%s\n' '== Python validator outline =='
ast-grep outline scripts/ci/python_lock_provenance.py --items all 2>/dev/null || true
printf '%s\n' '== Python test outline =='
ast-grep outline backend/tests/test_python_lock_provenance.py --items all 2>/dev/null || true
printf '%s\n' '== Workflow diff =='
git diff --no-ext-diff --unified=80 "$(git merge-base "$requested_head" origin/develop)" "$requested_head" -- .github/workflows/app-ci.ymlLength of output: 10338 🏁 Script executed: #!/bin/bash
set -euo pipefail
base='bc98789521d21271e84789888413c182aa111b4d'
head='1b991190d69e6a8dc028d51b64d92fca319c5f04'
printf '%s\n' '== Validator implementation =='
sed -n '1,430p' scripts/ci/python_lock_provenance.py
printf '%s\n' '== Contract tests =='
sed -n '1,440p' backend/tests/test_python_lock_provenance.py
printf '%s\n' '== Active SHA-256 requirements files and headers =='
while IFS= read -r -d '' file; do
if rg -q -- '--hash=sha256:' "$file"; then
printf '\n--- %s ---\n' "$file"
sed -n '1,45p' "$file"
fi
done < <(fd -0 -t f -e txt -e in -e requirements .)
printf '%s\n' '== Validator and documentation diff =='
git diff --no-ext-diff --unified=100 "$base" "$head" -- \
scripts/ci/python_lock_provenance.py \
docs/doctoring/python-lock-provenance-receipt.mdLength of output: 31565 🏁 Script executed: #!/bin/bash
set -euo pipefail
base='bc98789521d21271e84789888413c182aa111b4d'
head='1b991190d69e6a8dc028d51b64d92fca319c5f04'
candidates="$(mktemp)"
trap 'rm -f "$candidates"' EXIT
fd -t f -e txt -e in -e requirements . > "$candidates"
printf '%s\n' '== Requirements candidates that contain hash evidence =='
while IFS= read -r file; do
if rg -q -- '--hash=sha256:' "$file"; then
printf '\n--- %s ---\n' "$file"
sed -n '1,55p' "$file"
fi
done < "$candidates"
printf '%s\n' '== Changed documentation =='
sed -n '1,180p' docs/doctoring/python-lock-provenance-receipt.md
printf '%s\n' '== Failure-contract and syntax references =='
rg -n -C 3 --glob 'scripts/ci/python_lock_provenance.py' \
--glob 'backend/tests/test_python_lock_provenance.py' \
--glob 'docs/doctoring/python-lock-provenance-receipt.md' \
'disappear|unread|read_text|PermissionError|FileNotFoundError|same line|inline|continuation|fail-closed|receipt' \
scripts backend/tests docs/doctoring
printf '%s\n' '== Full changed workflow section =='
git diff --no-ext-diff --unified=30 "$base" "$head" -- .github/workflows/app-ci.ymlLength of output: 56905 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Numbered parser and discovery regions =='
nl -ba scripts/ci/python_lock_provenance.py | sed -n '105,175p;325,375p'
printf '%s\n' '== Include syntax in changed contract and documentation =='
rg -n -C 3 --glob 'backend/tests/test_python_lock_provenance.py' \
--glob 'docs/doctoring/python-lock-provenance-receipt.md' \
-- '(?:^|[^A-Za-z])(?:-r|--requirement|--constraint|-c)(?:\s|=)' \
backend/tests/test_python_lock_provenance.py \
docs/doctoring/python-lock-provenance-receipt.md || true
printf '%s\n' '== Existing include declarations in active requirements files =='
rg -n -C 2 --glob 'requirements*.txt' \
-- '^\s*(?:-r|--requirement|--constraint|-c)(?:\s|=)' . || trueLength of output: 1123 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Parser ignore branch =='
rg -n -C 10 --fixed-strings 'if stripped.startswith("-"):' \
scripts/ci/python_lock_provenance.py
printf '%s\n' '== Discovery filename restriction =='
rg -n -C 8 --fixed-strings 'repository_root.rglob("requirements*.txt")' \
scripts/ci/python_lock_provenance.py
printf '%s\n' '== Include syntax in changed contract tests and documentation =='
rg -n -C 3 \
--glob 'backend/tests/test_python_lock_provenance.py' \
--glob 'docs/doctoring/python-lock-provenance-receipt.md' \
-- '(^|[^A-Za-z])(-r|--requirement|--constraint|-c)([[:space:]]|=)' \
backend/tests/test_python_lock_provenance.py \
docs/doctoring/python-lock-provenance-receipt.md || true
printf '%s\n' '== Existing include declarations in current requirements files =='
rg -n -C 2 --glob 'requirements*.txt' \
-- '^[[:space:]]*(-r|--requirement|--constraint|-c)([[:space:]]|=)' . || trueLength of output: 2795
I found one issue.
✅ Action performedReview finished.
|
|
@coderabbitai review Please review the unchanged exact head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
head='bb8e34988af133bf28b0c1b657be7f757b66b2c8'
git fetch origin develop --quiet
base="$(git merge-base "$head" origin/develop)"
printf '%s\n' '== Revision verification =='
printf 'checked-out HEAD: '; git rev-parse HEAD
printf 'requested head: '; git rev-parse "$head^{commit}"
printf 'live merge base: '; printf '%s\n' "$base"
printf '%s\n' '== Changed files against live develop =='
git diff --name-status "$base" "$head"
printf '%s\n' '== Validator outline =='
ast-grep outline scripts/ci/python_lock_provenance.py --items all 2>/dev/null || true
printf '%s\n' '== Changed validator, tests, workflow, and documentation =='
git diff --no-ext-diff --unified=90 "$base" "$head" -- \
scripts/ci/python_lock_provenance.py \
backend/tests/test_python_lock_provenance.py \
.github/workflows/app-ci.yml \
docs/doctoring/python-lock-provenance-receipt.md
printf '%s\n' '== Include parsing and lock discovery references =='
rg -n -C 12 --glob 'scripts/ci/python_lock_provenance.py' \
--glob 'backend/tests/test_python_lock_provenance.py' \
-- '(?:requirement|constraint|include|rglob\(|startswith\("-"\)|--hash=sha256:|-r\b|-c\b)' \
scripts/ci/python_lock_provenance.py backend/tests/test_python_lock_provenance.py || true
printf '%s\n' '== Numbered relevant validator regions =='
nl -ba scripts/ci/python_lock_provenance.py | sed -n '1,460p'Length of output: 114936 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '== Include test outline =='
ast-grep outline backend/tests/test_python_lock_provenance_includes.py --items all 2>/dev/null || true
printf '%s\n' '== Include regression tests =='
sed -n '1,520p' backend/tests/test_python_lock_provenance_includes.py
printf '%s\n' '== Active requirements files and include directives =='
while IFS= read -r -d '' path; do
if rg -q -- '--hash=sha256:|^[[:space:]]*(-r|--requirement)([[:space:]=]|$)' "$path"; then
printf '\n--- %s ---\n' "$path"
sed -n '1,100p' "$path"
fi
done < <(fd -0 -t f -e txt -e in -e requirements .)
printf '%s\n' '== CI pip requirements arguments =='
rg -n -C 4 --glob '*.yml' --glob '*.yaml' --glob '*.sh' --glob '*.py' \
'pip install|--require-hashes|(^|[[:space:]])(-r|--requirement)([[:space:]=]|$)' \
.github scripts backend connector 2>/dev/null || true
printf '%s\n' '== Focused include validator region =='
sed -n '25,180p;325,465p' scripts/ci/python_lock_provenance.py
printf '%s\n' '== File inventory and diff statistics =='
git diff --stat bc98789521d21271e84789888413c182aa111b4d HEAD
git status --shortLength of output: 9411 🏁 Script executed: #!/bin/bash
set -euo pipefail
candidates="$(mktemp)"
trap 'rm -f "$candidates"' EXIT
fd -t f -e txt -e in -e requirements . > "$candidates"
printf '%s\n' '== Requirements candidates with hash pins or include directives =='
while IFS= read -r path; do
if rg -q -- '--hash=sha256:|^[[:space:]]*(-r|--requirement)([[:space:]=]|$)' "$path"; then
printf '\n--- %s ---\n' "$path"
sed -n '1,120p' "$path"
fi
done < "$candidates"
printf '%s\n' '== All current requirements include directives =='
rg -n -C 3 --glob '*.txt' --glob '*.in' --glob '*requirements*' \
'^[[:space:]]*(-r([[:space:]]*[^[:space:]]+)|--requirement(=|[[:space:]]+)[^[:space:]]+)' \
. || true
printf '%s\n' '== CI requirements-file consumers =='
rg -n -C 5 --glob '*.yml' --glob '*.yaml' --glob '*.sh' \
'python -m pip install|pip install|--require-hashes|(^|[[:space:]])(-r|--requirement)([[:space:]=]|$)' \
.github scripts || true
printf '%s\n' '== Include parser and include tests with line numbers =='
sed -n '30,175p;330,430p' scripts/ci/python_lock_provenance.py | cat -n
sed -n '45,210p' backend/tests/test_python_lock_provenance_includes.py | cat -n
printf '%s\n' '== Changed-file whitespace errors =='
git diff --check bc98789521d21271e84789888413c182aa111b4d HEAD || true
printf '%s\n' '== Tracked changed files at requested revision =='
git diff --name-only bc98789521d21271e84789888413c182aa111b4d HEADLength of output: 57426
I found no new issues. The prior P1 finding is resolved. The validator now recursively processes Static checks found no active include directives in the current requirements files. I did not execute repository tests in this environment. You are interacting with an AI system. |
Superseded by current head bb8e349. Both include-directive findings were addressed test-first in commits 6fdb12d and 65f5a88, the linked review threads are resolved, and this CHANGES_REQUESTED review is anchored to predecessor head 1b99119. Dismissal removes stale predecessor review state only; current-head required checks and independent approval remain mandatory.
|
@opencode-agent @cwl-noema-review Review only. Re-evaluate unchanged exact head |
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head4313e2509ea085a8274dc8c750eb291752121bb1. -
Head SHA:
4313e2509ea085a8274dc8c750eb291752121bb1 -
Workflow run: 32123693472
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Workflow: app-ci.yml"]
S1 --> I1["GitHub Actions review job"]
I1 --> R1["Review risk: Workflow: app-ci.yml"]
R1 --> V1["actionlint plus required checks"]
Evidence --> S2["Backend (2 files)"]
S2 --> I2["API and service runtime"]
I2 --> R2["Review risk: Backend (2 files)"]
R2 --> V2["backend tests"]
Evidence --> S3["Docs: python-lock-provenance-receipt.md"]
S3 --> I3["operator or user guidance"]
I3 --> R3["Review risk: Docs: python-lock-provenance-receipt.md"]
R3 --> V3["docs review"]
Evidence --> S4["CI script: python_lock_provenance.py"]
S4 --> I4["review and security gate shell path"]
I4 --> R4["Review risk: CI script: python_lock_provenance.py"]
R4 --> V4["bash -n plus Strix self-test"]
OpenCode Review Overview
Pull request overviewOpenCode cannot approve yet because required coverage evidence did not pass. Review outcome1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
Coverage evidenceCoverage evidence job did not run or did not publish coverage evidence. Changed-File Evidence Mapflowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Workflow: app-ci.yml"]
S1 --> I1["GitHub Actions review job"]
I1 --> R1["Review risk: Workflow: app-ci.yml"]
R1 --> V1["actionlint plus required checks"]
Evidence --> S2["Backend (2 files)"]
S2 --> I2["API and service runtime"]
I2 --> R2["Review risk: Backend (2 files)"]
R2 --> V2["backend tests"]
Evidence --> S3["Docs: python-lock-provenance-receipt.md"]
S3 --> I3["operator or user guidance"]
I3 --> R3["Review risk: Docs: python-lock-provenance-receipt.md"]
R3 --> V3["docs review"]
Evidence --> S4["CI script: python_lock_provenance.py"]
S4 --> I4["review and security gate shell path"]
I4 --> R4["Review risk: CI script: python_lock_provenance.py"]
R4 --> V4["bash -n plus Strix self-test"]
|
|
Current-head supply-chain fix pushed at |
|
The actionable authentication finding from the prior Strix run is now fixed in the stacked auth PR #1415 at current head |
23a548b to
f6eeb69
Compare
Stale review: cited a coverage-evidence/required-check failure on an earlier commit; current head has been verified (gh pr checks) to pass coverage-evidence and all other non-metadata-gate required checks, with no current-head review from this reviewer. Dismissing as superseded per AGENTS.md stale-review guidance.
|
Caution Review failedAn error occurred during the review process. Please try again later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Important Approval pendingCodeRabbit has no unresolved comments, but it has not reviewed the latest commit. Use the checkbox below to review the latest commit. CodeRabbit will approve the changes if it finds no blocking issues.
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…egistry-hash verification Reconcile feat/python-lock-registry-provenance with the advanced base branch feat/dependency-lock-provenance-receipt (#1369 side): - scripts/ci/python_lock_provenance.py + tests: take base evolution (inline source-comment pin binding, non-file lock candidate skip) - .github/workflows/app-ci.yml: union keeping both offline provenance and new PyPI release hash provenance steps before dependency install
* test(supply-chain): add RED lock provenance contracts * feat(supply-chain): implement offline Python lock provenance receipt * ci(supply-chain): publish Python lock provenance receipt * test(supply-chain): harden lock provenance branch coverage * fix(supply-chain): fail closed on incomplete lock generators * docs(supply-chain): record Python lock provenance evidence boundary * fix(supply-chain): fail closed when lock hashes disappear * test(supply-chain): cover provenance review regressions * fix(supply-chain): contain lock provenance reads * fix(ci): publish failed lock provenance receipts * docs(supply-chain): document contained provenance reads * test(supply-chain): specify registry hash provenance contract * feat(supply-chain): validate locked hashes against PyPI releases * ci(supply-chain): verify PyPI hashes before install * docs(supply-chain): record PyPI hash provenance boundary * test(supply-chain): cover PyPI provenance failure boundaries * test(supply-chain): reject PyPI metadata origin redirects * fix(supply-chain): keep PyPI metadata reads on trusted origin * test(supply-chain): keep registry edge suite lint-clean * test(supply-chain): reject vacuous PyPI provenance receipts * fix(supply-chain): require non-vacuous registry evidence * test(supply-chain): expose recursive requirements include bypass * fix(supply-chain): validate recursive requirements includes * docs(supply-chain): record recursive include boundary * fix(ci): reject unvalidated PyPI redirects * fix(http): reject explicit zero loopback ports (#1337) * fix(http): reject explicit zero loopback ports * test(security): lock OIDC hostname boundary * test(security): preserve subdomain validation contracts * docs(security): record local HTTP port validation boundary * style: format local HTTP validation tests --------- Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> --------- Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
|
Non-force restack evidence for exact head |
Issue #1229 supply-chain lane
Status: Draft. Protected base is
develop@042b0c70531b229af3acbd0421a2f23098d848b3; exact head is8892d0fdeb90ec0e5e5eee9b8dceb1ae02bbca1a. The current compare is ahead-only: 26 commits ahead, 0 behind, with merge base exactly at protecteddevelop.This PR now explicitly owns the combined Naruon-local Python lock evidence lane that #1370 originally introduced as a child: deterministic offline declaration/provenance plus PyPI release-hash provenance. Merged #1370 commit
cd7241798e347ee4b14a2b9812dd69eb719a1b58is already in this branch ancestry. No mutable external owner branch is consumed.Current contract
Application CI always runs the deterministic offline Python lock validator before dependency installation. It validates exact pins, SHA-256 structure, recursive
-r/--requirementincludes, repository containment, generator/source binding, every declareduv pip compilesource file, UTF-8/read failures, and deterministic non-secret receipts.The live-PyPI release-hash gate remains fail-closed when supply-chain evidence can change, but it is now diff-scoped so unrelated product changes do not become dependent on public PyPI availability. Changes to
requirements*.txt, either provenance validator, focused lock-provenance backend tests/doctoring, or.github/workflows/app-ci.ymlrequire the registry gate. Missing, zero, or unusable event-base evidence defaults torequired=true. Skipping the network gate because the diff is outside that scope is not a passing registry receipt and does not weaken offline hash validation orpip install --require-hashes.Current RED → repair evidence
3a3628d9de42d212c7022d9edac2b75b1e760f3b— RED: public PyPI evidence must not gate unrelated product PRs while offline lock validation remains unconditional.3f76039b8db1f339a5c3f07c5e5a716604a9e07e— causal fix: fail-safe diff classification and conditional PyPI registry gate.58fe47085fd4ecfc042b97eedb65a38364855294— doctoring updated to the scoped network-evidence boundary.f4b2cbbf4e2b134d7355d6b16f944dda9615f6c2— scope regression kept lint-clean.32cdf3bf4923be7090052a7e03fefb44582e66a7— RED: an earlier source in a multi-inputuv pip compilecould escape version agreement, and a non-UTF-8 included requirements file raised instead of producing stable evidence.5d29d5ff91362ef5311ace6301a88920c292bbf6— causal fix: validate every declared non-output.txt/.insource and convert lock/source read failures to bounded stable reason codes.8892d0fdeb90ec0e5e5eee9b8dceb1ae02bbca1a— offline provenance doctoring reconciled with the combined registry lane and current reason-code/source-path contracts.All live inline review threads have been re-read against the current source and resolved. Informational findings that represent deliberate fail-closed conventions were documented rather than converted into unnecessary source churn.
Exact-head evidence and merge boundary
Fresh pull-request workflows for exact head
8892d0fdeb90ec0e5e5eee9b8dceb1ae02bbca1aare currently queued:339401235893394012369033940123657339401236203394012359933940123764There is no qualifying independent post-last-push
APPROVEDreview for this exact head. Predecessor checks and reviews do not transfer.Keep Draft. Do not merge until exact-head repository workflows are terminal GREEN, organization-required contexts are satisfied, and a qualifying independent approval is current. No self-approval, dummy requeue commit, admin bypass, force push, destructive rebase, or gate weakening.