An agent-owned nixpkgs fork that turns known upstream security fixes into
signed, merge-ready CVE evidence bundles.
Findings, cost numbers and the corpus browser live at trace.adastra.computer.
trace is a research artifact, not a product. It tests one question: can an agent system take a disclosed CVE and a known upstream fix and produce a maintainer trustworthy nixpkgs evidence bundle, signed against a locked workflow identity. It is an upstream-fix integrator, not a generic auto-patcher and not a vulnerability-discovery system. The scope boundaries are deliberate; see Boundaries.
# Flakes and nix-command must be enabled (nix.conf: experimental-features =
# nix-command flakes), or prefix with --extra-experimental-features.
nix develop # dev shell from flake.nix
pytest # full suite, offline, no API spendA bundle is a directory of files under traces/example/CVE-XXXX-XXXXX--<attr>/.
A complete bundle records a CVE, the affected derivation, the proposed patch, the
proof the patch fixes the vulnerability, and the routing verdict; some in-repo
directories are staged or single-role fixtures rather than complete signed
bundles. To read one:
ls traces/example/CVE-2025-26625--git-lfs/
cat traces/example/CVE-2025-26625--git-lfs/finding.jsonSignature verification runs against the signed artifact a Steward run produces,
not the in-repo copy. The run emits a bundle.canonical.json frozen snapshot,
and trace bundle verify <downloaded-dir> verifies the cosign signature over that
snapshot, including the embedded Rekor transparency-log proof and the locked
workflow identity. (Steward checks the per-file replay hashes at signing time.)
See docs/SIGNING_V1.md for the download-and-verify
protocol.
A CVE flows through a chain of roles, each with an explicit contract under
agents/<role>/, a schema in policy/, and a final Steward that can deny the
result:
- Scout discovers CVEs from NVD and Vulnpatch, scopes them against a frozen
nixpkgs graph snapshot, and records version bounds and fix-commit refs. Runs
hourly under
.github/workflows/scout-cron.yml. - UpstreamRefResolver decides eligibility from whether a derivable target version and a recognized fix-commit URL exist. Deterministic, no model.
- Cartographer records the downstream packaging context: the affected
derivation's
impact.json(rebuild closure) andmaintainers.json. - Patcher produces the diff and a
patch-rationale.md. Model-authored or deterministic. It cannot decide its own eligibility. - Reviewer adversarially reviews the patch against the upstream ground truth. It must be a different model family from the Patcher (the cross-family rule), so the reviewer and the author never share context.
- Reproducer demonstrates the vulnerability with a sandbox test that fails on the unpatched build and passes on the patched one, or refuses with a principled reason (the CVE class needs a network socket, no public PoC, and so on).
- Builder runs the patched derivation and the affected
passthru.testsundernix-build, and runs the Reproducer's two test arms.
Steward then evaluates the assembled bundle against policy/steward.rego and
routes it to one of four states: auto-merge, human-review-required,
advisory-only, or ineligible-rejected. Auto-merge bundles are signed with Sigstore
keyless OIDC against a locked workflow identity; the signature anchors to a Rekor
entry that anyone can check with trace bundle verify or cosign verify-blob.
Latest tag: v1.0.0 (20 October 2026). The corpus in
traces/example/ holds 184 real-CVE directories (excluding the CVE-0000-*
synthetic fixtures), of which 137 carry a bundle.json evidence bundle and
the rest are staged or single-role fixtures; 113 of those are tracked on the
bundle browser, 86 of them
cert-green. Every bundle in the current corpus was reviewed by a frontier
model. A Reviewer-LoRA adapter on Qwen2.5-Coder-14B-Instruct passed its own
pilot gate (84 cert-green positives, 55 negatives) and is kept on record as a
cost-reduction experiment, but it is not in the production path and makes no
frontier-parity claim.
Where the pipeline stands on running without a human:
- Patcher and Reviewer run without a human. The Patcher authors the fix, the
Reviewer verifies it cross-family against the upstream fix, and dozens of
bundles have passed a full Linux cert (
bundle-linux-cert.yml) with a signed manifest. - The Reproducer authors its behavioral test without a human with Sonnet or Haiku as of August 2026. Earlier this stage needed a human because the model output failed to parse; that was a format-handling limit, now fixed.
- Corpus-wide auto-merge is ongoing, not finished. A bundle reaches
auto-merge on one of two paths: a cert-green sandbox Reproducer, or a
reviewer-attested route where the CVE class admits no sandbox reproducer and
the bundle ships a principled
reproducer-refusal.json. Either way the fix must be cert-green and the signature must verify. Many bundles route instead to human-review-required for documented policy reasons: major version jumps, large rebuild closures, or a CVE class with no sandbox reproducer. That routing is the policy working as designed.
Bundles live as files; review happens in pull requests against the fork. The
site is a read-only view of the corpus, not a way to run the pipeline. Frozen
scope: nixpkgs nixos-unstable, derivations with passthru.tests, upstream
fixes that ship in a release or tag, and a rebuild closure under 500.
trace opens pull requests against its own Ad-Astra-Computing/nixpkgs fork from
cert-green bundles. These measure how close the pipeline's output lands to the
human upstream fix. They are not merge candidates and are never submitted to
nixpkgs. The fork is the staging ground; the signed bundles are the artifact.
What trace deliberately does not do:
- Auto-merge for kernel CVEs. The kernel builds its source inside
buildLinux, not from a flatsrc = fetchurl, so there is no single fixed-output hash to bump. Kernel CVEs route to human-review-required. A kernel-aware patcher is a separate arc. - Direct upstreaming. Bundles are evidence. Humans pick what to upstream and when.
- Novel-vulnerability discovery. A separate lane with separate guardrails, out of scope here.
- Live-API CI on every push. The live-Anthropic path is wired and proven, but running it on every push is gated on per-workspace budget caps. Live model calls are research spend.
- Hydra integration and a UI. Both deferred.
docs/CONCEPTS.md: what trace is, and the core ideas (bundles, roles, kinds, the cross-family rule, signing).docs/ARCHITECTURE.md: directory layout, control flow, and what pins what.docs/SEED_INDEX.md: a per-bundle map of the corpus.SPEC.md: the v0 design.- Per-role contracts under
docs/:BUILDER_V1.md,REPRODUCER_V1.md,STEWARD_V1.md,SIGNING_V1.md. CHANGELOG.md: tagged release notes.
nix develop # default dev shell
pytest # full suiteThe Rust graph crate has its own shell: nix develop .#graph.
Local git hooks run a secret scan plus house-style and invisible-character
checks before a commit reaches origin. See CONTRIBUTING.md for how contributions
are signed and reviewed.
Apache-2.0 covers trace's own content: the pipeline code, schemas, docs,
prose, and most of the JSON evidence a bundle writes. It does not cover
every file under traces/: a bundle's package.nix is copied verbatim
from nixpkgs and stays MIT, nixpkgs' own license, and a bundle's own
upstream-fix patch, source excerpts and co-landed test assets are
verbatim records of the upstream project's own code or security fix,
kept under that project's own license. REUSE.toml
declares the license for every such file, built by
scripts/gen_third_party_notices.py
from what is actually on disk rather than a hand-maintained list;
traces/THIRD_PARTY_NOTICES.md is the
same information read as a table. See LICENSE and
CONTRIBUTING.md for inbound terms on trace's own
content. Citing trace in your own work: see CITATION.cff.
Every signed bundle anchors a Rekor transparency-log entry to a locked workflow
identity. The verifier-side identity (issuer, subject regex, expected workflow
ref) lives in policy/signing-identity.json and
is the authoritative pin. See docs/SIGNING_V1.md for the
verifier protocol.
For coordinated disclosure, see SECURITY.md.