Skip to content

ci: ignore PYSEC-2026-89 in pip-audit (markdown 3.10.2 false positive) - #12

Merged
mousebrains merged 1 commit into
mainfrom
ci-fix-markdown-vuln
May 21, 2026
Merged

ci: ignore PYSEC-2026-89 in pip-audit (markdown 3.10.2 false positive)#12
mousebrains merged 1 commit into
mainfrom
ci-fix-markdown-vuln

Conversation

@mousebrains

Copy link
Copy Markdown
Owner

Summary

  • CI's pip-audit --strict started failing on main right after Montana USGS gauges + state-scoped gauges page #10 merged, flagging markdown 3.10.2 against PYSEC-2026-89 / CVE-2025-69534 (DoS via unhandled AssertionError in html.parser.HTMLParser on malformed input).
  • This is not caused by Montana USGS gauges + state-scoped gauges page #10 — neither pyproject.toml nor uv.lock changed in that merge. The advisory was published in the ~14h between PR php: append reach location to description.php + reach.php headings #11's green CI run and PR Montana USGS gauges + state-scoped gauges page #10's red one.
  • The OSV record is malformed: it has introduced: 0 with no closing fixed event, so pip-audit treats every markdown version as affected and reports "Fix Versions" empty — even though the advisory body says 3.8.1 patched the bug. 3.10.2 is currently the latest PyPI release, so an upgrade isn't available.
  • kayak's only import markdown is at build time in src/kayak/web/build/deploy.py:183, rendering repo-controlled docs/regression/*.md → static HTML. No untrusted Markdown ever reaches the library, so the DoS surface for kayak is nil.

Fix

Add --ignore-vuln PYSEC-2026-89 to the pip-audit invocation with an inline comment explaining the OSV record bug + the build-time-only usage. Revisit when OSV amends the record or python-markdown ships 3.10.3.

Test plan

  • CI on this PR should run with the new flag — pip-audit job will go green.
  • After merge: re-verify main's next push triggers a green pip-audit job.

🤖 Generated with Claude Code

The OSV record for PYSEC-2026-89 / CVE-2025-69534 (DoS via unhandled
AssertionError in html.parser.HTMLParser on malformed Markdown input)
has a malformed affected-range: an `introduced: 0` event with an empty
closing event, so pip-audit treats every markdown version as affected
and "Fix Versions" comes back empty — even though the advisory body
says 3.8.1 patched the bug. 3.10.2 (currently pinned) is the latest
PyPI release, so we can't upgrade past it.

kayak's only `import markdown` is at build time in
src/kayak/web/build/deploy.py, where docs/regression/*.md is rendered
to static HTML. The input is repo-controlled; untrusted Markdown never
reaches the library, so the DoS surface is nil.

Revisit when OSV amends the record or python-markdown ships 3.10.3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mousebrains
mousebrains merged commit 5b4bcf6 into main May 21, 2026
8 checks passed
@mousebrains
mousebrains deleted the ci-fix-markdown-vuln branch May 23, 2026 20:53
mousebrains added a commit that referenced this pull request Jun 9, 2026
…ecover-metadata (SA-teardown-B) (#150)

* refactor(metadata): retire reverse-sync snapshot; export_metadata → recover-metadata (SA-teardown-B)

The nightly metadata snapshot existed only to reconcile editor-direct DB
edits back into the kayak_data dataset. With the editor write path off in
prod there is nothing to reconcile, so retire the reverse-sync entirely and
demote the export from an automated DB→dataset writer to a hand-run recovery
tool. Completes dataset-separation AC #6/#12: the dataset CSVs are the single
authority for metadata and no scheduled job git-mutates any repo.

Remove the snapshot machinery:
- delete scripts/snapshot_metadata.sh, systemd/kayak-metadata-snapshot.{service,timer}
- drop the unit from systemd/install.service.sh (UNITS+TIMERS) and scripts/audit-t30.sh
- remove the hc_metadata_snapshot config field (its only consumer was the deleted unit)
- dereference the snapshot in migrate.py's "deploy guard" (--check still gates
  deploy.sh; behavior unchanged), the kayak-status timing comments, and deploy.sh

export_metadata.py → `levels recover-metadata` (src/kayak/cli/recover_metadata.py):
- recovery-only subcommand; --out required (no DATASET_DIR default) and refused
  if it points inside the active DATASET_DIR, so it can't overwrite the live
  checkout — recovery output is reviewed via a normal kayak_data PR
- --db opens read-only; defaults to the configured DATABASE_URL
- rename layout.SNAPSHOT_EXPORT_CSVS → RECOVER_EXPORT_CSVS (sole importer moved)
- drop export_metadata.py from the mypy CI scope (the new module rides mypy src/)

Engine-only: no kayak_data change. Disabling the prod timer + enabling
kayak_data branch protection are the operator's SA-teardown-C step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: address #150 review — retired-env allowlist, deploy-time timer prune, stale .gitattributes ref

Three findings from the live-host adversarial review of SA-teardown-B, none a
code defect in the new path but all real deploy-sequencing / hygiene items:

1. [HIGH — deploy-brick] `deploy.sh` runs `validate-config --known-env --strict`,
   which exits 1 on any unknown `HC_*` env name. Dropping the hc_metadata_snapshot
   field would make a stale `HC_METADATA_SNAPSHOT=` line left in a prod
   `.env`/`/etc/kayak/env` fail the deploy before migrate. Allowlist the retired
   name in `validate_config._EXTRA_KNOWN` for one release (matching the METADATA_
   grace pattern) so it can't brick an otherwise-safe deploy; add tests covering
   both the allowlist membership and strict-mode tolerance.

2. [HIGH — deploy hazard] `install.service.sh` only adds/refreshes units; it never
   prunes one removed from the repo. The installed kayak-metadata-snapshot.timer
   keeps firing (~04:30) and 203/EXEC-fails nightly (script deleted) until pruned
   by hand. Document the timing-coupled disable+rm+daemon-reload (and the inert
   .env-line cleanup, and the kayak-status reinstall for config-drift parity) in
   deploy/SETUP.md §8 as an SA-teardown-B upgrade note.

3. [LOW] `.gitattributes` line 1 still named the deleted scripts/export_metadata.py
   as the regenerator — repoint to `levels recover-metadata` (and reword the
   matching "snapshotted out" comment).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant