# cargo-deny configuration for the JellyTau backend.
#
# TRACES: | DR-216
#
# Run locally with:  cd src-tauri && cargo deny check
# CI runs the same command in the `security` job of
# .gitea/workflows/build-and-test.yml. cargo-deny is baked into the builder
# image (Dockerfile.builder) -- the advisory database it fetches at run time is
# *data*, not a toolchain, so it does not conflict with the "CI installs no
# system tools" rule.
#
# Four checks run: advisories (known vulnerabilities), licenses (what we are
# allowed to ship), bans (duplicate/undesired crates) and sources (where code
# may come from).

# ---------------------------------------------------------------------------
# Graph scope
#
# Only the targets JellyTau actually ships. This is not a performance tweak --
# it changes which advisories are *real*. Without it the graph includes Apple
# targets, which drag in `plist` -> `quick-xml`, and two quick-xml DoS
# advisories (RUSTSEC-2026-0194/0195) get reported against a crate that is not
# compiled into anything we release. Ignoring them by ID would have been the
# wrong fix: it silences the finding everywhere, including on a target where it
# would matter. Scoping the graph makes the finding correctly absent instead.
#
# Add a target here the day we ship it, and expect new findings with it.
[graph]
targets = [
    "x86_64-unknown-linux-gnu",
    "x86_64-pc-windows-msvc",
    "aarch64-linux-android",
    "armv7-linux-androideabi",
    "x86_64-linux-android",
]
all-features = true

[advisories]
# Vulnerabilities and unsoundness are hard errors -- there is deliberately no
# switch here turning them into warnings. Everything below is an explicit,
# justified exception with a named ID; a new advisory fails the build until
# somebody decides what to do about it.
#
# Yanked crates in the lockfile are an error too: a yank usually means the
# author withdrew that exact version for a reason.
yanked = "deny"

ignore = [
    # ---------------------------------------------------------------------
    # GTK3 bindings: unmaintained, and not ours to replace.
    #
    # Tauri v2's Linux backend is WebKitGTK, which is GTK3. The gtk-rs project
    # has stopped maintaining its GTK3 bindings in favour of GTK4, but Tauri
    # cannot move until WebKitGTK does. These arrive through
    # tauri -> tauri-runtime-wry -> wry -> gtk, with no version of any of them
    # that avoids it ("No safe upgrade is available", per cargo-deny).
    #
    # Unmaintained != vulnerable: no advisory here describes an exploitable
    # defect. Revisit when Tauri ships a GTK4/WebKitGTK-6 backend.
    { id = "RUSTSEC-2024-0411", reason = "gdkwayland-sys: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0412", reason = "gdk: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0413", reason = "atk: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0414", reason = "gdkx11-sys: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0415", reason = "gtk: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0416", reason = "atk-sys: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0417", reason = "gdkx11: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0418", reason = "gdk-sys: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0419", reason = "gtk3-macros: GTK3 binding, pulled in by Tauri's Linux backend" },
    { id = "RUSTSEC-2024-0420", reason = "gtk-sys: GTK3 binding, pulled in by Tauri's Linux backend" },

    # ---------------------------------------------------------------------
    # Unmaintained transitive build-time crates. All are proc-macro or
    # lookup-table dependencies of Tauri's own toolchain; none has a safe
    # upgrade and none is a vulnerability.
    { id = "RUSTSEC-2024-0370", reason = "proc-macro-error: unmaintained proc-macro helper, transitive" },
    { id = "RUSTSEC-2024-0436", reason = "paste: unmaintained macro helper, transitive" },
    { id = "RUSTSEC-2025-0057", reason = "fxhash: unmaintained hasher, transitive" },

    # unic-* reach us via urlpattern -> tauri-utils. Unicode table crates,
    # superseded upstream but with no drop-in replacement at this depth.
    { id = "RUSTSEC-2025-0075", reason = "unic-char-range: unmaintained, via urlpattern -> tauri-utils" },
    { id = "RUSTSEC-2025-0080", reason = "unic-common: unmaintained, via urlpattern -> tauri-utils" },
    { id = "RUSTSEC-2025-0081", reason = "unic-char-property: unmaintained, via urlpattern -> tauri-utils" },
    { id = "RUSTSEC-2025-0098", reason = "unic-ucd-version: unmaintained, via urlpattern -> tauri-utils" },
    { id = "RUSTSEC-2025-0100", reason = "unic-ucd-ident: unmaintained, via urlpattern -> tauri-utils" },
]

