security(attestation): normalize signer receipt read I/O failures #2322
Description
Finding
The signer-facing receipt reader in scripts/ci/validate_scientific_validation_receipt.py normalizes os.open() failures into EvidenceError, but os.fstat() and stream.read() failures after the descriptor has been opened can still escape as raw OSError/PermissionError.
main() only catches EvidenceError. A storage/read fault can therefore bypass the stable fail-closed CLI contract, emit a traceback, and return a platform-dependent process failure instead of the deterministic scientific-validation rejection boundary used by the owner workflow.
This is separate from semantic receipt validation: bounded regular-file intake must first normalize read-path failures before exact bytes can be delegated to validate_receipt_manifest().
Acceptance
- Add a source-level RED that injects an
OSErrorduring receipt bytes read after a valid regular file has been opened. - The reader must convert that failure to a typed
EvidenceErrorwith the receipt role in the diagnostic. - The CLI must continue to return its stable invalid-receipt status rather than leaking the raw exception.
- Preserve one-open
O_NOFOLLOW | O_NONBLOCK, descriptor-pinned parent authority, 4 MiB+1 bound, exact-byte delegation, and same-inode refusal. - Do not weaken current tests, add skip/xfail, or move the path outside the existing 100% owned quality denominator.
- Keep this in the
.githubowner; TEPP must consume only the eventual immutable/released attestation contract.
Refs #2299 #2300 #2315 #2316 #2317 #2164 ContextualWisdomLab/TEPP#637.
Activity
test(attestation): cover signer receipt read I/O failure (#2322)
fix(attestation): normalize signer receipt read I/O failures (#2322)
docs(attestation): record typed signer receipt read failures (#2322)
docs(attestation): doctor signer receipt read I/O boundary (#2322)
seonghobae commentedon Sep 21, 2026
Implemented ordinary-forward on the existing #2300 owner branch.
94f12c632703444204bb7525907cceb604770b7fadds an injected post-openstream.read()OSErrorand requires both the reader API and CLI to keep the failure inside the role-specificEvidenceError/exit-2 contract.2813d50bbcee5de37fc3bd5882479cc6726b7d77catches post-open metadata/readOSErrorwithout swallowing existingEvidenceError, returning<receipt role> read failedwhile preserving the existing one-open, pinned-parent, nonblocking/no-follow and byte-bound semantics.103f116ff46043a23341cecbb11d7570696ca918.f83237cf0a11c62b14bf391ac3576977e01a12f4.The existing Scientific Validation Evidence Quality workflow already includes both the reader and
tests/test_scientific_validation_receipt_intake.pyin PR/push path authority, 100% owned branch coverage, interrogate and compileall. No skip/xfail or denominator change was introduced.Hosted settlement is not claimed yet; the new exact-head workflow generation has not appeared in the commit-run query at this moment. Keep this issue open until current-head checks and qualifying independent review settle.
seonghobae commentedon Sep 21, 2026
Current-head settlement update: PR-event generation is now visible for
.github#2300@f83237cf0a11c62b14bf391ac3576977e01a12f4. Scientific Validation Evidence Quality run35566752445has verifier-quality job106230013392queued withrunner_id=0, empty runner name, andsteps=[]; CodeQL35566752543, Semgrep35566752498, Security35566752610, and Python Security35566752486are also non-terminal. This is runner/admission evidence, not hosted RED/GREEN. Keep #2322 open; predecessor results do not transfer and no blind rerun/wake commit is warranted.