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

nordisk/holger

deny.toml

# cargo-deny policy for holger.
#
# Why this file exists: the 2026-06-14 security review recorded `cargo audit` as
# clean — 0 vulnerabilities. The 2026-09-11 review found 29, and nothing in the
# repository had noticed, because nothing in the repository ever ran either tool.
# This is the policy half of that gap; `.github/workflows/security.yml` is the
# half that runs it.
#
# Run locally:  cargo deny check
# Just the advisories:  cargo deny check advisories

[graph]
all-features = false

[advisories]
# Unsound and unmaintained advisories are warnings, not failures: holger's
# dependency graph carries several through transitive paths it does not drive,
# and failing the build on them would train people to pass `--no-deny-warnings`.
# A real vulnerability fails.
# Yanked crates in the graph are real (a yanked version can vanish from the
# registry and break a rebuild) but every one here is transitive and cannot be
# moved from this repository, so they report rather than fail.
yanked = "warn"
ignore = [
    # RUSTSEC-2023-0071 — Marvin timing side-channel in `rsa`. No fixed version
    # exists upstream. Reached only through the TLS/JWT closure's RSA key
    # operations, which holger performs on ITS OWN keys and on IdP public keys,
    # not on attacker-supplied ciphertexts, so the side channel has no oracle to
    # leak through here. Re-evaluate when rsa ships a fix.
    # Re-triaged 2026-10-30 (lane OSSF-NEXT): server-lib's `rsa` 0.9 (feature pull-apk) only MAKES
    # Holger's own APK signing key once and derives its public key; `ring` (constant time) does
    # every signature. The other copies (pgp, ssh-key, russh, cms, korp-installer) parse keys
    # and verify signatures. No rsa private-key operation runs on a request an attacker times.
    { id = "RUSTSEC-2023-0071", reason = "no upstream fix; no decryption oracle in holger's use: server-lib's rsa only makes Holger's APK key once (ring signs, constant time), the rest verify. Re-triaged 2026-10-30 (OSSF-NEXT); re-check when rsa ships a fix." },

    # quick-xml RUSTSEC-2026-0194 / -0195: CLOSED 2026-10-29 (lane QXML). znippy-plugin-maven
    # 0.10.1 is on quick-xml 0.41, and quick-xml 0.36.2 has left the lock.

    # RUSTSEC-2026-0387 — crypto-bigint timing variability in operations meant to be
    # constant-time. Crate: crypto-bigint 0.5.5, fixed only in 0.7.6+ (the 0.7.x copy in the
    # graph is already past it). The 0.5.5 copy enters ONLY through cx448 0.1.1 (X448), which
    # rpgp (`pgp` =0.21.0, the newest) needs unconditionally; holger-provenance takes pgp behind
    # its off-by-default `pgp` feature. holger uses rpgp to VERIFY Maven Central's detached
    # `.asc` signatures against pinned PUBLIC keys (verify_detached, SignedPublicKey): no
    # secret integer, no X448 key agreement, nothing for a timing side channel to leak.
    # Triaged 2026-10-28 (lane OX-CVE); re-check at every pgp bump (cx448 on crypto-bigint 0.7).
    # Re-triaged 2026-10-30 (lane OSSF-NEXT): the 0.5.5 copy ALSO enters through elliptic-curve
    # 0.13 (p256/p384/p521 0.13 under ssh-key 0.6, russh, korp-installer, znippy-common,
    # nornir-identity, nornir-auth-webauthn). Most of those verify; the secret operations on
    # it are the server's OWN P-256 keys (an identity or bundle signature, a few per change),
    # never on a request an attacker can repeat and time. The move is elliptic-curve 0.14
    # (whose copies are already in the graph) in ssh-key 0.7, russh and pgp upstream.
    { id = "RUSTSEC-2026-0387", reason = "crypto-bigint 0.5.5 (fixed only in 0.7.6) via cx448 under pgp =0.21.0 (verify only) and elliptic-curve 0.13 (p256/p384 0.13: ssh-key 0.6, russh, znippy-common, nornir-identity, webauthn; mostly verify, the server's own P-256 signatures are not attacker-timed). Triaged 2026-10-28 (OX-CVE), re-triaged 2026-10-30 (OSSF-NEXT); re-check at every ssh-key/russh/pgp bump." },

    # RUSTSEC-2024-0436 — paste is unmaintained (not a vulnerability). A proc-macro: it runs in the
    # compiler and links into no binary. It enters through image (ravif -> rav1e, exr -> pulp),
    # which only the egui dev tools pull (eframe for holger-mannequin and nornir-robotui,
    # egui_kittest); the server does not link image. Triaged 2026-10-30 (lane OSSF-NEXT);
    # re-check at every image/eframe bump (pastey is the maintained fork).
    { id = "RUSTSEC-2024-0436", reason = "paste is unmaintained (no vulnerability): a compile-time proc-macro under image (rav1e, pulp), pulled only by the egui dev tools (mannequin, robotui, egui_kittest); links into no binary. Triaged 2026-10-30 (OSSF-NEXT); re-check at every image/eframe bump." },

    # RUSTSEC-2026-0370 / -0371 / -0372 — zvariant, zbus_names and zvariant_derive are no longer
    # standalone crates (not a vulnerability): they moved into zbus 6 as its `wire` module. zbus 5
    # enters through skidbladnir-systemd (the server's systemd D-Bus client: unit state on the
    # local system bus, a trusted peer) and accesskit_unix (the egui dev tools). The move is zbus 6
    # in Skidbladnir (a sibling) and in accesskit upstream. Triaged 2026-10-30 (lane OSSF-NEXT).
    { id = "RUSTSEC-2026-0370", reason = "zvariant 5 unmaintained (merged into zbus 6, no vulnerability): zbus 5 via skidbladnir-systemd (systemd on the local system bus) and accesskit (egui dev tools). Fix = zbus 6 in Skidbladnir. Triaged 2026-10-30 (OSSF-NEXT)." },
    { id = "RUSTSEC-2026-0371", reason = "zbus_names 4 unmaintained (merged into zbus 6, no vulnerability): same path as RUSTSEC-2026-0370. Triaged 2026-10-30 (OSSF-NEXT)." },
    { id = "RUSTSEC-2026-0372", reason = "zvariant_derive 5 unmaintained (merged into zbus 6, no vulnerability): a proc-macro on the same path as RUSTSEC-2026-0370. Triaged 2026-10-30 (OSSF-NEXT)." },

    # GHSA-q54r-jf2p-rfr2 — gix 0.88.0 (fixed in 0.90.0): an untrusted repository's .git/config
    # can switch off the .git path protection of a checkout. In estate/Cargo.lock only, through
    # nornir-git 0.2.3 (edda), which only nornir-build-thing and nornir-xtask-support pull: the build
    # and CI tooling, which reads and checks out the house's own repositories (git.gunnar.rs)
    # and never a repository a stranger supplies; no Holger server links nornir-git. The gix
    # 0.90 family bump is row GIX-090. Triaged 2026-10-30 (lane OSSF-NEXT).
    { id = "GHSA-q54r-jf2p-rfr2", reason = "gix 0.88 .git-protection via untrusted .git/config: estate only, via nornir-git 0.2.3 (the edda sibling) in the build/CI tooling (nornir-build-thing, nornir-xtask-support), which only opens the house's own repositories; no Holger server links it. gix 0.90 bump = row GIX-090. Triaged 2026-10-30 (OSSF-NEXT)." },

]

