Skip to content

[CI/Security] Automated dependency-audit workflow (pip-audit + osv-scanner) publishing a reproducible security evidence base as a nightly-release artifact #1949

Description

@oberstet

Summary

Add a security-audit job to CI that runs pip-audit and osv-scanner against a
fully resolved autobahn environment, emits a machine- and human-readable security
evidence base
(resolved versions + the matching OSV/GHSA/CVE advisories, including
transitive dependencies), uploads it as a verified artifact, and — via the existing
release.yml flow — attaches it to the nightly master-* release alongside the wheels
(e.g. like master-202609220126).

This makes the dependency-floor security review automatic, reproducible, and transitive-aware,
and replaces hand-collected advisory tables with signed, dated, tool-verified CI output. It is the
foundation issue: the follow-up dependency-floor bump for 26.9.1 should be driven off the
evidence base this produces, not off a manual spreadsheet.

Timely: autobahn just shipped a security fix of its own — CVE-2026-77528 / GHSA-hxp9-w8x3-p566
(compressed-frame maxMessagePayloadSize bypass, fixed in 26.7.1) — so standing up a continuous
dependency-audit is a natural next step in the same security track.

Why (motivation)

  • Reproducible & evidence-backed. A resolved-env scan against the OSV database is reproducible
    and cites canonical advisory IDs, rather than relying on ad-hoc, possibly-stale manual research.
    (The scanners are consumers of vulnerability databases — they are not themselves authoritative
    about whether a vulnerability exists or is exploitable in autobahn's actual use.)
  • Transitive coverage. autobahn declares only direct deps; the real attack surface includes
    transitive packages (e.g. numpy via bjdata, argon2-cffi-bindings via argon2-cffi,
    cryptography via service-identity). A resolved-env scan sees all of them.
  • Auditable over time. Publishing the evidence base as a release asset means every nightly
    carries a timestamped SBOM + advisory report — a lightweight, continuously-updated supply-chain
    record. New advisories against already-shipped versions surface on the next nightly.
  • Drives policy, not just alerts. The evidence base is the input to the deliberate floor policy
    (raise a floor only where there is a real, reachable advisory — see the follow-up issue).

What to build

1. New security-audit job in .github/workflows/main.yml

Runs on ubuntu-24.04, in parallel with the other main.yml jobs (quality-checks, test-serdes,
import-smoke, build-schema, ...). Uses the existing just create / uv toolchain.

2. Resolve the environment(s) — one scan per dependency scope

Audit each scope separately so findings are attributable to where a dep enters:

  • runtime: autobahn[all] (the union extra: twisted, compress, serialization, encryption, scram, nvx)
  • build: .[build-tools]
  • dev: .[dev] (dev/build tooling executes locally on maintainer machines and in CI, so its CVEs matter)

For each scope: install into a fresh venv, then capture the exact resolved set
(uv pip freeze / uv export) into the evidence base. (autobahn intentionally does not track a
uv.lock; the resolution is captured per run into the artifact for reproducibility, which is also
what lets the scan catch newly-disclosed advisories in transitive deps.)

3. Run both scanners over each resolved scope

  • pip-audit — PyPI/OSV-backed, Python-native; emit JSON and CycloneDX SBOM.
  • osv-scanner — run over the generated SBOM / frozen requirements; emit JSON.
  • Running both cross-verifies findings and gives richer OSV↔GHSA↔CVE linkage. Pin the tool
    versions and record the OSV database snapshot timestamp so a report is reproducible.

4. Evidence-base format (committed to the artifact, not the repo)

A directory (zipped) containing, per scope:

  • resolved-<scope>.txt — frozen pkg==version (direct + transitive).
  • sbom-<scope>.cdx.json — CycloneDX SBOM.
  • pip-audit-<scope>.json, osv-scanner-<scope>.json — raw tool output.
  • advisories-<scope>.md/.json — normalized rollup: one row per finding with
    OSV id, GHSA id, CVE id, severity/CVSS, affected range, fixed version, package, resolved
    version, direct-vs-transitive, which extra/group pulled it in
    .
  • summary.md — human rollup + provenance header: autobahn version + commit, tool versions,
    OSV DB snapshot time, run URL, UTC timestamp.

5. Publish as a nightly-release artifact

  • Upload via wamp-proto/wamp-cicd/actions/upload-artifact-verified@main (same verified-artifact
    path the wheels/schema jobs already use).
  • Extend release.yml to download-artifact-verified the audit artifact from the main run
    (main_run_id is already resolved there) and attach autobahn-security-evidence-<tag>.zip to the
    master-* release, so it ships next to the wheels.

6. CI job summary

Write the advisory rollup table to $GITHUB_STEP_SUMMARY so findings are visible on the run page
without downloading the artifact.

Design decisions (please confirm in-issue)

  1. Gating policy. Recommend non-blocking / reporting-only initially (always upload the
    evidence base; never fail unrelated PRs on a freshly-disclosed transitive advisory) — consistent
    with the project's "float tools, fix from substance" philosophy. Add opt-in gating later, scoped
    to direct declared deps resolving below their security floor (once the floors from the
    follow-up issue land), with a documented, reviewed allowlist for accepted/again-unreachable
    findings (e.g. python-ecdsa Minerva — see below).
  2. Scopes. Audit runtime [all] and [build-tools] and [dev] (dev/build CVEs are
    in-scope because those packages execute locally).
  3. Both tools (pip-audit + osv-scanner), pinned, with OSV DB snapshot recorded.

Acceptance criteria

  • security-audit job runs on push/PR in main.yml, one scan per scope (runtime/build/dev), both tools.
  • Evidence base produced with resolved versions (direct + transitive), SBOMs, raw tool output,
    normalized advisory rollup (OSV/GHSA/CVE + severity + affected/fixed + direct/transitive + extra), and a provenance header.
  • Evidence base uploaded via upload-artifact-verified and attached to the master-* nightly release by release.yml.
  • Advisory rollup written to the CI job summary.
  • Tool + OSV-DB versions pinned/recorded so a report is reproducible.
  • Non-blocking by default (documented), with a clear path to opt-in gating + allowlist.

Notes / links

  • Foundation for the 26.9.1 dependency-floor review (follow-up meta-issue): floors get raised
    off this evidence base, not a manual table. Confirmed already-landed: cryptography>=50 ([CI] PyPy-ARM64 wheel job times out: scope the smoke test by tier (lightweight on emulated) + raise emulated-job limits #1947).
  • FlatBuffers hardening is a separate, coordinated autobahn + zlmdb issue — the vendored
    FlatBuffers version is asserted equal to zlmdb's (autobahn.check_zlmdb_flatbuffers_version_in_sync()
    • test_zlmdb_flatbuffers_in_sync), so it cannot be bumped in autobahn alone.
  • python-ecdsa / Minerva (CVE-2024-23342) is N/A across autobahn, wamp-xbr and crossbar:
    python-ecdsa is used only for secp256k1 BIP32 derivation math (never P-256, never .sign());
    signing is Ed25519 (nacl) and Ethereum secp256k1 (eth_account/libsecp256k1). A good first
    allowlist entry once gating is added.
  • Nightly release example the artifact should ride along with:
    https://github.com/crossbario/autobahn-python/releases/tag/master-202609220126
  • Ties into the WAMP-group CI/CD (wamp-cicd); the audit job + evidence-base format is a candidate
    to generalize to the other group repos (txaio, zlmdb, cfxdb, crossbar, wamp-xbr) afterwards.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions