Skip to content

security: bound direct SBOM archive input before parser execution - #68

Draft
seonghobae wants to merge 19 commits into
release/sealed-evidence-preparationfrom
security/bound-sbom-archive-input
Draft

security: bound direct SBOM archive input before parser execution#68
seonghobae wants to merge 19 commits into
release/sealed-evidence-preparationfrom
security/bound-sbom-archive-input

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Test-first direct-generator hardening

Progresses #67 as a bounded stack on PR #64 without modifying .github, credentials, dependencies, release permissions, protected refs, network transports, or files owned by the stacked base.

Exact tree binding

The stacked base has advanced after the auditable merge, so GitHub currently reports this draft PR as conflicting. No rebase, force update, retarget, or conflict strategy has been used. The branch remains draft until an auditable credential-separated stack-integration mechanism can reproduce and independently verify the exact tree.

Implemented boundary

  • rejects missing, symlinked, non-regular, or over-256-MiB direct wheel/source archives before parser or hashing entry;
  • binds one no-follow regular-file descriptor to the accepted path device/inode and rechecks its live size around parser reads and seeks;
  • caps each parser-visible unbounded or excessive read to the strictly positive bytes remaining through the 256 MiB ceiling plus one tripwire byte;
  • validates parser-visible descriptors and positions, normalizes fileno, tell, read, and seek failures to one non-leaking unsafe-artifact boundary, and rejects booleans, non-integer, negative, or out-of-range positions before bound arithmetic or parser consumption;
  • rejects malformed or oversized read results and seek/tell disagreement while preserving the distinct compressed-byte safety-bound failure for actual file growth beyond 256 MiB;
  • parses and hashes only the bound descriptor and brackets metadata parsing with exact SHA-256 equality;
  • preserves archive member-count, traversal, link/device, metadata-byte, dependency-lock, deterministic JSON, and final digest controls;
  • changes no workflow, dependency, credential, permission, signing, attestation, release, publication, tag, ref, or network behavior.

Test-first evidence

Exact RED commit d5e073f799c459fa7a3f195018802d5958b5ef1e added focused regressions proving that:

  • an out-of-range parser position must fail before an underlying read(-1) or other unsafe size can occur;
  • a negative seek result must fail closed; and
  • parser-visible fileno, tell, read, and seek failures must use one stable non-leaking error.

Exact current commit 127e4577ea31ca20e7260a482343c892efeed6f9 changes only scripts/ci/generate_release_sbom.py relative to that RED head and implements the bounded descriptor/position validation and stable failure normalization.

The current conflicted stack cannot produce the repository's normal pull-request merge-ref CI, so no queued, missing, or prior-head run is treated as exact-current-head success. Prior CI run 31103515511 succeeded on 224e6d253a7957e981515ec66260fb1c2cf84a31, but it predates the parser-state RED/GREEN extension and is not acceptance evidence for 127e4577ea31ca20e7260a482343c892efeed6f9.

Remaining gates

Keep this PR draft. Complete the bounded docs/CHANGELOG formatting pass, then require an auditable stack integration, exact-current-head CI, applicable SAST and Security Scan, completed automated review, independent non-author approval, branch protection, and every repository policy gate. Do not merge, enable auto-merge, release, publish, rebase, retarget, force-update, or claim provenance or a SLSA Build level.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c701008e-6f9b-49d2-bcc2-83fc84d4cbcc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Implement the bounded GREEN repair on exact current test-only head 22e87649257386e89933e0ae44067f116d4c2870 of branch security/bound-sbom-archive-input.

The immutable RED history is valid. Exact head 22e87649257386e89933e0ae44067f116d4c2870 passed Ruff and package acceptance, then failed all Python 3.10–3.13 lanes with exactly the five focused regressions (5 failed, 750 passed on Python 3.13): oversized wheel and sdist reached ZIP/tar parser entry points, a symlinked wheel reached the parser, an lstat failure reached the parser, and a directory produced the old non-normalized error.

Modify only these paths:

  • scripts/ci/generate_release_sbom.py
  • tests/test_release_sbom_archive_bound.py
  • docs/sbom-release-evidence.md
  • CHANGELOG.md

Required minimal implementation:

  1. In the standalone generator, define one compressed release-artifact limit of exactly 256 * 1024 * 1024 bytes, aligned with the sealed-evidence verifier without importing the package under test.
  2. Add a beginner-readable private helper that calls Path.lstat() and, before any zipfile.ZipFile, tarfile.open, metadata reader, or artifact hash operation:
    • rejects every symlink, directory, device, FIFO, socket, missing path, and other non-regular input;
    • normalizes inspection failures and unsafe/non-regular inputs to exactly release artifact is missing or unsafe without leaking local filesystem details;
    • rejects st_size above the limit with exactly release artifact exceeds the compressed-byte safety bound.
  3. Call that helper at the first line of build_sbom(...) and replace the current is_file() precondition. Retain all existing member-count, traversal, link/device, metadata-byte, dependency-lock, exact SHA-256, deterministic-output, and archive-format checks as independent defenses.
  4. Keep the generator standalone and the attestable adapter API unchanged. Add no package import, dependency, network, credential, workflow, signing, attestation, tag, ref, release, or publication behavior.
  5. Keep the focused RED tests and add only coverage assertions/tests needed to prove the exact constant and every new branch while preserving 100% statement and branch coverage. Do not weaken parser-entry assertions.
  6. Update docs/sbom-release-evidence.md with direct-generator/operator guidance: finite compressed-input preflight happens before parser execution; accepted-size archives remain subject to member/metadata/decompression controls and residual mutable-storage risk; no provenance or SLSA claim follows.
  7. Add a concise [Unreleased] Security entry to CHANGELOG.md. Do not bump the version.
  8. Add or retain APA 7 primary references for MITRE CWE-400 and Python's official zipfile decompression-pitfalls documentation, using the repository's existing reference style.

