# 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