Skip to content

Forbid ::warning:: advisory pattern; pip-audit + benchmark fail-fast#550

Merged
mvillmow merged 4 commits into
mainfrom
chore/forbid-advisory-warnings
May 11, 2026
Merged

Forbid ::warning:: advisory pattern; pip-audit + benchmark fail-fast#550
mvillmow merged 4 commits into
mainfrom
chore/forbid-advisory-warnings

Conversation

@mvillmow
Copy link
Copy Markdown
Collaborator

Summary

Ports the Bucket F regression guard from HomericIntelligence/Odysseus#282 and refactors 2 advisory-annotation sites to fail-fast.

Refactor sites

File Line Tool Before After
.github/workflows/_required.yml 693 pip-audit --strict if ! pip-audit --strict; then echo "::warning::..."; fi pip-audit --strict
.github/workflows/extras.yml 73 make benchmark.native if ! make benchmark.native; then echo "::warning::..."; fi make benchmark.native

Lint guard

  • Adds forbid-advisory-warnings pygrep hook to .pre-commit-config.yaml (exempts _required.yml for self-documentation).
  • Adds Reject advisory annotation pattern step to _required.yml forbid-suppressions job.

Local verification

  • pre-commit run forbid-or-true --all-files -> Passed
  • pre-commit run forbid-continue-on-error --all-files -> Passed
  • pre-commit run forbid-advisory-warnings --all-files -> Passed
  • pip-audit --strict --skip-editable against .[dev] deps (pydantic>=2.0, nats-py>=2,<3, mypy, conan, pytest, pytest-asyncio, pytest-cov, pytest-timeout): no findings
  • CI grep step replicated locally with self-exemption: OK

Benchmark decision

make benchmark.native calls scripts/run_benchmarks.sh (uses set -e). The script exits non-zero on:

  • Missing build directory / no benchmark executables found
  • Any benchmark binary crash (set -e)
  • Performance regressions (only when invoked with --compare; CI invokes without --compare)

So bare make benchmark.native correctly fail-fasts on real errors (broken builds, crashed binaries) while still emitting timing data on a happy run. extras.yml itself is a non-required workflow ("Extras (non-blocking)"), so the policy ("every required CI tool must fail-fast") technically doesn't gate it — but the pygrep lint rule covers all workflow files, so the bare invocation is also the cleanest path.

Reference: HomericIntelligence/Odysseus#282

Test plan

  • CI forbid-suppressions job passes
  • CI dependency-scan job runs pip-audit --strict cleanly
  • Extras workflow benchmarks job runs make benchmark.native to completion

🤖 Generated with Claude Code

…l-fast

Ports the Bucket F regression guard from HomericIntelligence/Odysseus#282
and refactors 2 advisory-annotation site(s) to fail-fast:

- .github/workflows/_required.yml:693 (pip-audit --strict)
- .github/workflows/extras.yml:73 (make benchmark.native)

Local pip-audit --strict --skip-editable: no findings.
make benchmark.native exits non-zero only on real benchmark errors;
non-blocking timing regressions are reported but do not gate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mvillmow and others added 3 commits May 10, 2026 22:40
Removing the ::warning:: suppressions in #550 surfaced two pre-existing
issues that the advisory annotations had been hiding.

## pip-audit --strict

CI failed with:
  ERROR:pip_audit._cli:projectkeystone: Dependency not found on PyPI
  and could not be audited: projectkeystone (0.1.0)

No CVEs — the failure is that `pip install -e ".[dev]"` registers the
local project in the venv, and pip-audit then tries to look it up on
PyPI. Keystone is intentionally not published to PyPI. The third-party
dependency tree itself is clean (matches the PR author's local
`pip-audit --strict --skip-editable` run).

Fix: add `--skip-editable` to the CI invocation with a comment
explaining why. This is not an `--ignore-vuln` allowlist (no
vulnerability is being suppressed); it's scoping pip-audit to the
package set it can actually audit.

## make benchmark.native

CI failed with:
  Error: Build directory not found
  make[1]: *** [Makefile:171: benchmark] Error 1