Stop without changing anything if the exact head is no longer 22e87649257386e89933e0ae44067f116d4c2870. Do not modify .github, workflows, dependencies, protected refs, credentials, permissions, review-agent identities, release behavior, or any path outside the four-file allowlist. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only exact current head 989959e429f165898818cf8ed4a1027a05024e40 against exact stacked base 421c0975cdabbc24cb4c42a9bb11e202cd33b0a4. Earlier draft-skip output and analysis of the RED heads are superseded and are not review success. Focus on whether every direct wheel/source archive is rejected as missing, unsafe, non-regular, or over the exact 256 MiB compressed-byte bound before ZIP/gzip-tar parsing, metadata reads, and artifact hashing; preservation of existing archive member, metadata, dependency-lock, deterministic JSON, and digest controls; stable non-leaking errors; standalone generator/API compatibility; APA 7 primary references; CHANGELOG accuracy; and absence of workflow, credential, dependency, signing, attestation, publication, tag, ref, release, or network changes. Treat the documented post-preflight mutable-storage interval as residual risk rather than an immutable-file claim. Do not approve, merge, mark ready, rebase, retarget, publish, or infer success from queued checks.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='421c0975cdabbc24cb4c42a9bb11e202cd33b0a4'
head='989959e429f165898818cf8ed4a1027a05024e40'

echo '== commit identities =='
git rev-parse HEAD
git cat-file -t "$base"
git cat-file -t "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=yes' || echo 'base_is_ancestor=no'

echo '== changed paths: exact range =='
git diff --name-status "$base" "$head"

echo '== implementation outline =='
ast-grep outline scripts/ci/generate_release_sbom.py --items all --view expanded

echo '== focused diff =='
git diff --unified=80 "$base" "$head" -- \
  scripts/ci/generate_release_sbom.py \
  tests/test_release_sbom_archive_bound.py \
  docs/sbom-release-evidence.md \
  CHANGELOG.md

echo '== parser/hash/metadata call contexts =='
rg -n -C 5 -P '\b(build_sbom|ZipFile|tarfile\.open|sha256|read_metadata|is_file|lstat)\b' \
  scripts/ci/generate_release_sbom.py

echo '== test outline =='
ast-grep outline tests/test_release_sbom_archive_bound.py --items all --view expanded

Length of output: 50761


@seonghobae Review found one blocking issue.

  • Line 509: arguments.artifact.resolve() follows a supplied artifact symlink before build_sbom() calls _preflight_release_artifact(). A CLI caller can pass a symlink to a valid wheel or source distribution. The helper then receives the resolved regular-file target, so lstat() does not detect the original symlink. ZIP/gzip-tar parsing, metadata reads, and hashing can proceed.

Pass the original arguments.artifact path to build_sbom(). Keep manifest and other path resolution separate as needed. Add a CLI-level regression that passes a symlink and asserts that the parser does not run.

The changed-path boundary is correct. The 256 MiB constant, stable errors, documentation, APA 7 references, and CHANGELOG entry otherwise match the requested scope. I did not approve the pull request.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only exact current head d037f24c7b4603412f448e26ed2e1576ec79d36e against exact stacked base 421c0975cdabbc24cb4c42a9bb11e202cd33b0a4. The request for 989959e429f165898818cf8ed4a1027a05024e40, all RED-head analysis, and draft-skip/rate-limit output are superseded and are not review success. Focus on the no-follow descriptor opening where supported, lstat/fstat regular-file and device/inode identity binding, live 256 MiB read ceiling, SHA-256 bracketing around metadata parsing, exact stable failures for unsafe/replaced/oversized/mutated inputs, parser and digest use of only the bound descriptor, existing archive/member/metadata/dependency/determinism controls, API compatibility, documentation and APA 7 references, CHANGELOG accuracy, and absence of workflow, credential, dependency, network, signing, attestation, release, publication, tag, or ref behavior. Do not approve, merge, mark ready, rebase, retarget, publish, or infer success from queued checks.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='421c0975cdabbc24cb4c42a9bb11e202cd33b0a4'
head='d037f24c7b4603412f448e26ed2e1576ec79d36e'

echo '== commit identity =='
printf 'checkout: '; git rev-parse HEAD
printf 'base type: '; git cat-file -t "$base"
printf 'head type: '; git cat-file -t "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base ancestor: yes' || echo 'base ancestor: no'

echo '== exact changed paths =='
git diff --name-status "$base" "$head"

echo '== production outline =='
ast-grep outline scripts/ci/generate_release_sbom.py --items all --view expanded

echo '== focused test outline =='
ast-grep outline tests/test_release_sbom_archive_bound.py --items all --view expanded

echo '== exact scoped diff =='
git diff --unified=100 "$base" "$head" -- \
  scripts/ci/generate_release_sbom.py \
  tests/test_release_sbom_archive_bound.py \
  docs/sbom-release-evidence.md \
  CHANGELOG.md

echo '== descriptor, parser, metadata, and digest contexts =='
rg -n -C 8 -P '\b(build_sbom|main|lstat|fstat|open|os\.open|O_NOFOLLOW|ZipFile|tarfile\.open|read_metadata|sha256|hashlib|is_file|resolve|st_size|read|seek)\b' \
  scripts/ci/generate_release_sbom.py

echo '== all exact-range diff, for boundary inspection =='
git diff --stat "$base" "$head"
git diff --name-only "$base" "$head"

Length of output: 74741


@seonghobae Review found one blocking issue on exact head d037f24c7b4603412f448e26ed2e1576ec79d36e.

  • Line 545: arguments.artifact.resolve() follows a caller-supplied final symbolic link before build_sbom() calls _open_release_artifact(). The subsequent lstat() and fstat() bind the resolved target, not the supplied artifact path. A CLI caller can therefore provide a symbolic link to a valid wheel or source distribution. The generator can then parse, read metadata from, and hash that target.

Pass arguments.artifact without .resolve() to build_sbom(). Keep resolution for the manifest, lock, and output paths separate where needed. Add a CLI-level regression that supplies an artifact symbolic link and asserts that ZIP or tar parsing does not run.