# ---------------------------------------------------------------------------
# Licenses
#
# JellyTau ships as MIT (see ../LICENSE) in deb/rpm/AppImage/NSIS/APK bundles,
# so every crate compiled into those has to be redistributable under terms
# compatible with that. The list is an allow-list on purpose: a new crate with
# an unlisted licence fails the build and gets a decision, rather than being
# shipped because nobody looked.
[licenses]
# A crate offering a choice ("MIT OR Apache-2.0") is satisfied by any allowed
# arm. 0.8 means we accept a licence-file match at >=80% textual confidence.
confidence-threshold = 0.8

allow = [
    # Permissive, no redistribution conditions beyond attribution.
    "MIT",
    "MIT-0",
    "Apache-2.0",
    "Apache-2.0 WITH LLVM-exception",
    "BSD-2-Clause",
    "BSD-3-Clause",
    "ISC",
    "Zlib",
    "0BSD",
    "CC0-1.0",
    "Unlicense",
    "BSL-1.0",
    # Unicode data tables (the icu_* family). Permissive, attribution only.
    "Unicode-3.0",
    # webpki-roots: the Mozilla CA bundle, published as data under CDLA.
    "CDLA-Permissive-2.0",

    # MPL-2.0 -- weak, *file-level* copyleft (cssparser, selectors, dtoa-short,
    # option-ext). The obligation attaches to modified MPL files, not to the
    # program that links them, so shipping them unmodified inside an MIT
    # application is fine. If we ever patch one of these crates, that patch must
    # be published.
    "MPL-2.0",

    # LGPL-2.1 -- `libmpv` and `libmpv-sys` only, and this one is deliberate.
    #
    # These are bindings to libmpv, which is itself LGPL-2.1+; the binding
    # crates inherit the licence. LGPL permits use from a differently-licensed
    # application provided the user can substitute their own build of the
    # library, which dynamic linking satisfies -- libmpv-sys links the *system*
    # shared object (the builder image installs libmpv-dev; the deb/rpm declare
    # a runtime dependency) rather than statically embedding it.
    #
    # 🔴 Two obligations follow, and they are ours, not cargo-deny's:
    #   - keep the linkage dynamic (do not switch libmpv-sys to a vendored
    #     static build without revisiting this),
    #   - ship libmpv's licence text with any bundle that carries the .so,
    #     which currently means the AppImage.
    "LGPL-2.1",
]

# Crates whose licence field is missing or unparseable get a per-crate
# clarification here rather than a blanket relaxation. Empty today.
exceptions = []

[bans]
# Duplicate versions are noise, not danger: a Tauri-sized graph legitimately
# carries several `windows-sys` and `bitflags` majors because its dependencies
# upgrade at different rates. Warn so the count stays visible; do not fail.
multiple-versions = "warn"
# The only wildcard in the graph is the `libmpv` git dependency: a git dep
# carries no semver requirement, so cargo-deny counts it as `*` no matter how it
# is pinned. It is pinned by `rev` in Cargo.toml and by hash in Cargo.lock, and
# `[sources].allow-git` below is the check that actually constrains it -- so
# "deny" here would fail the build forever over something already controlled
# twice. Warn, so a *second* wildcard still shows up.
wildcards = "warn"
# `cargo build` order for equal-priority features; keeps the check deterministic.
highlight = "all"

deny = []
skip = []

[sources]
# Anything not from crates.io needs to be named here. This is the check that
# would notice a dependency being repointed at somebody's fork.
unknown-registry = "deny"
unknown-git = "deny"

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

# The one git dependency. Cargo.toml pins it by branch, not by revision, which
# is worth knowing: the `master` it resolves to is whatever the lockfile has
# recorded, and `cargo update` will move it. It exists because the crates.io
# release of libmpv predates the MPV versions we support.
allow-git = ["https://github.com/ParadoxSpiral/libmpv-rs.git"]