Real bug. `scripts/run_benchmarks.sh` defaulted `BUILD_DIR` to
`$PROJECT_ROOT/build/release/bin`, but the Makefile actually produces
binaries at `$(BUILD_DIR)/$(BUILD_SUBDIR)` -> `build/x86.release/`.
The path the script looked at never existed; the prior `if ! make
benchmark.native; then echo "::warning::..."; fi` had been swallowing
this and benchmarks were never actually exercised in CI.

Fix: point the script's default at `build/x86.release` and let callers
override `BUILD_DIR` (full path) or `BUILD_SUBDIR` (suffix only).

Follow-up tracked in #551 (single
source of truth between Makefile and script; per-binary missing
detection; doc reconciliation).

Refs: #550, #551

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pre-existing issues surfaced by removing the ::warning:: suppressions
in #550 were only partially fixed by d10c8eb. Both checks were still red
on run 25652460546 / 25652460547. Real root causes and fixes below.

## security/dependency-scan (Required)

The previous fix tried `pip install -e ".[dev]" && pip-audit --strict
--skip-editable`. In pip-audit 2.10.0 (newer than the pinned version),
`--strict` treats a `--skip-editable` skip as a dependency-collection
failure and errors out:

  ERROR:pip_audit._cli:projectkeystone: distribution marked as editable
  Process completed with exit code 1.

`projectkeystone` is intentionally absent from PyPI — pyproject.toml
exists only so Python dev/test tools (mypy, conan, pytest, ...) can be
declared. There is no "install the project" requirement for an audit.

Fix: drop the editable install entirely and pass the project path as a
positional argument. `pip-audit --strict .` resolves pyproject.toml's
production dependency closure (pydantic, nats-py, pydantic_core,
annotated-types, typing_extensions, typing-inspection) directly from
PyPI metadata without installing anything. Locally:

  $ pip-audit --strict .
  No known vulnerabilities found

No `--ignore-vuln` allowlist needed; the closure is clean. No
suppression patterns introduced — still fail-fast on findings.

## benchmarks (Extras / non-blocking)

The previous fix pointed `BUILD_DIR` at `build/x86.release`, but
CMakeLists.txt:88 sets `CMAKE_RUNTIME_OUTPUT_DIRECTORY` to
`${CMAKE_BINARY_DIR}/bin`. CI log confirmed the linker produced
`bin/message_pool_benchmarks`, `bin/hierarchy_benchmarks`,
`bin/distributed_benchmarks` — but the script kept looking at
`build/x86.release/hierarchy_benchmarks` (no bin/), so every binary
was reported missing and `make benchmark` exited non-zero.

Fix: introduce `BENCH_BIN_DIR` (default `$BUILD_DIR/bin`) and use it
everywhere the script previously read `$BUILD_DIR/$bench`. Callers can
still override `BUILD_DIR` (full path to the CMake binary dir),
`BUILD_SUBDIR` (suffix only), or `BENCH_BIN_DIR` (full path to
binaries) to point at non-standard layouts.

Refs: #550, #551

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ees them

After fixing the benchmark binary lookup path in 3145bc9, CI got further:
all three benchmark executables (hierarchy, message_pool, distributed)
ran to completion and wrote their per-suite JSON files. The post-run
"Merging results..." heredoc then failed with:

  No result files found matching None/*_None.json
  make[1]: *** [Makefile:171: benchmark] Error 1

`python3 << EOF` runs as a subprocess of bash and only inherits
*exported* environment variables. `RESULTS_DIR`, `TIMESTAMP`,
`RESULTS_FILE`, and `COMPARE_BASELINE` were plain shell locals, so
`os.environ.get('RESULTS_DIR')` returned None on both the merge
heredoc and the regression-compare heredoc.

Fix: export the four shell variables the heredocs reference.

Refs: #550

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mvillmow mvillmow merged commit 0c83068 into main May 11, 2026
22 checks passed
@mvillmow mvillmow deleted the chore/forbid-advisory-warnings branch May 11, 2026 14:07
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