Gunnar

nordisk/gunnar-ui

deny.toml

# cargo-deny configuration for gunnar-UI — the console's half of the "0 known
# CVE" gate.
#
# gunnar itself has had this gate since 2026-08-31 (`nordisk/gunnar`'s own
# `deny.toml` plus `xtask/src/cve.rs`), and the console did not. That asymmetry
# is the finding: the two halves ship together, the console is the half that
# faces the public internet, and nothing in `.github/workflows/ci.yml` looked at
# a single advisory. This file is gunnar's policy, restated for this tree rather
# than copied wholesale — the ignores below are this tree's, triaged here.
#
# CI runs, on this workspace's own resolved `Cargo.lock`:
#
#     cargo deny --workspace check advisories bans sources
#
# Every `ignore` is a dated decision with a reachability argument, never a
# blanket mute. A NEW advisory or a NEW yanked crate fails the job by name.

[advisories]
version = 2
# A yanked crate is not a CVE, but the gate treats it as a hard stop so it
# cannot rot in silently.
yanked = "deny"
# **Unmaintained is checked on what this workspace DECLARES, not on the whole
# closure.** Six crates in this tree are unmaintained today — `bincode`,
# `paste`, `proc-macro-error2`, `rustybuzz`, `ttf-parser`, `yaml-rust` — and
# every one arrives several levels down through typst's font and document
# stack. "Somebody stopped maintaining a crate under a dependency of a
# dependency" is hygiene with no action attached: there is no version to move to
# and no code here to change. Made a hard stop it is six permanent reds, which
# teaches a reader to skip this job's output — and that is how a real advisory
# gets missed. Vulnerabilities are still checked over the WHOLE tree; those are
# the ones with an action attached.
unmaintained = "workspace"
ignore = [
    # -----------------------------------------------------------------------
    # RUSTSEC-2026-0194 — quick-xml, quadratic run time on duplicate attribute
    #                     names in a start tag.
    # RUSTSEC-2026-0195 — quick-xml, unbounded namespace-declaration allocation
    #                     in `NsReader` (memory exhaustion).
    # Crate: quick-xml 0.38.4, fixed in >= 0.41.0 — which this tree cannot take:
    #   citationberg 0.6.1 pins ^0.38, and the chain is
    #   citationberg -> hayagriva -> typst-library -> typst -> nornir-docbook
    #   -> gunnar-ui-server. (0.41.0 is in the lock as well, for another
    #   consumer, so this is a pin and not a missing update.)
    # Triaged 2026-09-11 (this review):
    #   Both are denial of service against an XML PARSE, and the only XML
    #   quick-xml sees on this path is a CSL citation style — hayagriva's
    #   bibliography support, reached from typst's `bibliography` function. The
    #   console's use of typst is `readme::`, typesetting a repository's README,
    #   and that module names no bibliography, no `.csl` and no `.bib`: a README
    #   cannot introduce one, because it is converted from markdown by code in
    #   this repository. No attacker-controlled bytes reach quick-xml. Revisit
    #   if the README pipeline gains typst's bibliography, or if citationberg
    #   widens its pin.
    { id = "RUSTSEC-2026-0194", reason = "quick-xml 0.38.4 is pinned by citationberg under typst; it parses CSL styles only, and the console's typst use (readme::) names no bibliography or style file, so no attacker bytes reach it. No upgrade exists within the pin. Triaged 2026-09-11." },
    { id = "RUSTSEC-2026-0195", reason = "quick-xml 0.38.4 is pinned by citationberg under typst; it parses CSL styles only, and the console's typst use (readme::) names no bibliography or style file, so no attacker bytes reach it. No upgrade exists within the pin. Triaged 2026-09-11." },

    # -----------------------------------------------------------------------
    # RUSTSEC-2023-0071 — Marvin Attack, RSA private-key timing side channel.
    # Crate: rsa 0.10.0-rc.18. No safe upstream version exists.
    # Triaged 2026-10-28 (lane OX-CVE), as gunnar's deny.toml (2026-08-31):
    #   rsa enters ONLY through russh's default `rsa` feature in edda's
    #   nornir-git (the build thing's git, the xtask tooling) and ssh-key's
    #   rsa module in that graph. gunnar-ui-server builds its own ssh-key with
    #   ed25519 only (Cargo.toml: features ed25519/std/rand_core) and mints and
    #   signs with ed25519 keys; no RSA private-key operation runs on any path
    #   an attacker can time. Drop with the russh rsa feature change in
    #   nornir-git (the same decision gunnar tracks).
    { id = "RUSTSEC-2023-0071", reason = "rsa has no fix: only via russh's default rsa feature (edda nornir-git) and ssh-key in that graph; gunnar-ui-server's ssh-key is ed25519-only and its keys are ed25519, so no RSA private-key op on an attacker-observable path. Triaged 2026-10-28 (as gunnar 2026-08-31)." },
]

[bans]
# Surfaced rather than fatal: the tree legitimately carries a few duplicates
# through the tonic/axum churn, and a warning keeps them visible without
# failing a job for something nobody can act on today.
multiple-versions = "warn"
wildcards = "allow"
deny = []

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

[licenses]
# Licences are not what this gate is for; kept broad on purpose so a licence
# surprise never masquerades as a security failure.
version = 2
allow = [
    "MIT",
    "Apache-2.0",
    "Apache-2.0 WITH LLVM-exception",
    "BSD-2-Clause",
    "BSD-3-Clause",
    "ISC",
    "MPL-2.0",
    "Unicode-3.0",
    "Unicode-DFS-2016",
    "Zlib",
    "CC0-1.0",
    "OpenSSL",
    "BSL-1.0",
]
confidence-threshold = 0.8