The changed-path boundary matches the allowlist. The descriptor-based parser and hash flow, 256 MiB limit, stable errors, documentation, APA 7 references, and CHANGELOG entry otherwise match the requested scope. I did not approve the pull request.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only exact current head 01a31595eb96ef0b4df46dcfa1b529af9e7a4039 against exact stacked base 421c0975cdabbc24cb4c42a9bb11e202cd33b0a4. Every earlier head and review request is superseded. The only change after d037f24c7b4603412f448e26ed2e1576ec79d36e preserves the repository's existing _sha256_file contract name for the descriptor-bound finite hashing helper after exact-head CI exposed that compatibility contract. Recheck the complete four-file diff, descriptor/path identity binding, mutation detection, finite resource bounds, stable errors, standalone compatibility, docs/references/changelog, and absence of workflow or credential changes. Do not approve, merge, mark ready, rebase, retarget, publish, or treat rate-limited/queued output as success.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='421c0975cdabbc24cb4c42a9bb11e202cd33b0a4'
head='01a31595eb96ef0b4df46dcfa1b529af9e7a4039'

echo '== Exact commit binding =='
printf 'checked_out='; git rev-parse HEAD
printf 'base_type='; git cat-file -t "$base"
printf 'head_type='; git cat-file -t "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_ancestor=yes' || echo 'base_ancestor=no'

echo '== Changed paths in exact range =='
git diff --name-status "$base" "$head"

echo '== Changed-files outlines =='
ast-grep outline scripts/ci/generate_release_sbom.py --items all --view expanded
ast-grep outline tests/test_release_sbom_archive_bound.py --items all --view expanded

echo '== Full permitted-file diff =='
git diff --unified=100 "$base" "$head" -- \
  scripts/ci/generate_release_sbom.py \
  tests/test_release_sbom_archive_bound.py \
  docs/sbom-release-evidence.md \
  CHANGELOG.md

echo '== Artifact binding and parser/digest/metadata contexts =='
rg -n -C 12 -P '\b(_open_release_artifact|_sha256_file|build_sbom|main|lstat|fstat|os\.open|O_NOFOLLOW|ZipFile|tarfile\.open|read_metadata|sha256|seek|read|resolve|st_size|stat\.S_ISREG|samefile)\b' \
  scripts/ci/generate_release_sbom.py

echo '== Relevant test contexts =='
rg -n -C 10 -P '\b(symlink|replace|mutat|oversiz|parser|ZipFile|tarfile|_sha256_file|main|O_NOFOLLOW|lstat|fstat|256)\b' \
  tests/test_release_sbom_archive_bound.py

echo '== Other exact-range changes, if any =='
git diff --name-only "$base" "$head" | grep -Ev '^(scripts/ci/generate_release_sbom\.py|tests/test_release_sbom_archive_bound\.py|docs/sbom-release-evidence\.md|CHANGELOG\.md)$' || true

echo '== Current references in documentation and changelog =='
rg -n -C 4 -P '(CWE-400|zipfile|decompression|256|compressed|mutable|SLSA|Unreleased)' \
  docs/sbom-release-evidence.md CHANGELOG.md

Length of output: 109765


@seonghobae Review found two blocking issues on exact head 01a31595eb96ef0b4df46dcfa1b529af9e7a4039 against base 421c0975cdabbc24cb4c42a9bb11e202cd33b0a4.

  1. Line 545: arguments.artifact.resolve() follows a caller-supplied final symbolic link before _open_release_artifact() calls lstat(). The helper receives the regular-file target, not the supplied symbolic-link path. A CLI caller can provide a symbolic link to a wheel or source distribution, and the generator can parse, read metadata from, and hash the target.

    Pass arguments.artifact directly to build_sbom(). Keep resolution for the manifest, lock, and output paths separate. Add a CLI-level symbolic-link regression that asserts the ZIP or tar parser does not run.

  2. Lines 462-465: The first _sha256_file() call applies the 256 MiB live read ceiling before parser execution. _artifact_metadata() then passes the unbounded descriptor directly to zipfile.ZipFile or tarfile.open. If the artifact grows after the first hash, either parser can read more than 256 MiB before the second _sha256_file() detects the oversized input.

    Apply the live read ceiling to every descriptor read, including ZIP and gzip/tar parser reads. Keep the stable oversized error. Add a regression that grows an accepted archive after the first hash and asserts parser reads fail at the ceiling.

The four-file boundary is correct. The descriptor identity comparison, mutation digest bracketing, stable error text, standalone _sha256_file contract name, documentation, APA 7 primary references, and [Unreleased] Security entry otherwise match the requested scope. I did not approve the pull request.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Implement the bounded GREEN repair on exact current test-only head 39f601cc893045e4494876cb4456dfcdaf5a1918 of branch security/bound-sbom-archive-input.

The exact test-only head adds two valid CodeRabbit regressions and must remain in history:

  1. main() currently calls arguments.artifact.resolve(), which follows the caller-supplied final symlink before the descriptor preflight. The new CLI-level regression must fail until the unresolved artifact path is passed to build_sbom(...).
  2. After the first bounded _sha256_file(...), ZIP or gzip/tar parsing receives the live descriptor without enforcing the 256 MiB ceiling on every parser read/seek. The new wheel and source-distribution regressions grow an initially accepted archive to MAX_RELEASE_ARTIFACT_BYTES + 1 after the first hash and require the stable compressed-byte error before a second hash.

Modify only:

  • scripts/ci/generate_release_sbom.py
  • tests/test_release_sbom_archive_bound.py
  • docs/sbom-release-evidence.md
  • CHANGELOG.md

Required minimal implementation:

  • Pass arguments.artifact directly to build_sbom(...); retain .resolve() for manifest, lock, and output paths.
  • Keep _open_release_artifact(...) fail-closed, no-follow, descriptor/path identity-bound, and standalone.
  • Wrap the accepted descriptor in a beginner-readable bounded binary reader, or equivalently enforce the same finite live ceiling on every descriptor read and seek used by zipfile.ZipFile and tarfile.open. Check descriptor regularity and live size before and after operations; cap unbounded or oversized reads so a concurrent growth cannot consume beyond the 256 MiB compressed limit before rejection. Preserve the exact error release artifact exceeds the compressed-byte safety bound and the existing _sha256_file callable contract.
  • Preserve the digest-before/metadata/digest-after mutation check, member and metadata bounds, dependency-lock checks, deterministic JSON, API behavior, and standalone execution.
  • Add only focused coverage tests needed for every new statement and branch; do not weaken the two new RED regressions. Maintain 100% production statement and branch coverage and beginner-readable docstrings.
  • Update operator documentation to state that the unresolved final artifact component is validated and parser-visible descriptor reads/seeks remain live-bounded even if mutable storage grows after initial hashing. Keep residual mutable-storage and non-provenance/SLSA boundaries explicit.
  • Add a concise [Unreleased] Security follow-up. Do not bump the version.
  • Preserve existing APA 7 primary references; add only a primary reference if a new claim requires it.

