Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

deny.toml

# cargo-deny configuration for gunnar — the "0 known CVE" gate.
#
# The deploy pipeline (`<ops>/deploy.sh` `door cve`) runs, on gunnar's own Cargo.lock:
#     cargo deny --no-default-features check advisories
#     cargo deny --no-default-features check bans
# and aborts the deploy if either goes red, exactly like a KVM boot door.
#
# Every `ignore` below is a triaged, dated decision — NOT a blanket mute.
# `yanked = "deny"` and the `bans` duplicate check are deliberately strict so a
# NEW yanked crate or a NEW advisory fails the door by name. Proven red-then-green
# 2026-08-31 (see `<ops>/deploy.sh` door history).

[advisories]
version = 2
# Fail the door on any crate the registry has yanked. A yanked crate is a warning,
# not a CVE, but the gate treats it as a hard stop so it cannot rot in silently.
yanked = "deny"
ignore = [
    # ---------------------------------------------------------------------------
    # RUSTSEC-2023-0071 — Marvin Attack, RSA private-key timing sidechannel.
    # Crate: rsa 0.10.0-rc.18. No safe upstream version exists.
    # Triaged 2026-08-31 (lane CVE-GATE):
    #   rsa enters ONLY through russh's default `rsa` feature (and the transitive
    #   ssh-key/rsa) — a capability of the SSH stack, not something gunnar calls.
    #   gunnar's SSH server (gunnar-ssh) mints and uses an ed25519 host key
    #   EXCLUSIVELY: gunnar-core::host_key::mint_ed25519 / Algorithm::Ed25519,
    #   with no code path that generates or signs with an RSA host key. The
    #   network-facing server therefore performs no RSA private-key operation.
    #   Verifying a client's RSA signature is not a private-key op and leaks no
    #   secret. The only path that could exercise an RSA private-key op is a
    #   gunnar CLIENT dialling with an operator-supplied ~/.ssh/id_rsa (client
    #   key search order: id_ed25519, id_ecdsa, id_rsa) — and its timing is
    #   observable only by the trusted remote it dials, not by an attacker.
    #   => The Marvin timing sidechannel is not reachable on gunnar's attack
    #      surface. Fully removing rsa from the tree is possible (russh
    #      default-features = false, drop `rsa`) but requires the same change in
    #      sibling nornir-git and pageant; tracked as a project decision.
    { id = "RUSTSEC-2023-0071", reason = "rsa is unreachable: gunnar's SSH server host key is ed25519-only (gunnar-core mint_ed25519); no RSA private-key op on any network-facing path. Triaged 2026-08-31. Full drop needs russh feature change in nornir-git+pageant (decision)." },

    # ---------------------------------------------------------------------------
    # RUSTSEC-2026-0222, RUSTSEC-2026-0269, RUSTSEC-2026-0316 (wasmtime 45.0.3):
    #   ignores REMOVED 2026-10-06 (round 4 triage). The lock carries wasmtime
    #   49.0.2 only (nornir-build-thing moved off ^45), which no advisory names;
    #   cargo-deny warned "advisory was not encountered" for all three. A stale
    #   ignore would mute the next wasmtime advisory of the same id for nothing.

    # ---------------------------------------------------------------------------
    # RUSTSEC-2026-0173 — proc-macro-error2 is unmaintained (not a vulnerability).
    # Crate: proc-macro-error2 2.0.1. No maintained release exists.
    # Triaged 2026-10-06 (round 4):
    #   it enters ONLY as a PROC-MACRO of i18n-embed-fl, which `age` 0.11.5 needs
    #   unconditionally (no feature turns it off) for its CLI's localized messages;
    #   gunnar-crypt takes age with default-features = false, features ssh+armor
    #   (encrypted repositories). A proc-macro runs in the compiler and links into
    #   no binary: nothing of it is on any shipped gunnar's runtime path. The fix
    #   is upstream (age/i18n-embed-fl moving off it); re-check at every age bump.
    { id = "RUSTSEC-2026-0173", reason = "proc-macro-error2 2.0.1 is unmaintained (no vulnerability): a compile-time proc-macro of i18n-embed-fl, which age 0.11.5 needs unconditionally (gunnar-crypt: age ssh+armor). Links into no binary. No maintained release. Triaged 2026-10-06; re-check at every age bump." },

    # ---------------------------------------------------------------------------
    # RUSTSEC-2026-0374 — basic-toml is unmaintained (not a vulnerability).
    # Crate: basic-toml 0.1.10. No safe upgrade exists.
    # Triaged 2026-10-28 (lane OX-CVE):
    #   it enters ONLY through i18n-config 0.4.8 (the newest; 0.4.7+ moved from
    #   toml to basic-toml), which the PROC-MACROS i18n-embed-impl and
    #   i18n-embed-fl read i18n.toml with at compile time; `age` 0.11.5 needs them
    #   unconditionally (gunnar-crypt: age ssh+armor), the same path as
    #   RUSTSEC-2026-0173 above. It parses this build's own i18n.toml, never
    #   input from a user or the network, and links into no binary. It cannot be
    #   replaced from here (a third-party proc-macro's dependency); the fix is
    #   upstream (i18n-config moving to toml). Re-check at every age bump.
    { id = "RUSTSEC-2026-0374", reason = "basic-toml 0.1.10 is unmaintained (no vulnerability): only a compile-time dependency of i18n-config 0.4.8 (newest), read by the proc-macros i18n-embed-impl/i18n-embed-fl that age 0.11.5 needs unconditionally (gunnar-crypt). Parses the build's own i18n.toml, links into no binary. No maintained release. Triaged 2026-10-28; re-check at every age bump." },

    # ---------------------------------------------------------------------------
    # OSSF-NEXT, 2026-10-30: the advisories with no fixed release that the NESTED locks
    # (and the root with --all-features) carry. cargo deny reads this file from every
    # workspace below the root; OSV-Scanner reads the osv-scanner.toml beside each lock,
    # and xtask/tests/osv_triage.rs keeps every id there equal to an entry here. Run with
    # --no-default-features at the root, cargo-deny warns "not encountered" for the
    # nested-only ids: that is expected, they are triaged for the locks that carry them.
    { id = "RUSTSEC-2026-0370", reason = "zvariant is unmaintained (no vulnerability): zbus 5's D-Bus types, only in gunnar-cli's optional skidbladnir (installer) feature, which talks to the local system bus and never to the network. No maintained release of zbus 5; the fix is upstream. Triaged 2026-10-30 (OSSF-NEXT); re-check at every skidbladnir bump." },
    { id = "RUSTSEC-2026-0371", reason = "zbus_names is unmaintained (no vulnerability): zbus 5's D-Bus names, only in gunnar-cli's optional skidbladnir (installer) feature, local system bus only. No maintained release; the fix is upstream. Triaged 2026-10-30 (OSSF-NEXT); re-check at every skidbladnir bump." },
    { id = "RUSTSEC-2026-0372", reason = "zvariant_derive is unmaintained (no vulnerability): a compile-time proc-macro of zbus 5, only in gunnar-cli's optional skidbladnir (installer) feature; links into no binary. Triaged 2026-10-30 (OSSF-NEXT); re-check at every skidbladnir bump." },
    { id = "RUSTSEC-2024-0320", reason = "yaml-rust is unmaintained (no vulnerability): only through syntect (gunnar-ui-server's syntax highlighting, two-face, typst), which reads the build's own bundled syntax definitions, never YAML from a user or the network. No fix in syntect 5. Triaged 2026-10-30 (OSSF-NEXT); re-check at every syntect bump." },
    { id = "RUSTSEC-2025-0141", reason = "bincode 1 is unmaintained (no vulnerability): only through syntect, which decodes the build's own bundled syntax and theme dumps. No fix in syntect 5. Triaged 2026-10-30 (OSSF-NEXT); re-check at every syntect bump." },
    { id = "RUSTSEC-2024-0436", reason = "paste is unmaintained (no vulnerability): a compile-time proc-macro of biblatex/hayagriva (typst-library, via nornir-docbook's renderer); links into no binary. Triaged 2026-10-30 (OSSF-NEXT); re-check at every typst bump." },
    { id = "RUSTSEC-2024-0449", reason = "unsafe-libyaml is unmaintained (no vulnerability): only through serde_yaml in hayagriva/typst-library (bibliography files); nornir-docbook renders Markdown to typst with no bibliography, so no user YAML reaches it. Triaged 2026-10-30 (OSSF-NEXT); re-check at every typst bump." },
    { id = "RUSTSEC-2026-0192", reason = "ttf-parser is unmaintained (no vulnerability): typst/krilla/usvg's font parser in nornir-docbook's renderer, which loads only the fonts bundled into the build. No maintained release. Triaged 2026-10-30 (OSSF-NEXT); re-check at every typst bump." },
    { id = "RUSTSEC-2026-0206", reason = "rustybuzz is unmaintained (no vulnerability): typst/krilla/usvg's text shaper in nornir-docbook's renderer, over the build's bundled fonts only. No maintained release. Triaged 2026-10-30 (OSSF-NEXT); re-check at every typst bump." },
    { id = "RUSTSEC-2026-0194", reason = "quick-xml 0.38 (quadratic duplicate-attribute check), fixed only in 0.41: it enters through citationberg 0.7.0 (newest, quick-xml ^0.38), typst's CSL style reader; nornir-docbook renders Markdown to typst with no bibliography, so no user XML reaches it (plist already takes 0.42). Triaged 2026-10-30 (OSSF-NEXT); re-check at every typst/citationberg bump." },
    { id = "RUSTSEC-2026-0195", reason = "quick-xml 0.38 (unbounded NsReader namespace allocation), fixed only in 0.41: through citationberg 0.7.0 (newest), typst's CSL style reader; nornir-docbook renders Markdown with no bibliography, so no user XML reaches it. Triaged 2026-10-30 (OSSF-NEXT); re-check at every typst/citationberg bump." },
    { id = "RUSTSEC-2026-0387", reason = "crypto-bigint 0.5 (timing variability), fixed only in 0.7.6: the 0.5 line enters through elliptic-curve 0.13 of ssh-key 0.6.7, which only monetize-shop-pairing (a sibling) takes; Gunnar's own SSH stack is on ssh-key 0.7 / crypto-bigint 0.7.10. The fix is monetize-shop-pairing moving to ssh-key 0.7. Triaged 2026-10-30 (OSSF-NEXT)." },
    # The second russh (0.63.3) the root, gunnar-front and deploy/upcloud keep under nornir-git
    # 0.2.2 until nornir-git 0.2.3 is published (row SSH-PUBLISH). GitHub advisories with no
    # RustSec id: cargo-deny does not see them, OSV-Scanner does; listed here so the two lists
    # stay equal (xtask/tests/osv_triage.rs).
]

[bans]
# Duplicate versions are a warning (the tree legitimately carries a few during
# the russh/ssh-key rc churn), but they are surfaced so they cannot pile up
# unseen. Flip to "deny" once the tree is consolidated.
multiple-versions = "warn"
wildcards = "allow"
# No crate is outright banned yet; add entries here to hard-fail a known-bad dep.
deny = []

[sources]
unknown-registry = "deny"
unknown-git = "allow"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]

[licenses]
# Licenses are gated elsewhere; keep this permissive so `check advisories`/`bans`
# never trip on a license surprise. Left intentionally broad.
version = 2
allow = [
    "MIT", "Apache-2.0", "Apache-2.0 WITH LLVM-exception", "BSD-2-Clause",
    "BSD-3-Clause", "ISC", "Unicode-3.0", "Unicode-DFS-2016", "Zlib",
    "MPL-2.0", "CC0-1.0", "0BSD", "BSL-1.0",
]
confidence-threshold = 0.8