[bans]
multiple-versions = "warn"
wildcards = "deny"
# A path dependency of an unpublished crate (publish = false), or a dev-dependency, never
# reaches crates.io, so it is no wildcard (cargo-deny `allow-wildcard-paths`). A published
# crate's normal path dependency still needs its version. Lane HOL-NCSC, 2026-10-31: with
# this `cargo deny --locked check` is green on main and runs in CI.
allow-wildcard-paths = true
# The reason to look at duplicates at all: two copies of a crate that carries a
# trait (arrow, egui, tonic) produce two incompatible traits and errors that read
# as nonsense. holger has been bitten by this; see server/lib/Cargo.toml's arrow
# pin and the facett/egui note in mannequin/Cargo.toml.
skip-tree = []

[licenses]
# Holger is AGPL-3.0-only plus a commercial licence (Ignalina ApS + Vetra AB), and
# so are the sibling nordisk crates it path-depends on (edda, monetize, ...).
# AGPL-3.0-only is allowed for those own crates. Any other copyleft in a
# dependency is a licensing decision, not an oversight, so it fails.
allow = [
    "AGPL-3.0-only",
    "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",
    "OpenSSL",
    # Permissive: smoltcp/managed (0BSD) and the Mozilla CA roots in
    # webpki-roots / webpki-root-certs (CDLA-Permissive-2.0).
    "0BSD",
    "CDLA-Permissive-2.0",
]
confidence-threshold = 0.9
# The pure-Rust bzip2 decoder the INGEST walk opens .bz2 / old conda archives with (HOL-NCSC
# P2, 1d43438b): libbz2-rs-sys carries the original bzip2 licence, a permissive BSD-style one.
# Allowed for that crate alone.
exceptions = [
    { allow = ["bzip2-1.0.6"], crate = "libbz2-rs-sys" },
]

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