potiuk opened a new pull request, #363:
URL: https://github.com/apache/airflow-steward/pull/363

   ## Summary
   
   The default Vulnogram API push (`vulnogram-api-record-update`) is a full 
record replacement: whatever JSON the script sends becomes the record. That 
model has bitten the Apache Airflow security team in three concrete ways during 
2026, all surfaced on `CVE-2026-41016`'s reviewer-comment thread on 2026-05-28:
   
   | Failure | Trigger |
   |---|---|
   | `PUBLIC` → `REVIEW` state regression | regenerated re-push from a sibling 
tracker walked the published state backwards |
   | `apache-airflow-providers-smtp` → `apache-airflow` product change | 
regenerator's scope-label resolution changed the affected package 
post-publication |
   | Lost `references[]` advisory URL | regenerator emits references from the 
tracker body only; the hand-added archive URL got blasted |
   
   ## Changes
   
   Three guard checks fire before the POST. All three are opt-out via explicit 
flags so deliberate changes still work:
   
   | Flag | Behaviour |
   |---|---|
   | (default) | refuse `PUBLIC` → `REVIEW / DRAFT / READY` |
   | `--allow-state-downgrade` | allow the transition |
   | (default) | merge `references[]` by URL — preserve current entries not in 
new emission |
   | `--replace-references` | replace `references[]` wholesale |
   | (default) | refuse `affected[].product` / `packageName` changes |
   | `--allow-product-change` | allow the change |
   | `--full-replace` | umbrella for all three overrides |
   
   The guards live in a new `vulnogram_api.merge_mode` module so the contract 
is testable in isolation. The CLI fetches the current record via `get_record` 
before the push (no-op when the record doesn't exist yet — first push for a CVE 
ID), passes both docs through `apply_merge_mode_guards`, and pushes the merged 
document. New exit code **3** specifically reports a merge-mode refusal so a 
scripted caller can distinguish a guard refusal from a transport / validation 
failure.
   
   ## Test plan
   
   - [x] 84 tests pass (`uv run pytest`).
   - [x] 12 new tests in `test_merge_mode.py` covering each guard's refusal + 
override paths, references-by-URL merge semantics, no-current-record (first 
push) no-op, deep-copy isolation of the input doc.
   - [x] 7 new tests in `test_record_update.py` exercising the CLI end-to-end 
against mocked `get_record` / `update_record`.
   - [x] `mypy` clean, `ruff format` / `ruff check` clean.
   - [x] Existing CLI tests still pass with the new fetch-current-before-push 
behaviour (mocked `_fetch_current_or_none` returns `None` to keep them on the 
"first push, no merge" path).
   
   ## Related
   
   - Caps the four-PR diagnostic series from Arnout's 2026-05-28 review pass: 
#360 (gate REVIEW on RC vote), #361 (sync-skill `[VOTE]` detection), #362 (CWE 
wrapper + version sanitization), this PR (record-update merge-mode).
   - Closes the regen-overwrites-manual-edits class identified in 
CVE-2026-41016's revert: with all three guards on, the regression that prompted 
the revert would have been refused at push time.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to