chore(deps): address Copilot review round 12 on #2243
Build the open-GHSA set from the raw alert feed, not from the grouped alerts. groupAlerts deliberately drops an alert with no first_patched_version, so an advisory that stays OPEN but loses its patched version vanished from both the keys and that set — and reconciliation would have called it "fixed or dismissed". Same wrong direction as the superseded case fixed last round, reached a different way: a still-open advisory must never stand itself down. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013H6Cew3KB3jVmQ5x4Dq1sq Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
233647163f
commit
bc47fcbcf0
2 changed files with 54 additions and 3 deletions
|
|
@ -1019,7 +1019,8 @@ export function main(
|
|||
|
||||
const securityPrsOff = checkSecurityPrsStillDisabled(repo, spawn);
|
||||
|
||||
const groups = groupAlerts(openAlerts(repo, spawn));
|
||||
const alerts = openAlerts(repo, spawn);
|
||||
const groups = groupAlerts(alerts);
|
||||
|
||||
// ⚠️ Loaded BEFORE the zero-group early return, and reconciled after the loop.
|
||||
// `openAlerts` asks for `state=open`, so an alert that is FIXED or DISMISSED
|
||||
|
|
@ -1036,8 +1037,23 @@ export function main(
|
|||
const boardProblems = [];
|
||||
/** Grouping keys this run actually saw in the open feed. */
|
||||
const seenKeys = new Set();
|
||||
/** Every GHSA still open, in ANY group — the check a vanished key needs. */
|
||||
const openGhsas = new Set(groups.flatMap((g) => g.ghsas));
|
||||
/**
|
||||
* Every GHSA still open, taken from the RAW feed rather than from `groups`.
|
||||
*
|
||||
* ⚠️ `groupAlerts` deliberately drops an alert with no `first_patched_version`
|
||||
* — there is nothing to bump to, so nothing to file. Building this set from
|
||||
* the groups would inherit that filter, so an advisory that stays open but
|
||||
* LOSES its patched version would vanish from both the keys and this set, and
|
||||
* reconciliation would call it "fixed or dismissed" (Copilot). Same wrong
|
||||
* direction as the superseded case, reached a different way: what a still-open
|
||||
* advisory must never do is stand itself down.
|
||||
*/
|
||||
const openGhsas = new Set(
|
||||
alerts
|
||||
.filter((a) => a.state === "open")
|
||||
.map((a) => a.security_advisory?.ghsa_id)
|
||||
.filter(Boolean),
|
||||
);
|
||||
|
||||
for (const rawGroup of groups) {
|
||||
seenKeys.add(rawGroup.key);
|
||||
|
|
|
|||
|
|
@ -1415,6 +1415,41 @@ test("main omits the security-PR claim when the token could not read it", () =>
|
|||
);
|
||||
});
|
||||
|
||||
test("main will not stand down an open alert that lost its patched version", () => {
|
||||
// groupAlerts drops an alert with no first_patched_version, so the bump's key
|
||||
// disappears — but the advisory is still OPEN. Reading the open-GHSA set from
|
||||
// the groups instead of the raw feed would report it as fixed or dismissed.
|
||||
const [filed] = groupAlerts([alert({ ghsa: "GHSA-a" })]);
|
||||
const unpatched = alert({ ghsa: "GHSA-a" });
|
||||
unpatched.security_vulnerability.first_patched_version = null;
|
||||
|
||||
const spawn = fakeSpawn({
|
||||
alertPages: [[unpatched]],
|
||||
issues: [
|
||||
{
|
||||
number: 41,
|
||||
title: buildIssueTitle(filed),
|
||||
body: buildIssueBody(filed, asInstalled()),
|
||||
},
|
||||
],
|
||||
});
|
||||
inTempRepo({ "package-lock.json": lockWith("fast-uri", "3.1.5") }, () =>
|
||||
withoutProjectToken(() =>
|
||||
captureLog(() => main("o/r", spawn, "2026-09-04")),
|
||||
),
|
||||
);
|
||||
const edit = ghCall(spawn, "edit");
|
||||
assert.ok(edit, "the issue is still reconciled");
|
||||
const body = edit.args[edit.args.indexOf("--body") + 1];
|
||||
assert.doesNotMatch(
|
||||
body,
|
||||
/fixed or dismissed/,
|
||||
"a still-open advisory must never stand itself down",
|
||||
);
|
||||
assert.match(body, /superseded/);
|
||||
assert.match(body, /`GHSA-a` is still open/);
|
||||
});
|
||||
|
||||
test("main reads every page of open dependabot issues", () => {
|
||||
// The second page holds the matching marker. Truncating the lookup would
|
||||
// file a duplicate issue rather than recognising this one.
|
||||
|
|
|
|||
Loading…
Reference in a new issue