Stop without changing anything if the exact head is no longer 39f601cc893045e4494876cb4456dfcdaf5a1918. Do not modify .github, workflows, dependencies, credentials, permissions, protected refs, review-agent identities, network transports, signing, attestation, tags, releases, or publication behavior. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Implement the bounded GREEN repair on exact current lint-clean test-only head 7debd03ada556c114669b3259525a6d121c89550 of branch security/bound-sbom-archive-input.

This supersedes the earlier request naming head 39f601cc893045e4494876cb4456dfcdaf5a1918; that request must not be applied. Exact CI run 31096428731 proved the new RED boundary across Python 3.10–3.13: Ruff and package acceptance succeeded, and every test lane failed with exactly two focused failures (2 failed, 759 passed on Python 3.13):

  1. test_cli_rejects_symlinked_archive_before_parser proves main() follows a caller-supplied final symlink via arguments.artifact.resolve() and reaches ZIP parsing.
  2. The wheel case of test_archive_growth_after_initial_hash_is_bounded_inside_parser proves an initially accepted descriptor can grow above 256 MiB after the first hash and reach ZIP parsing, which reports release wheel is not a valid ZIP archive instead of the stable compressed-byte bound. The source-distribution parameter already fails closed with the expected bound and must remain passing.

Modify only:

  • scripts/ci/generate_release_sbom.py
  • tests/test_release_sbom_archive_bound.py
  • docs/sbom-release-evidence.md
  • CHANGELOG.md

Required minimal implementation:

  • Pass arguments.artifact directly to build_sbom(...); retain .resolve() for manifest, lock, and output paths.
  • Preserve _open_release_artifact(...) as a no-follow, regular-file, descriptor/path identity-bound preflight.
  • Ensure every parser-visible ZIP descriptor read/seek remains live-bounded by MAX_RELEASE_ARTIFACT_BYTES, including growth after the initial hash. Use a beginner-readable binary wrapper or equivalent descriptor check that tests the live regular descriptor size before and after parser operations and raises exactly release artifact exceeds the compressed-byte safety bound. Cap unbounded or oversized reads rather than permitting allocation/read beyond the ceiling. Preserve compatibility with zipfile.ZipFile, tarfile.open, _sha256_file, the generator's standalone execution, and existing caller-visible behavior.
  • Preserve digest-before/metadata/digest-after mutation detection, archive member and metadata limits, hash-locked dependency evidence, deterministic CycloneDX JSON, stable errors, and the existing sdist fail-closed behavior.
  • Add only focused tests required to cover every new statement and branch; do not weaken or delete the lint-clean RED tests. Maintain 100% production statement and branch coverage and beginner-readable docstrings.
  • Update operator documentation to state that the final artifact component remains unresolved until no-follow validation and parser-visible descriptor operations are live-bounded against mutable growth. Keep residual mutable-storage limitations and explicit non-provenance/no-SLSA-claim boundaries accurate.
  • Add a concise [Unreleased] Security follow-up. Do not bump the version. Preserve APA 7 primary references.

Stop without changing anything if the exact head is no longer 7debd03ada556c114669b3259525a6d121c89550. Do not modify .github, workflows, dependencies, credentials, permissions, protected refs, review-agent identities, network transports, signing, attestation, tags, releases, or publication behavior. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Implement the bounded GREEN repair on exact current head 7debd03ada556c114669b3259525a6d121c89550 of branch security/bound-sbom-archive-input. Stop without changing anything if the exact head differs.

Modify only:

  • scripts/ci/generate_release_sbom.py
  • tests/test_release_sbom_archive_bound.py
  • docs/sbom-release-evidence.md
  • CHANGELOG.md

The current head is intentionally RED with exactly two Python 3.10–3.13 regressions: the CLI resolves a final artifact symlink before no-follow validation, and a wheel that grows beyond 256 MiB after the first hash reaches ZIP parsing before the second bounded hash.

Required implementation:

  1. Keep _open_release_artifact(...) and the same already-open descriptor identity. Do not reopen the path for parsing or hashing.
  2. Add one private beginner-readable parser-facing reader around that descriptor. Before and after every parser-visible read or seek, use fstat() and the live offset to require a regular descriptor, size no greater than MAX_RELEASE_ARTIFACT_BYTES, and offset within 0..MAX_RELEASE_ARTIFACT_BYTES. Normalize unsafe/inspection/seek failures to exactly release artifact is missing or unsafe; normalize live growth or escaped offsets to exactly release artifact exceeds the compressed-byte safety bound.
  3. Bound any negative, omitted, read-all, or excessive read request to the remaining accepted bytes plus one tripwire byte, so the underlying descriptor never receives an unbounded -1 parser read. Support the file-like operations actually needed by the existing ZIP and gzip/tar paths without exposing a pathname reopen.
  4. Pass that bounded reader to _artifact_metadata(...); retain the existing first and second finite SHA-256 passes over the same descriptor and the exact digest-equality failure release artifact changed during verification.
  5. In main(), pass arguments.artifact directly to build_sbom(...); do not call .resolve() on the artifact path. Keep manifest, lock, and output behavior/API unchanged.
  6. Preserve all current RED tests. Add focused coverage proving: (a) growth after a parser seek but before its next read fails with the compressed-byte bound, and (b) a parser read-all request becomes a finite MAX_RELEASE_ARTIFACT_BYTES - current_offset + 1 underlying read. Add only other tests needed for the new branches and retain 100% production statement/branch coverage.
  7. Update docs/sbom-release-evidence.md to state that the descriptor-bound parser reader caps unbounded reads and rechecks live regular-file type, size, and offset around parser reads/seeks; accepted-size archives remain subject to member, path, link/device, metadata, decompression, identity, dependency, and digest controls; mutable-storage risk remains residual; no provenance or SLSA claim follows. Retain the APA 7 MITRE CWE-400 and Python zipfile decompression-pitfalls primary references.
  8. Update the existing [Unreleased] Security entry in CHANGELOG.md; do not bump the version.

