Skip to content

fix(vulns): GHSA advisory references are string-array, not [{url}] (repairs enrichment)#110

Open
msitarzewski wants to merge 1 commit into
mainfrom
fix/ghsa-references-shape
Open

fix(vulns): GHSA advisory references are string-array, not [{url}] (repairs enrichment)#110
msitarzewski wants to merge 1 commit into
mainfrom
fix/ghsa-references-shape

Conversation

@msitarzewski

Copy link
Copy Markdown
Owner

Live verification (fetching a real advisory from api.github.com) caught a latent parser bug.

The bug

GET /advisories/{ghsa_id} returns references as an array of plain URL strings:

"references": ["https://github.com/.../GHSA-…"]

…but both parsers modeled it as [{ "url": … }] objects.

  • Rust (enrich.rs, since v0.5.0): a present field with the wrong element type makes the whole RawAdvisory deserialize fail → fetch_advisory_with returns Ok(None)GHSA enrichment was a silent no-op for any advisory with references (≈ all of them).
  • Swift (VulnsEnrich.swift): tolerant per-field decode kept summary/details/fixed-in working but silently dropped all references.

The fix

RawReference now accepts both shapes — an untagged enum in Rust, a custom decoder in Swift — so neither the real string shape nor the object shape (nor a future change) can silently break enrichment.

Why we missed it

The unit-test fixtures used the invented [{url}] shape — the same wrong assumption as the code — so they validated a shape the real API never sends. Fixtures are now corrected to the real captured shape (string array), plus a both-shapes regression test in each shell.

Tests

cargo enrich 17, swift 171 (each +1). clippy clean.

🤖 Generated with Claude Code

The global advisories endpoint (`GET api.github.com/advisories/{id}`) returns
`references` as an array of plain URL STRINGS, but both the Rust enrich layer
and its Swift port modeled it as `[{ "url": … }]` objects. Consequences:
- Rust: a present-but-wrong-type `references` made the WHOLE `RawAdvisory`
  parse fail, so `fetch_advisory_with` returned `Ok(None)` — GHSA enrichment
  was a silent no-op for essentially every advisory (latent since v0.5.0).
- Swift: tolerant per-field decode kept summary/details/fixed-in working but
  silently dropped all references.

Both `RawReference` parsers now accept BOTH shapes (untagged enum in Rust, a
custom decoder in Swift) so neither endpoint variant nor a future change can
silently disable enrichment again.

Root cause of the miss: the unit-test fixtures used the invented `[{url}]`
shape — the same wrong assumption as the code — so they passed against a shape
the real API never sends. Fixtures are now corrected to the REAL captured
shape (string array), plus a both-shapes regression test in each shell.

Tests: cargo enrich 17, swift 171 (each +1). clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant