Problem
skills/pr-batch/bin/autonomous-merge-calibrate (added in #252, merged at head f55f81c) gates its dataset-shape validation behind the no---repo branch:
# skills/pr-batch/bin/autonomous-merge-calibrate:131-137
unless options[:repositories].any?
abort "calibration PR must be a mapping" unless prs.all? { |pr| pr.is_a?(Hash) }
unless prs.all? { |pr| pr["repository"].is_a?(String) }
abort "calibration PR repository must use OWNER/REPO form"
end
end
prs = prs.select { |pr| pr.is_a?(Hash) && repositories.include?(pr["repository"]) }
When --repo is supplied, non-Hash (corrupt/tampered) PR entries are silently dropped by the select instead of aborting.
Evidence (verified by experiment on f55f81c)
A dataset containing [validPR, 42, "corrupted-entry"] plus an enforced reviewed_heads_decision:
- without
--repo: exit 1, calibration PR must be a mapping (correct, fail-closed)
- with
--repo example/one --format decision: exit 0, disposition enforced, empty blockers
skills/pr-batch/bin/autonomous-merge-eligibility:249 consumes exactly that disposition field, so a tampered/corrupt dataset can feed an enforcement input through the filtered path that the unfiltered path rejects. This contradicts PR #252's fail-closed completeness-validation claims.
Direction
Validate pr.is_a?(Hash) and the repository string shape for all entries before applying the repository filter (move the two checks above the unless options[:repositories].any? guard, or drop the guard). Add a regression test: corrupt entry + --repo filter must abort, not emit a decision.
Found by adversarial review of #252: #252 (comment) (finding B1).
Problem
skills/pr-batch/bin/autonomous-merge-calibrate(added in #252, merged at headf55f81c) gates its dataset-shape validation behind the no---repobranch:When
--repois supplied, non-Hash (corrupt/tampered) PR entries are silently dropped by theselectinstead of aborting.Evidence (verified by experiment on
f55f81c)A dataset containing
[validPR, 42, "corrupted-entry"]plus an enforcedreviewed_heads_decision:--repo: exit 1,calibration PR must be a mapping(correct, fail-closed)--repo example/one --format decision: exit 0, dispositionenforced, empty blockersskills/pr-batch/bin/autonomous-merge-eligibility:249consumes exactly that disposition field, so a tampered/corrupt dataset can feed an enforcement input through the filtered path that the unfiltered path rejects. This contradicts PR #252's fail-closed completeness-validation claims.Direction
Validate
pr.is_a?(Hash)and therepositorystring shape for all entries before applying the repository filter (move the two checks above theunless options[:repositories].any?guard, or drop the guard). Add a regression test: corrupt entry +--repofilter must abort, not emit a decision.Found by adversarial review of #252: #252 (comment) (finding B1).