No .github, workflow, dependency, credential, permission, network, signing, attestation, publication, tag, ref, release, protected-base, or public API change. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish. Run the focused tests first, then the complete repository CI-equivalent suite available on the exact resulting tree. Commit only after the credential-free exact tree is verified.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Complete the remaining bounded documentation slice on exact current head faa3939fbf6fd4a2f011d933aa0c8d3d91b75ffa of branch security/bound-sbom-archive-input.

The production repair is already present and exact-head CI for its source commit succeeded. The current head also documents unresolved final-component validation and live-bounded parser reads/seeks. Modify only CHANGELOG.md.

Under [Unreleased]Security, refine the existing direct release-SBOM archive entry (do not add a duplicate) so it states that the caller-supplied final artifact component remains unresolved until no-follow descriptor validation, and that ZIP/gzip-tar parser-visible descriptor reads and seeks remain live-bounded by the exact 256 MiB compressed-byte ceiling even if an initially accepted file grows after the first hash. Preserve stable fail-closed errors, descriptor/path identity binding, digest bracketing, residual mutable-storage limitations, and the explicit non-provenance/no-SLSA-claim boundary. Do not bump the version.

Stop without changing anything if the exact head is no longer faa3939fbf6fd4a2f011d933aa0c8d3d91b75ffa. Do not modify tests, production code, docs, .github, workflows, dependencies, credentials, permissions, protected refs, review-agent identities, network transports, signing, attestation, tags, releases, or publication behavior. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Implement the bounded GREEN follow-up on exact current test-only head f232731e6c8f4b72d2c4bdc101cf9c9fdd666b9a of branch security/bound-sbom-archive-input. Stop without changing anything if the exact head differs.

The new immutable test commit preserves the prior CLI-symlink and post-hash growth regressions and adds two focused parser-reader contracts: a read-all request must be converted to MAX_RELEASE_ARTIFACT_BYTES - current_offset + 1, and growth after a successful parser seek must fail before the next read. Modify only:

  • scripts/ci/generate_release_sbom.py
  • docs/sbom-release-evidence.md
  • CHANGELOG.md

Required minimal repair:

  1. Keep the caller-supplied final artifact component unresolved until _open_release_artifact(...) performs no-follow, regular-file, device/inode binding. Keep main() passing arguments.artifact directly.
  2. Refine the private parser-facing reader around the same accepted descriptor. Before and after every parser-visible read or seek, use fstat() and the live offset to require a regular descriptor, size no greater than MAX_RELEASE_ARTIFACT_BYTES, and offset within 0..MAX_RELEASE_ARTIFACT_BYTES.
  3. Normalize descriptor inspection, tell, read, and seek failures to exactly release artifact is missing or unsafe. Normalize live growth, oversized input, or an escaped offset to exactly release artifact exceeds the compressed-byte safety bound.
  4. For negative, omitted, read-all, or excessive read requests, pass at most the remaining accepted bytes plus one tripwire byte to the underlying descriptor. Never pass an unbounded -1 read. Preserve readinto, ZIP, gzip/tar, _sha256_file, standalone execution, and public caller compatibility.
  5. Preserve digest-before/metadata/digest-after mutation detection and every existing member, path, link/device, metadata, decompression, dependency-lock, deterministic JSON, and stable-error control.
  6. Update the existing operator documentation and the existing [Unreleased] Security entry—not duplicates—to describe unresolved final-component validation, remaining-plus-tripwire read caps, live descriptor type/size/offset checks around parser reads/seeks, residual mutable-storage risk, and the explicit non-provenance/no-SLSA-claim boundary. Preserve APA 7 primary references and do not bump the version.
  7. Run the focused tests and complete CI-equivalent suite. Maintain beginner-readable docstrings and 100% production statement/branch coverage.

Do not modify tests, .github, workflows, dependencies, credentials, permissions, protected refs, review-agent identities, network transports, signing, attestation, tags, releases, or publication behavior. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Implement the minimal GREEN repair on exact current RED head f232731e6c8f4b72d2c4bdc101cf9c9fdd666b9a of branch security/bound-sbom-archive-input.

CI run 31100972234 is valid RED evidence: package acceptance and Ruff succeeded, while every Python 3.10–3.13 lane failed with exactly one focused regression, test_parser_read_all_is_capped_to_remaining_bytes_plus_tripwire (1 failed, 762 passed on Python 3.13). The wrapper currently forwards MAX_RELEASE_ARTIFACT_BYTES + 1 for read(-1) even when the descriptor position is already nonzero; at position 2 it requests 268435457 bytes instead of the remaining-bound tripwire value 268435455.

Modify only scripts/ci/generate_release_sbom.py.

In _LiveBoundedArtifactReader.read(...), preserve the pre-read and post-read _require_live_artifact_descriptor(...) checks, but compute the maximum parser-visible read request from the current descriptor position: remaining bytes to the exact 256 MiB ceiling, plus one tripwire byte. For a negative/read-all request use that value; for a finite request use the smaller of the caller request and that value. Do not weaken the exact compressed-byte ceiling, descriptor regular-file checks, path/device/inode binding, parser wrapping, digest bracketing, stable errors, or any existing archive/member/metadata/dependency/determinism control.

Do not change tests: the exact current RED tests already define the required behavior and branch evidence. Do not modify documentation, CHANGELOG, .github, workflows, dependencies, credentials, permissions, signing, attestation, publication, release, tag, ref, network behavior, or any other path. Run the focused regression first, then the complete Python 3.10–3.13 suite, Ruff, compileall, public-docstring checks, 100% production statement and branch coverage, package acceptance, and applicable security checks on the resulting exact head. Keep the PR draft. Stop without writing if the head differs from f232731e6c8f4b72d2c4bdc101cf9c9fdd666b9a; do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only exact current head ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce against exact stacked base 421c0975cdabbc24cb4c42a9bb11e202cd33b0a4. Earlier draft-skip output, reviews of prior GREEN candidates, and analysis of RED heads are not exact-current-head review success.

