Skip to content

Commit 64f3547

Browse files
committed
docs(fix-vulnerability skill): codify branch-per-advisory workflow
Adds a pre-step-1 callout and restructures step 8 into 8a-8e covering: - Isolation rationale (one branch per advisory; main is the integration line) - Fork creation via the advisory endpoint - Branch creation (new advisory vs follow-up on existing fork) - Commit/push hygiene - Integration into main at release time Branch-per-advisory keeps embargoed fixes off main until publication and makes conflicts surface deliberately at integration rather than hide inside a stack of fix commits.
1 parent eb88541 commit 64f3547

1 file changed

Lines changed: 59 additions & 3 deletions

File tree

  • .claude/skills/fix-vulnerability

.claude/skills/fix-vulnerability/SKILL.md

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ Wear three hats simultaneously:
5151

5252
## Workflow
5353

54+
> **Before step 1**: this skill assumes you are working **on a dedicated per-advisory branch**, not on `main`. See step 8a for why and step 8c for the setup commands. If the user invoked `/fix-vulnerability` while `git branch --show-current` returns `main`, your first action is to create and check out a fresh branch (`git checkout -b ghsa-<short-id> main`). Every subsequent step — repro test, multi-angle agents, instrumentation, doc updates, commits — happens on that branch. Local `main` stays clean and never carries an embargoed fix commit.
55+
5456
### 1. Orient
5557

5658
Re-read `CLAUDE.md` and `docs/ATTACKS.md` cover-to-cover. CLAUDE.md has the file roles and architectural map; ATTACKS.md has the attack catalog, the [Defense Invariants](../../../docs/ATTACKS.md#defense-invariants), and the [Category Entry Format](../../../docs/ATTACKS.md#category-entry-format) you'll use later.
@@ -166,6 +168,21 @@ Apply the fix with minimal, self-contained diff. Comment every security-critical
166168

167169
Each advisory gets its own **temporary private fork** at `patriksimek/vm2-ghsa-<short-id>`. This fork is what the reporter (added as a collaborator on the advisory) sees and reviews; **never** push the embargoed fix to `origin` (`patriksimek/vm2`) until the advisory is published.
168170

171+
#### 8a. Isolation: one branch per advisory
172+
173+
**Local `main` stays at the last public release commit** (`origin/main` tip) — it is the integration line, not a scratch branch. Every embargoed fix lives on its own branch tracking its own private fork. This is the load-bearing invariant of the multi-advisory workflow:
174+
175+
- **Two open reports never see each other's commits** until the maintainer chooses to integrate them. No accidental cross-contamination in tests, comments, or commit messages.
176+
- **`/hacker`, `npm test`, and the multi-angle agents** for advisory A run against advisory A's checked-out branch only — they cannot stumble into an advisory-B mitigation that incidentally also blocks the bypass they were looking for.
177+
- **Conflict surfaces at integration time, not at commit time.** When two advisories both touched `lib/bridge.js`, the conflict is resolved deliberately in front of `npm test`, not hidden inside a stack of `fix(GHSA-…)` commits on `main`.
178+
- **Rollback is trivial.** If a reporter rejects the structural direction, `git checkout main && git branch -D ghsa-<short-id>` plus a force-push to the private fork undoes everything without disturbing `main` or other open advisories.
179+
180+
**Switching between advisories** is `git checkout ghsa-<other-short-id>`. Commit or stash anything in flight first — uncommitted changes carry across branches in a single working directory.
181+
182+
**Multi-angle exploration agents** (the three Generators spawned in step 5) still use `isolation: "worktree"` — each spawns its own temporary worktree off the current branch tip so it can edit and test in parallel without disturbing your work. Those worktrees are scratch space owned by the agents; clean them up after you've synthesized.
183+
184+
#### 8b. Create the temporary private fork
185+
169186
**Check whether a fork already exists** as a git remote pointing at the GHSA-specific repo:
170187

171188
```bash
@@ -185,19 +202,58 @@ git remote add ghsa-<short-id> git@github.com:patriksimek/vm2-ghsa-<GHSA-id>.git
185202

186203
If the API call returns 202/Accepted, the fork is being created asynchronously — poll `gh api repos/patriksimek/vm2-ghsa-<GHSA-id>` until it returns 200 before pushing.
187204

188-
**If the fork DOES exist** — this is a follow-up commit (e.g. reporter found a bypass, requested a tweak). Add an additional commit to the existing branch on that fork. Do not force-push or rebase prior commits the reporter has already reviewed.
205+
#### 8c. Create the per-advisory branch
189206

190-
**Push the fix**:
207+
For a **new advisory** (fork is fresh, no commits beyond `main`):
191208

192209
```bash
193-
git push ghsa-<short-id> HEAD:main # or a dedicated fix branch
210+
# From main, branch off and check out.
211+
git checkout main
212+
git checkout -b ghsa-<short-id>
194213
```
195214

215+
For a **follow-up on an advisory you've already pushed** (reporter found a bypass, asked for a tweak, or you're resuming after a context switch and deleted the local branch):
216+
217+
```bash
218+
git fetch ghsa-<short-id>
219+
git checkout -b ghsa-<short-id> ghsa-<short-id>/main
220+
```
221+
222+
The branch lives only locally and on the private fork's `main`. It is your working branch where you accumulate commits before pushing.
223+
224+
#### 8d. Commit and push
225+
226+
All edits, multi-angle agent worktrees spawned with `isolation: "worktree"` (those spawn off the current branch tip and stay isolated), repro tests, `npm test`, `/hacker` runs, ATTACKS.md updates, and CHANGELOG.md entries happen **on this branch**. Local `main` is never touched during embargoed work.
227+
228+
When ready:
229+
230+
```bash
231+
# From the advisory branch
232+
git push ghsa-<short-id> HEAD:main
233+
```
234+
235+
**If the fork already has commits** (follow-up commit on a previously reviewed fix) — add a new commit on top. Do not force-push or rebase commits the reporter has already reviewed.
236+
196237
**Disclosure hygiene**:
197238
- Do not push to `origin` or open a public PR.
198239
- Commit messages MAY reference the GHSA ID — the fork is private and visible only to maintainers + reporter.
199240
- Never reference reporter names or embargo dates in commits, code comments, or `CHANGELOG.md`.
200241

242+
#### 8e. Integration into `main` (at release time, not during embargo)
243+
244+
When the advisory is published and the next release is being cut, merge each ready advisory's branch into `main` in a deliberate integration pass:
245+
246+
```bash
247+
git checkout main
248+
git merge --no-ff ghsa-<short-id>
249+
# Resolve any cross-advisory conflicts in lib/bridge.js etc.
250+
npm test
251+
# Run /hacker once more against the integrated tree.
252+
# Bump version in package.json, write CHANGELOG release header, then push origin.
253+
```
254+
255+
Only after the public push do you delete the per-advisory branch (`git branch -d ghsa-<short-id>`) and (optionally) archive the private fork.
256+
201257
### 9. Post-commit summary
202258

203259
After every commit (initial fix or follow-up), produce a **short** summary of what changed and post it to the advisory thread / share with the user. Keep it terse — the details live in the diff, the tests, and `ATTACKS.md`.

0 commit comments

Comments
 (0)