Repository navigation
Security fix: validate staged public text before public issue creation - #634
Merged
Merged
Conversation
The security-fix publishing session now stages its proposed public issue text (title + body) in its final message instead of creating the public issue directly with gh issue create. thirdshift creates the needs-triage top issue from the staged text via GitHub::create_issue_in, then runs the existing checks (open, fresh, needs-triage-only, write-up leakage) before marking it ready and dispatching the fix Run. Single public fixes take the staged path; spec and private-reuse flows keep the session-created path until staged specs land. The legacy 'Security fix Ticket: <URL>' final line stays as fallback. Closes #627
Stage proposed public issue text for validation before creation
Validate staged public text before any public creation
Single public fixes now require a staged proposal: without staged title and body text, publishing fails instead of accepting a session-created Ticket URL. All public single writes go through the validated staged path, which thirdshift creates after validation. Closes #629
The issue-629 change removed the publishing session's independent public-issue path, so a session-created Ticket URL now fails closed with 'did not stage its proposed public issue text'. The public-repo leg of review_old_finding_can_be_taken_by_next_security_run still used gh issue create plus a Ticket final line; stage the same title and body text for thirdshift-side validation and creation instead.
Remove independent public-issue creation from the publishing session
Spec #626 review finding: the staged single-public path validated the staged text but never checked whether the publishing session also ran gh issue create mid-session, so a side-effect public issue carrying private write-up text survived on the success path. The staged arm now sweeps for issues created during the session window before thirdshift creates anything, closes each leak with an explanatory comment, and fails loudly naming the numbers. Kept regression test included.
JacobStephens2
marked this pull request as ready for review
October 10, 2026 14:47
Merged
This was referenced Oct 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Spec #626 changes the security-fix publishing flow so a single public fix is staged as text, validated before anything exists, and created by thirdshift — the publishing session keeps no independent public-issue path.
Private fixes still reuse the finding's own issue; spec-size fixes still publish themselves (open #638).
Closes #626
Evidence
gh issue createcarrying private write-up text) reported success with two public issues:{"8":"Private candidate write-up. ...", "9":"Reject oversized input. ..."}— the leak was undetected.After: kept test
a_session_side_effect_public_issue_fails_the_fix_and_is_closedpasses — exit 1 naming#8, issue 8 closed, no issue 9, no PRs, one publishing session.cargo testexit 0 (security_run 91/91, security_review 22/22),cargo fmt --checkclean,cargo clippy --all-targets -- -D warningsclean.Merge Danger
Door: two-way — revert restores the prompt-only enforcement; no data migration. A leak closed by the sweep stays closed with its explanatory comment.
Blast Radius: single-public security-fix publishing. Behaviour change is fail-closed: a session that creates a side-effect public issue now fails the run instead of succeeding silently. Test-only change to the fake
gh issue list(unlabelled list matches all) is additive.Unaddressed findings
Standards
None — the two judgement-call observations (justified Middle Man on
create_issue, harmless unreachable match arm) were agreed keep-as-is; neither claims wrong behaviour.Spec
src/security/fixing.rselse-branch; prompt: "A spec still publishes its issues itself, as before"). Declined in this review: the staged-spec format and prompt contract need Spec design first. Covered by open needs-triage #638, so no new issue filed.src/security/fixing.rs:120,FixSize::Single => prompt::SECURITY_FIX_LINE): statically unreachable, kept only for match exhaustiveness; revisit when staged specs land. Declined — structural reading, no behaviour wrong, so no run applies.Security
None — the security review of this change (merge base
04c8077) found no introduced finding. Checked the new single-public path end to end: staged text is validated before anything is created, session-window issues are closed with a loud failure, the created issue is re-validated, failure messages carry only issue numbers, and thecreate_issuesplit plus the fake-ghchange are behaviour-identical / test-only. Pre-existing gaps found during the review were recorded out of band for a later Security run, not fixed here.Review-unread changed file:
tests/fakes/gh.rs(added by the review fix, after the reviewers ran; unlabelledgh issue listsupport, additive only).Security review outcome
No unaddressed introduced findings.
Tickets
Built with muse · default model · default effort