Focus on direct wheel/source archive rejection before parser/hash entry; no-follow descriptor/path device+inode binding; live regular-file and exact 256 MiB checks around parser reads/seeks; the remaining-byte-plus-one-tripwire cap for both read(-1) and finite reads from nonzero offsets; descriptor-only parsing/hashing and digest bracketing; preservation of archive/member/metadata/dependency/deterministic JSON controls; stable errors; standalone generator/API compatibility; documentation and CHANGELOG accuracy; and absence of workflow, dependency, credential, permission, signing, attestation, release, publication, tag, ref, or network changes. Exact-head CI 31103070285 passed Python 3.10–3.13, Ruff, 763 tests, 1,626 statements/554 branches at 100% production coverage, compileall, product-guard self-test, and wheel/sdist acceptance. Treat documented mutable-storage risk as residual risk, not an immutable-file claim. Do not approve, merge, mark ready, rebase, retarget, release, publish, or infer success from queued checks.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Review only exact current head ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce against exact stacked base 421c0975cdabbc24cb4c42a9bb11e202cd33b0a4; do not modify the branch.

The exact RED head f232731e6c8f4b72d2c4bdc101cf9c9fdd666b9a failed every Python 3.10–3.13 lane only because a parser read(-1) from offset 2 requested the global maximum plus tripwire instead of remaining bytes plus tripwire. The current commit changes only scripts/ci/generate_release_sbom.py and uses MAX_RELEASE_ARTIFACT_BYTES - current_offset + 1, retaining live descriptor checks before and after each read. Exact-head CI 31103070285 succeeded with 763 tests, Ruff, compileall, product-guard self-test, wheel/sdist acceptance, and 1,626 statements/554 branches at 100% production coverage.

Independently verify the no-follow descriptor/path identity boundary, live parser read/seek limits, exact finite byte ceiling, descriptor-only parse/hash path, digest bracketing, archive/member/metadata/dependency/deterministic-output controls, stable errors, documentation and CHANGELOG, and absence of workflow, dependency, credential, permission, signing, attestation, release, publication, tag, ref, or network changes. Submit a current-head review outcome only after checking the exact tree and evidence. Keep the PR draft; do not merge, mark ready, enable auto-merge, release, publish, rebase, or retarget.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='421c0975cdabbc24cb4c42a9bb11e202cd33b0a4'
head='ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce'

echo '== exact commit binding =='
printf 'checked_out='; git rev-parse HEAD
printf 'base_type='; git cat-file -t "$base"
printf 'head_type='; git cat-file -t "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_ancestor=yes' || echo 'base_ancestor=no'

echo '== complete exact-range changed paths =='
git diff --name-status "$base" "$head"

echo '== implementation structure =='
ast-grep outline scripts/ci/generate_release_sbom.py --items all --view expanded

echo '== focused tests structure =='
ast-grep outline tests/test_release_sbom_archive_bound.py --items all --view expanded

echo '== complete permitted-file diff =='
git diff --unified=100 "$base" "$head" -- \
  scripts/ci/generate_release_sbom.py \
  tests/test_release_sbom_archive_bound.py \
  docs/sbom-release-evidence.md \
  CHANGELOG.md

echo '== artifact binding, parser reader, parser, hash, and CLI contexts =='
rg -n -C 12 -P '\b(MAX_RELEASE_ARTIFACT_BYTES|_open_release_artifact|_LiveBoundedArtifactReader|_require_live_artifact_descriptor|_sha256_file|_artifact_metadata|build_sbom|main|lstat|fstat|os\.open|O_NOFOLLOW|ZipFile|tarfile\.open|readinto|read|seek|tell|resolve|sha256)\b' \
  scripts/ci/generate_release_sbom.py

echo '== exact regressions and error assertions =='
rg -n -C 8 -P '\b(symlink|grow|growth|read_all|tripwire|remaining|parser|unsafe|exceeds|changed during verification|ZipFile|tarfile|main)\b' \
  tests/test_release_sbom_archive_bound.py

echo '== documentation and CHANGELOG claims =='
rg -n -C 8 -P '(256|compressed|unresolved|no-follow|descriptor|read|seek|tripwire|mutable|provenance|SLSA|CWE-400|zipfile|Unreleased|Security)' \
  docs/sbom-release-evidence.md CHANGELOG.md

echo '== out-of-allowlist paths, if any =='
git diff --name-only "$base" "$head" | grep -Ev '^(scripts/ci/generate_release_sbom\.py|tests/test_release_sbom_archive_bound\.py|docs/sbom-release-evidence\.md|CHANGELOG\.md)$' || true

Length of output: 138331


@seonghobae Review found one blocking issue on exact head ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce.

  • Lines 88-125: _LiveBoundedArtifactReader does not normalize tell(), read(), or seek() failures. It also does not validate the current offset before read(). If tell() returns an offset above MAX_RELEASE_ARTIFACT_BYTES, remaining_with_tripwire becomes negative. The default read() then forwards -1 to the descriptor. This violates the required finite parser-read contract. A failing descriptor operation can also expose an underlying OSError instead of release artifact is missing or unsafe.

    Wrap parser-visible tell(), read(), and seek() operations. Normalize their failures to the stable unsafe-input error. Before and after each operation, require an offset in 0..MAX_RELEASE_ARTIFACT_BYTES. If the offset escapes that range, raise release artifact exceeds the compressed-byte safety bound. Compute the underlying read size only after this validation. Add focused regressions for an out-of-range current offset and an underlying descriptor-operation failure.

The exact range contains only the four allowed files. The unresolved CLI artifact path, no-follow descriptor binding, device/inode checks, descriptor-only parser and hash flow, digest bracketing, archive controls, documentation, APA references, and CHANGELOG entry otherwise match the requested scope. I did not approve the pull request.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only exact current head 224e6d253a7957e981515ec66260fb1c2cf84a31 against exact stacked base fb54b615cbc69ef92c3ac787db1f3faafbc2cba9. The earlier requests for ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce, draft-skip output, prior-candidate reviews, and analysis of RED heads are superseded and are not exact-current-head review success.

