Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions prompts/security-fix.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,30 @@ With fixing allowed, publishes a terse Ticket or Spec with Tickets for the most
```
Publish the fix for this reproduced Security finding on Base branch `<base>`.
Read the private record at <private record URL> and the record below.
Follow the completed reproduction's fix size: single stages one Ticket; spec publishes a Spec with Tickets using `thirdshift-to-spec` and `thirdshift-to-tickets`.
On a public repository with a single fix, stage the proposed public issue text instead of creating the public issue directly: do not run `gh issue create` yourself. thirdshift validates the staged text and creates the `needs-triage` top issue from it. On a private repository, reuse the finding's issue as the top issue and preserve its body and evidence; add the bigger fix's Tickets as its native sub-issues. A spec still publishes its issues itself, as before.
Follow the completed reproduction's fix size: single stages one Ticket; spec stages a Spec with Tickets, drafted with `thirdshift-to-spec` and `thirdshift-to-tickets`.
On a public repository, stage the proposed public issue text instead of creating any public issue directly: do not run `gh issue create` yourself. thirdshift validates the staged text and creates the `needs-triage` top issue and its Tickets from it. On a private repository, reuse the finding's issue as the top issue and preserve its body and evidence; add the bigger fix's Tickets as its native sub-issues. Only a private bigger fix publishes its issues itself.
Every new issue is terse: it says only what the fix changes and links the private record. It carries none of the write-up, trace, evidence, reproduction notes, proof-of-concept test or exploit details, even paraphrased. Keep those in the private record. This overrides the skills' templates.
A Spec's Tickets must be new, open, labelled `ready-for-agent`, linked as native sub-issues with their native blocking links, and have no sub-issues of their own. Read the links back before finishing.
A Spec's Tickets must be new, open, labelled `ready-for-agent`, linked as native sub-issues with their native blocking links, and have no sub-issues of their own. On a public repository thirdshift makes those links from the staged text; read the staged blocking edges back before finishing.
This session changes no repository source, commits and pushes nothing, opens no pull request, and does not implement the fix. thirdshift checks every issue, marks the top issue ready, labels all fix issues security-fix and dispatches its Run or Spec run.
End your final message for a single public fix with exactly:
Proposed public issue:
Title: <title>
Body:
<body>
For a spec, end with exactly `Security fix Spec: <Issue URL>`, naming the top issue.
For a public spec, end with exactly:
Proposed public spec:
Title: <spec title>
Body:
<spec body>
Ticket: <ticket 1 title>
Body:
<ticket 1 body>
Blocked by: none
Ticket: <ticket 2 title>
Body:
<ticket 2 body>
Blocked by: 1
with each later Ticket naming the 1-based positions of the Tickets that block it, or none. For a private bigger fix, end with exactly `Security fix Spec: <Issue URL>`, naming the top issue.

Private record:
<recorded Security finding>
Expand Down
21 changes: 17 additions & 4 deletions site/prompts/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -240,17 +240,30 @@ <h3 id="prompt-security-fix-title">Security fix publishing</h3>
<p class="sent-by">Sent by a Security run, before any unit</p>
<pre class="job-text"><code>Publish the fix for this reproduced Security finding on Base branch `<mark class="ph">&lt;base&gt;</mark>`.
Read the private record at &lt;private record URL&gt; and the record below.
Follow the completed reproduction's fix size: single stages one Ticket; spec publishes a Spec with Tickets using `thirdshift-to-spec` and `thirdshift-to-tickets`.
On a public repository with a single fix, stage the proposed public issue text instead of creating the public issue directly: do not run `gh issue create` yourself. thirdshift validates the staged text and creates the `needs-triage` top issue from it. On a private repository, reuse the finding's issue as the top issue and preserve its body and evidence; add the bigger fix's Tickets as its native sub-issues. A spec still publishes its issues itself, as before.
Follow the completed reproduction's fix size: single stages one Ticket; spec stages a Spec with Tickets, drafted with `thirdshift-to-spec` and `thirdshift-to-tickets`.
On a public repository, stage the proposed public issue text instead of creating any public issue directly: do not run `gh issue create` yourself. thirdshift validates the staged text and creates the `needs-triage` top issue and its Tickets from it. On a private repository, reuse the finding's issue as the top issue and preserve its body and evidence; add the bigger fix's Tickets as its native sub-issues. Only a private bigger fix publishes its issues itself.
Every new issue is terse: it says only what the fix changes and links the private record. It carries none of the write-up, trace, evidence, reproduction notes, proof-of-concept test or exploit details, even paraphrased. Keep those in the private record. This overrides the skills' templates.
A Spec's Tickets must be new, open, labelled `ready-for-agent`, linked as native sub-issues with their native blocking links, and have no sub-issues of their own. Read the links back before finishing.
A Spec's Tickets must be new, open, labelled `ready-for-agent`, linked as native sub-issues with their native blocking links, and have no sub-issues of their own. On a public repository thirdshift makes those links from the staged text; read the staged blocking edges back before finishing.
This session changes no repository source, commits and pushes nothing, opens no pull request, and does not implement the fix. thirdshift checks every issue, marks the top issue ready, labels all fix issues security-fix and dispatches its Run or Spec run.
End your final message for a single public fix with exactly:
Proposed public issue:
Title: &lt;title&gt;
Body:
&lt;body&gt;
For a spec, end with exactly `Security fix Spec: <mark class="ph">&lt;Issue URL&gt;</mark>`, naming the top issue.
For a public spec, end with exactly:
Proposed public spec:
Title: &lt;spec title&gt;
Body:
&lt;spec body&gt;
Ticket: &lt;ticket 1 title&gt;
Body:
&lt;ticket 1 body&gt;
Blocked by: none
Ticket: &lt;ticket 2 title&gt;
Body:
&lt;ticket 2 body&gt;
Blocked by: 1
with each later Ticket naming the 1-based positions of the Tickets that block it, or none. For a private bigger fix, end with exactly `Security fix Spec: <mark class="ph">&lt;Issue URL&gt;</mark>`, naming the top issue.

Private record:
&lt;recorded Security finding&gt;
Expand Down
49 changes: 49 additions & 0 deletions src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,55 @@ impl GitHub {
])
}

/// The numeric database id of `issue`, for API calls that take one
/// instead of the issue number (sub-issues, dependencies).
fn issue_db_id(&self, issue: &IssueUrl) -> Result<u64> {
let json = self.gh_json(&[
"api",
&format!("repos/{}/issues/{}", issue.repo_slug(), issue.number),
"--jq",
".id",
])?;
json.as_u64()
.context("gh api did not return the issue's database id")
}

/// Link `child` as a native sub-issue of `parent`.
pub fn add_sub_issue(&self, parent: &IssueUrl, child: &IssueUrl) -> Result<()> {
let child_id = self.issue_db_id(child)?;
self.post_by_id(
parent,
&format!("issues/{}/sub_issues", parent.number),
"sub_issue_id",
child_id,
)
}

/// Add a native "blocked by" edge: `ticket` is blocked by `blocker`.
pub fn add_blocked_by(&self, ticket: &IssueUrl, blocker: &IssueUrl) -> Result<()> {
let blocker_id = self.issue_db_id(blocker)?;
self.post_by_id(
ticket,
&format!("issues/{}/dependencies/blocked_by", ticket.number),
"issue_id",
blocker_id,
)
}

/// `POST` one database-id field to the `endpoint` below
/// `repos/<owner>/<repo>`: the shared shape behind issue links that take
/// an id instead of an issue number.
fn post_by_id(&self, issue: &IssueUrl, endpoint: &str, field: &str, id: u64) -> Result<()> {
self.gh(&[
"api",
"--method",
"POST",
&format!("repos/{}/{}", issue.repo_slug(), endpoint),
"-F",
&format!("{field}={id}"),
])
}

/// Every open issue labelled `label` in the repository `repo`, an
/// `owner/repo`, newest first. They come from GitHub's issue list, not its
/// search, whose index can be a while behind an issue just opened.
Expand Down
11 changes: 7 additions & 4 deletions src/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,19 +360,22 @@ pub fn security_reproduction(commit: &str, finding: &str, test: &std::path::Path
pub const SECURITY_FIX_LINE: &str = "Security fix Ticket: ";
pub const SECURITY_FIX_SPEC_LINE: &str = "Security fix Spec: ";
pub const STAGED_PROPOSAL_MARKER: &str = "Proposed public issue:";
pub const STAGED_SPEC_MARKER: &str = "Proposed public spec:";
pub const STAGED_TITLE_MARKER: &str = "Title:";
pub const STAGED_BODY_MARKER: &str = "Body:";
pub const STAGED_TICKET_MARKER: &str = "Ticket:";
pub const STAGED_BLOCKED_BY_MARKER: &str = "Blocked by:";

pub fn security_fix(base: &str, url: &str, finding: &str) -> String {
format!(
"Publish the fix for this reproduced Security finding on Base branch `{base}`.\n\
Read the private record at {url} and the record below.\n\
Follow the completed reproduction's fix size: single stages one Ticket; spec publishes a Spec with Tickets using `thirdshift-to-spec` and `thirdshift-to-tickets`.\n\
On a public repository with a single fix, stage the proposed public issue text instead of creating the public issue directly: do not run `gh issue create` yourself. thirdshift validates the staged text and creates the `needs-triage` top issue from it. On a private repository, reuse the finding's issue as the top issue and preserve its body and evidence; add the bigger fix's Tickets as its native sub-issues. A spec still publishes its issues itself, as before.\n\
Follow the completed reproduction's fix size: single stages one Ticket; spec stages a Spec with Tickets, drafted with `thirdshift-to-spec` and `thirdshift-to-tickets`.\n\
On a public repository, stage the proposed public issue text instead of creating any public issue directly: do not run `gh issue create` yourself. thirdshift validates the staged text and creates the `needs-triage` top issue and its Tickets from it. On a private repository, reuse the finding's issue as the top issue and preserve its body and evidence; add the bigger fix's Tickets as its native sub-issues. Only a private bigger fix publishes its issues itself.\n\
Every new issue is terse: it says only what the fix changes and links the private record. It carries none of the write-up, trace, evidence, reproduction notes, proof-of-concept test or exploit details, even paraphrased. Keep those in the private record. This overrides the skills' templates.\n\
A Spec's Tickets must be new, open, labelled `ready-for-agent`, linked as native sub-issues with their native blocking links, and have no sub-issues of their own. Read the links back before finishing.\n\
A Spec's Tickets must be new, open, labelled `ready-for-agent`, linked as native sub-issues with their native blocking links, and have no sub-issues of their own. On a public repository thirdshift makes those links from the staged text; read the staged blocking edges back before finishing.\n\
This session changes no repository source, commits and pushes nothing, opens no pull request, and does not implement the fix. thirdshift checks every issue, marks the top issue ready, labels all fix issues security-fix and dispatches its Run or Spec run.\n\
End your final message for a single public fix with exactly:\n{STAGED_PROPOSAL_MARKER}\n{STAGED_TITLE_MARKER} <title>\n{STAGED_BODY_MARKER}\n<body>\nFor a spec, end with exactly `{SECURITY_FIX_SPEC_LINE}<Issue URL>`, naming the top issue.\n\n\
End your final message for a single public fix with exactly:\n{STAGED_PROPOSAL_MARKER}\n{STAGED_TITLE_MARKER} <title>\n{STAGED_BODY_MARKER}\n<body>\nFor a public spec, end with exactly:\n{STAGED_SPEC_MARKER}\n{STAGED_TITLE_MARKER} <spec title>\n{STAGED_BODY_MARKER}\n<spec body>\n{STAGED_TICKET_MARKER} <ticket 1 title>\n{STAGED_BODY_MARKER}\n<ticket 1 body>\n{STAGED_BLOCKED_BY_MARKER} none\n{STAGED_TICKET_MARKER} <ticket 2 title>\n{STAGED_BODY_MARKER}\n<ticket 2 body>\n{STAGED_BLOCKED_BY_MARKER} 1\nwith each later Ticket naming the 1-based positions of the Tickets that block it, or none. For a private bigger fix, end with exactly `{SECURITY_FIX_SPEC_LINE}<Issue URL>`, naming the top issue.\n\n\
Private record:\n{finding}\n\n{HEADLESS}"
)
}
Loading
Loading