Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# Base dependency policy of the constellation (decision Y43, 2026-10-09).
# Every Rust repository of libre-ai carries this file unchanged and executes it
# with cargo-deny from its required check. The licence allowlist is the inbound
# policy of ADR-0042 §4 and §11; GPL (linked), AGPL and SSPL are refused by
# omission.
# Base dependency policy of the constellation (decisions Y43-Y46, 2026-10-09).
# Every Rust repository of libre-ai carries this file unchanged and executes
# `bans`, `licenses` and `sources` with cargo-deny from its required check.
# The licence allowlist is the inbound policy of ADR-0042 §4 and §11; GPL
# (linked), AGPL and SSPL are refused by omission.
#
# `[advisories]` is NOT part of the required verdict (I-26, Y44): an advisory
# verdict depends on the RustSec database of the day, so a fleet advisory
# control notifies without blocking. The section is kept for that control and
# for manual runs (`cargo deny check advisories`), which also apply
# `yanked = "deny"`.
#
# `[sources.allow-org] github = ["libre-ai"]` bounds git-dep trust to the
# organisation (ADR-0020 §2.5). `allow-wildcard-paths` admits the version-less
Expand All @@ -17,7 +23,7 @@ all-features = true
yanked = "deny"

[licenses]
confidence-threshold = 0.8
confidence-threshold = 0.9
unused-allowed-license = "allow"
# The allowlist governs inbound dependencies only: the workspace's own private
# crates carry the outbound licences of the repository (REUSE.toml), which
Expand All @@ -28,6 +34,9 @@ allow = [
"MIT",
"MIT-0",
"Apache-2.0",
# Apache-2.0 plus an additional permission (ADR-0042 §11, Y45); carried by
# `ar_archive_writer`, a build dependency of `psm` through `sqlparser`.
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
Expand Down
7 changes: 7 additions & 0 deletions tools/quality/check-dependency-policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ import {
countLockedPackages,
main,
parseArguments,
REQUIRED_CHECKS,
sha256Of,
verifyDigest,
} from "./check-dependency-policy";

describe("REQUIRED_CHECKS", () => {
test("keeps the calendar-dependent advisory verdict out of the required check (I-26)", () => {
expect([...REQUIRED_CHECKS]).toEqual(["bans", "licenses", "sources"]);
});
});

describe("archiveFor", () => {
test("pins the CI runner archive to the fleet template digest", () => {
const archive = archiveFor("linux", "x64");
Expand Down
25 changes: 12 additions & 13 deletions tools/quality/check-dependency-policy.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// SPDX-FileCopyrightText: 2026 Libre AI contributors
// SPDX-License-Identifier: EUPL-1.2
//
// Dependency policy gate (decision Y43, 2026-10-09): executes this
// Dependency policy gate (decisions Y43 and Y44, 2026-10-09): executes this
// repository's own `deny.toml` against its committed Cargo graph(s) with
// cargo-deny — advisories, bans, licenses and sources — from the required
// check.
// cargo-deny — bans, licenses and sources — from the required check.
//
// Why the binary is fetched here rather than taken from PATH: the required
// check runs inside the source composition, whose runner installs Bun, Node
Expand All @@ -16,11 +15,11 @@
// `reusable-dependency-policy.yml`). The cached archive is re-hashed on every
// run, so the cache is never trusted beyond its digest.
//
// Why advisories block here although the fleet template only reports them:
// Y43 makes advisories part of the required verdict. The verdict therefore
// depends on the RustSec database of the day; an accepted risk is recorded as
// a dated waiver in `deny.toml` under docs/security/ADVISORY-WAIVER-POLICY.md
// (project-governance), never as a silent exception.
// Why advisories are not checked here (I-26, Y44): bans, licenses and sources
// are a pure function of the committed Cargo.lock and deny.toml, so their
// verdict is reproducible at constant commit, which is what a required check
// may assert. An advisory verdict depends on the RustSec database fetched at
// run time; a fleet advisory control notifies on it without blocking.

import { spawnSync } from "node:child_process";
import { createHash } from "node:crypto";
Expand All @@ -38,6 +37,9 @@ import { dirname, isAbsolute, join, resolve } from "node:path";

export const CARGO_DENY_VERSION = "0.19.5";

/** The checks whose verdict is a function of the tree alone (I-26): no `advisories`. */
export const REQUIRED_CHECKS = ["bans", "licenses", "sources"] as const;

export interface CargoDenyArchive {
readonly triple: string;
readonly url: string;
Expand Down Expand Up @@ -213,10 +215,7 @@ export async function main(argv: readonly string[]): Promise<number> {
"--config",
config,
"--show-stats",
"advisories",
"bans",
"licenses",
"sources",
...REQUIRED_CHECKS,
],
root,
);
Expand All @@ -229,7 +228,7 @@ export async function main(argv: readonly string[]): Promise<number> {
rmSync(scratch, { recursive: true, force: true });
}
console.log(
`Dependency policy verified: advisories, bans, licenses and sources hold for ` +
`Dependency policy verified: ${REQUIRED_CHECKS.join(", ")} hold for ` +
`${manifests.length} manifest(s), ${lockedPackages} locked package(s) inspected ` +
`(cargo-deny ${CARGO_DENY_VERSION}, archive sha256 ${archive.sha256}).`,
);
Expand Down