Focus on direct wheel/source archive rejection before parser/hash entry; no-follow descriptor/path device+inode binding; live regular-file and exact 256 MiB checks around parser reads/seeks; the remaining-byte-plus-one-tripwire cap for read(-1) and finite reads from nonzero offsets; descriptor-only parsing/hashing and digest bracketing; preservation of archive/member/metadata/dependency/deterministic JSON controls; stable errors; standalone generator/API compatibility; documentation and CHANGELOG accuracy; and absence of workflow, dependency, credential, permission, signing, attestation, release, publication, tag, ref, or network changes. Verify the two-parent stack-sync merge imports only the deterministic parser-recursion test from the current base and leaves the PR diff at four intended files. Exact-head CI 31103515511 passed Python 3.10–3.13, Ruff, 763 tests, 1,626 statements/554 branches at 100% production coverage, compileall, product-guard self-test, and wheel/sdist acceptance. Treat documented mutable-storage risk as residual risk, not an immutable-file claim. Do not approve, merge, mark ready, rebase, retarget, release, publish, or infer success from queued checks.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Review only exact current head 224e6d253a7957e981515ec66260fb1c2cf84a31 against exact stacked base fb54b615cbc69ef92c3ac787db1f3faafbc2cba9; do not modify the branch.

The remaining-position RED head f232731e6c8f4b72d2c4bdc101cf9c9fdd666b9a failed every Python 3.10–3.13 lane only because a parser read(-1) from offset 2 requested the global maximum plus tripwire instead of remaining bytes plus tripwire. Commit ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce changes only the standalone generator to use MAX_RELEASE_ARTIFACT_BYTES - current_offset + 1 while retaining live checks before and after each read. The current two-parent merge then imports only the deterministic parser-recursion test from current PR #64. Exact-head CI 31103515511 succeeded with 763 tests, Python 3.10–3.13, Ruff, compileall, product-guard self-test, wheel/sdist acceptance, and 1,626 statements/554 branches at 100% production coverage.

Independently verify the no-follow descriptor/path identity boundary, live parser read/seek limits, exact finite byte ceiling, descriptor-only parse/hash path, digest bracketing, archive/member/metadata/dependency/deterministic-output controls, stable errors, documentation and CHANGELOG, and absence of workflow, dependency, credential, permission, signing, attestation, release, publication, tag, ref, or network changes. Submit a current-head review outcome only after checking the exact tree and evidence. Keep the PR draft; do not merge, mark ready, enable auto-merge, release, publish, rebase, or retarget.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='fb54b615cbc69ef92c3ac787db1f3faafbc2cba9'
head='224e6d253a7957e981515ec66260fb1c2cf84a31'
first_parent='ecf15d73783411f3ef0e883a4bbf7d75ee3d1fce'

echo '== exact commit binding =='
printf 'checked_out='; git rev-parse HEAD
printf 'base_type='; git cat-file -t "$base"
printf 'head_type='; git cat-file -t "$head"
printf 'head_parents='; git show -s --format='%P' "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_ancestor=yes' || echo 'base_ancestor=no'
git merge-base --is-ancestor "$first_parent" "$head" && echo 'first_parent_ancestor=yes' || echo 'first_parent_ancestor=no'

echo '== complete PR changed paths: base..head =='
git diff --name-status "$base" "$head"

echo '== merge import: first-parent..merge =='
git diff --name-status "$first_parent" "$head"
git diff --unified=80 "$first_parent" "$head"

echo '== complete permitted-file diff: base..head =='
git diff --unified=100 "$base" "$head" -- \
  scripts/ci/generate_release_sbom.py \
  tests/test_release_sbom_archive_bound.py \
  docs/sbom-release-evidence.md \
  CHANGELOG.md

echo '== changed paths outside intended four-file PR boundary =='
git diff --name-only "$base" "$head" | grep -Ev '^(scripts/ci/generate_release_sbom\.py|tests/test_release_sbom_archive_bound\.py|docs/sbom-release-evidence\.md|CHANGELOG\.md)$' || true

echo '== production structure =='
ast-grep outline scripts/ci/generate_release_sbom.py --items all --view expanded

echo '== descriptor, reader, parser, hash, and CLI contexts =='
rg -n -C 12 -P '\b(MAX_RELEASE_ARTIFACT_BYTES|_open_release_artifact|_LiveBoundedArtifactReader|_require_live_artifact_descriptor|_sha256_file|_artifact_metadata|build_sbom|main|lstat|fstat|os\.open|O_NOFOLLOW|ZipFile|tarfile\.open|readinto|read|seek|tell|resolve|sha256|st_dev|st_ino)\b' \
  scripts/ci/generate_release_sbom.py

echo '== exact artifact-bound regression contexts =='
ast-grep outline tests/test_release_sbom_archive_bound.py --items all --view expanded
rg -n -C 10 -P '\b(symlink|growth|grow|read_all|tripwire|remaining|parser|unsafe|exceeds|changed during verification|ZipFile|tarfile|main|seek|tell|OSError)\b' \
  tests/test_release_sbom_archive_bound.py

echo '== documentation and CHANGELOG claim contexts =='
rg -n -C 8 -P '(256|compressed|unresolved|no-follow|descriptor|read|seek|tripwire|mutable|provenance|SLSA|CWE-400|zipfile|Unreleased|Security)' \
  docs/sbom-release-evidence.md CHANGELOG.md

Length of output: 143994


@seonghobae Review found one blocking issue on exact head 224e6d253a7957e981515ec66260fb1c2cf84a31.

  • Lines 88-125: _LiveBoundedArtifactReader does not validate the current offset before it computes remaining_with_tripwire. If tell() returns an offset greater than MAX_RELEASE_ARTIFACT_BYTES, the computed bound is negative. For a default read() call, this negative value reaches the underlying descriptor as read(-1). This restores an unbounded parser-visible read. The reader also allows a negative seek result. In addition, tell(), read(), and seek() can expose wrapped descriptor failures instead of release artifact is missing or unsafe.

    Normalize parser-visible tell(), read(), and seek() failures to release artifact is missing or unsafe. Before and after each operation, require the offset to be within 0..MAX_RELEASE_ARTIFACT_BYTES. Raise release artifact exceeds the compressed-byte safety bound when the offset escapes this range. Compute the finite remaining-bytes-plus-tripwire request only after that validation. Add focused regressions for an out-of-range current offset, a negative seek result, and wrapped descriptor-operation failures.

The requested merge verification passed. The merge has the stated two parents. Relative to its first parent, it imports only tests/test_sealed_release_evidence_resource_limits.py with the deterministic strict-JSON recursion regression. The base-to-head PR diff contains only the intended four files.

The unresolved artifact path, no-follow descriptor binding, device/inode comparison, descriptor-only parser and hash flow, digest bracketing, archive controls, documentation, APA references, and CHANGELOG entry otherwise match the requested scope. I did not approve the pull request.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Apply the bounded GREEN implementation for the immutable RED head d5e073f799c459fa7a3f195018802d5958b5ef1e on branch security/bound-sbom-archive-input. Stop without writing if that is no longer the exact head.

Modify only scripts/ci/generate_release_sbom.py; the focused RED regressions already exist in tests/test_release_sbom_archive_bound.py.

Required behavior:

  1. Normalize OSError and ValueError from parser-visible fileno(), tell(), read(), and seek() operations to the stable non-leaking SystemExit("release artifact is missing or unsafe") boundary.
  2. Validate every parser position before using it in read-bound arithmetic and after seek/read operations. Reject booleans, non-integers, negative offsets, offsets beyond MAX_RELEASE_ARTIFACT_BYTES, and a returned seek position that disagrees with the stream's validated current position. No out-of-range position may produce a zero, negative, or -1 underlying read size.
  3. Preserve the existing finite compressed-byte ceiling and tripwire semantics: read(-1) or an excessive requested size is capped to the strictly positive bytes remaining through the ceiling plus one tripwire byte; ordinary stricter nonnegative sizes are preserved. File growth beyond the ceiling must still use the existing compressed-byte safety-bound error.
  4. Validate parser read results as bytes-like and no larger than the delegated bounded size; hostile or malformed stream results fail through the stable unsafe error. Preserve readinto behavior through the same contract.
  5. Keep all beginner-readable docstrings, direct archive path/device/inode binding, live descriptor checks around parser I/O, before/after SHA-256 equality, archive-member and metadata bounds, deterministic output, CLI semantics, and every later verification unchanged.

Run the focused archive-bound tests, complete Python 3.10–3.13 suite, Ruff, compileall, public-docstring contract, 100% production statement and branch coverage, and package acceptance on the resulting exact head. Do not modify tests, docs, CHANGELOG, .github, workflows, dependencies, permissions, credentials, protected refs, release/tag/publication behavior, or any other path. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Apply only the documentation and changelog completion to exact current head 127e4577ea31ca20e7260a482343c892efeed6f9 on branch security/bound-sbom-archive-input. Stop without writing if that is no longer the exact head.

Modify only:

  • docs/sbom-release-evidence.md
  • CHANGELOG.md

Required bounded edits:

  1. In the direct-generator contract and failure guidance, state that parser-visible descriptor operations (fileno, tell, read, and seek) are normalized to one non-leaking unsafe-artifact boundary; parser offsets must be real nonnegative integers within the 256 MiB ceiling; unbounded or excessive reads are reduced to the strictly positive remaining bytes plus one tripwire; malformed read results, negative/out-of-range positions, and seek/tell disagreement fail closed before unsafe parser consumption. Preserve the distinction that actual live file growth over 256 MiB uses the compressed-byte safety-bound error.
  2. Update the existing [Unreleased]Security entry for direct release-SBOM archive preflight to include finite parser-position validation and stable descriptor-operation failure normalization. Keep it concise; do not duplicate the entry.
  3. Preserve the residual mutable-storage limitation, all current APA 7 primary references, the no-provenance/no-SLSA claim boundary, and all existing claims. Do not add a version bump.

Do not modify scripts, tests, .github, workflows, dependencies, permissions, credentials, protected refs, review-agent identities, release/tag/publication behavior, or any other path. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Supersede the earlier documentation-only request and apply this exact bounded completion to current head 127e4577ea31ca20e7260a482343c892efeed6f9 on branch security/bound-sbom-archive-input. Stop without writing if that is no longer the exact head.

Modify only:

  • scripts/ci/generate_release_sbom.py
  • docs/sbom-release-evidence.md
  • CHANGELOG.md

Required edits:

  1. In scripts/ci/generate_release_sbom.py, make no semantic change. Wrap the overlong descriptor validation condition to the repository formatter's line length and restore exactly one final newline at EOF. Preserve every parser-state, error-normalization, finite-position, tripwire, descriptor/path, digest, and archive control byte-for-byte apart from formatting.
  2. In the direct-generator contract and failure guidance, state that parser-visible descriptor operations (fileno, tell, read, and seek) are normalized to one non-leaking unsafe-artifact boundary; parser offsets must be real nonnegative integers within the 256 MiB ceiling; unbounded or excessive reads are reduced to the strictly positive remaining bytes plus one tripwire; malformed read results, negative/out-of-range positions, and seek/tell disagreement fail closed before unsafe parser consumption. Preserve the distinction that actual live file growth over 256 MiB uses the compressed-byte safety-bound error.
  3. Update the existing [Unreleased]Security entry for direct release-SBOM archive preflight to include finite parser-position validation and stable descriptor-operation failure normalization. Keep it concise and do not duplicate the entry.
  4. Preserve the residual mutable-storage limitation, all current APA 7 primary references, the no-provenance/no-SLSA claim boundary, and all existing claims. Do not add a version bump.

Run Ruff/format checks and the focused tests/test_release_sbom_archive_bound.py tests on the resulting exact head. Do not modify tests, .github, workflows, dependencies, permissions, credentials, protected refs, review-agent identities, release/tag/publication behavior, or any other path. Do not rebase, retarget, merge, mark ready, enable auto-merge, release, or publish.

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