mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-14 19:27:04 -04:00
M0.4/M0.5: deny.toml + xtask deny in ci, GitHub CI workflow; MCP module behind a Cargo feature
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
b8fed39be5
commit
19788d3336
10 files changed
+169
-14
No files matched your search
@@ -0,0 +1,86 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: test (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Linux system dependencies (egui/winit/rfd)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
libxkbcommon-dev libwayland-dev libx11-dev libxrandr-dev libxi-dev \
|
||||
libgl1-mesa-dev libgtk-3-dev
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy, rustfmt
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Format
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --workspace --all-targets -- -D warnings
|
||||
|
||||
- name: Test
|
||||
run: cargo test --workspace
|
||||
|
||||
- name: Layering
|
||||
run: cargo xtask layers
|
||||
|
||||
- name: Assets (licences and attribution)
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo xtask assets
|
||||
|
||||
- name: CLI without the MCP server still builds
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo check -p printcraft-cli --no-default-features
|
||||
|
||||
wasm:
|
||||
name: wasm32 check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: wasm32
|
||||
- name: Check library crates for wasm32
|
||||
run: cargo xtask wasm
|
||||
|
||||
deny:
|
||||
name: dependency licences and advisories
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: EmbarkStudios/cargo-deny-action@v2
|
||||
with:
|
||||
command: check
|
||||
|
||||
# Nightly fuzzing arrives with the M1 fuzz targets (execution plan M0.5 / M1).
|
||||
Generated
+2
-2
@@ -5039,9 +5039,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78"
|
||||
checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
+9
-9
@@ -13,15 +13,15 @@ repository = "https://github.com/storytold/printcraft"
|
||||
|
||||
[workspace.dependencies]
|
||||
# internal
|
||||
printcraft-geom = { path = "crates/geom" }
|
||||
printcraft-filters = { path = "crates/filters" }
|
||||
printcraft-cos = { path = "crates/cos" }
|
||||
printcraft-crypt = { path = "crates/crypt" }
|
||||
printcraft-organize = { path = "crates/organize" }
|
||||
printcraft-render = { path = "crates/render" }
|
||||
printcraft-engine = { path = "crates/engine" }
|
||||
printcraft-ui-egui = { path = "crates/ui-egui" }
|
||||
printcraft-automation = { path = "crates/automation" }
|
||||
printcraft-geom = { path = "crates/geom", version = "0.1.0" }
|
||||
printcraft-filters = { path = "crates/filters", version = "0.1.0" }
|
||||
printcraft-cos = { path = "crates/cos", version = "0.1.0" }
|
||||
printcraft-crypt = { path = "crates/crypt", version = "0.1.0" }
|
||||
printcraft-organize = { path = "crates/organize", version = "0.1.0" }
|
||||
printcraft-render = { path = "crates/render", version = "0.1.0" }
|
||||
printcraft-engine = { path = "crates/engine", version = "0.1.0" }
|
||||
printcraft-ui-egui = { path = "crates/ui-egui", version = "0.1.0" }
|
||||
printcraft-automation = { path = "crates/automation", version = "0.1.0", default-features = false }
|
||||
|
||||
# pdf
|
||||
hayro = "0.7.1"
|
||||
|
||||
@@ -21,4 +21,4 @@ printcraft-automation = { workspace = true }
|
||||
[features]
|
||||
default = ["mcp"]
|
||||
# The opt-in MCP server (`printcraft-cli mcp`). Build with --no-default-features to leave it out.
|
||||
mcp = []
|
||||
mcp = ["printcraft-automation/mcp"]
|
||||
@@ -14,5 +14,10 @@ printcraft-render = { workspace = true }
|
||||
printcraft-organize = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
png = "0.18"
|
||||
base64 = "0.22"
|
||||
base64 = { version = "0.22", optional = true }
|
||||
|
||||
|
||||
[features]
|
||||
default = ["mcp"]
|
||||
# The MCP server module. Opt-in at run time either way; disable to leave it out of the build.
|
||||
mcp = ["dep:base64"]
|
||||
@@ -9,6 +9,7 @@
|
||||
//! with the origin at the top-left of the displayed page.
|
||||
//! - An optional root directory confines every path a tool reads or writes.
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
pub mod mcp;
|
||||
mod tools;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
use printcraft_automation::mcp::McpServer;
|
||||
use printcraft_automation::{Automation, Content, ToolError, tools};
|
||||
use serde_json::{Value, json};
|
||||
@@ -231,11 +232,13 @@ fn command_list_reports_enablement_and_tools() {
|
||||
|
||||
// ---- MCP ---------------------------------------------------------------------------------------
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
fn rpc(server: &mut McpServer, id: u64, method: &str, params: Value) -> Value {
|
||||
let line = json!({ "jsonrpc": "2.0", "id": id, "method": method, "params": params }).to_string();
|
||||
serde_json::from_str(&server.handle_line(&line).expect("a reply")).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
#[test]
|
||||
fn mcp_session_over_stdio() {
|
||||
let dir = workdir("mcp");
|
||||
@@ -268,6 +271,7 @@ fn mcp_session_over_stdio() {
|
||||
assert_eq!(&png[1..4], b"PNG");
|
||||
}
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
#[test]
|
||||
fn mcp_errors() {
|
||||
let mut s = McpServer::new(Automation::new());
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# cargo-deny policy (M0.4). Run with `cargo xtask deny`; part of `cargo xtask ci`.
|
||||
# Code dependencies follow the same rule as assets (AGENTS.md): permissive licences only.
|
||||
# Copyleft (GPL, AGPL, LGPL) is never linked; such tools run only as external oracle processes.
|
||||
|
||||
[graph]
|
||||
all-features = true
|
||||
|
||||
[licenses]
|
||||
confidence-threshold = 0.9
|
||||
allow = [
|
||||
"MIT",
|
||||
"MIT-0",
|
||||
"Apache-2.0",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
"Zlib",
|
||||
"Unicode-3.0",
|
||||
"BSL-1.0",
|
||||
"CC0-1.0",
|
||||
]
|
||||
|
||||
[licenses.private]
|
||||
ignore = true
|
||||
|
||||
[bans]
|
||||
multiple-versions = "allow"
|
||||
wildcards = "deny"
|
||||
allow-wildcard-paths = true
|
||||
|
||||
[sources]
|
||||
unknown-registry = "deny"
|
||||
unknown-git = "deny"
|
||||
|
||||
[advisories]
|
||||
yanked = "warn"
|
||||
|
||||
# egui's default UI fonts (Ubuntu-Light, Hack, emoji-icon-font): font licences on the AGENTS.md
|
||||
# §1.2 allowlist, attributed in ATTRIBUTION.toml as dependency-bundled assets.
|
||||
[[licenses.exceptions]]
|
||||
crate = "epaint_default_fonts"
|
||||
allow = ["OFL-1.1", "Ubuntu-font-1.0"]
|
||||
@@ -92,6 +92,7 @@ pub fn ci(_: &[String]) -> anyhow::Result<()> {
|
||||
("layers", Box::new(|| layers(&[]))),
|
||||
("wasm", Box::new(|| wasm(&[]))),
|
||||
("assets", Box::new(|| crate::assets::run(&[]))),
|
||||
("deny", Box::new(|| deny(&[]))),
|
||||
];
|
||||
for (i, (name, f)) in steps.iter().enumerate() {
|
||||
eprintln!("\n=== ci: {name} ===");
|
||||
@@ -104,6 +105,20 @@ pub fn ci(_: &[String]) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Dependency licences, bans, sources and advisories (`deny.toml`). Skipped with a hint when
|
||||
/// cargo-deny is not installed, except under CI (`CI` set), where it is required.
|
||||
pub fn deny(_: &[String]) -> anyhow::Result<()> {
|
||||
let installed = Command::new("cargo-deny").arg("--version").output().is_ok_and(|o| o.status.success());
|
||||
if !installed {
|
||||
if std::env::var_os("CI").is_some() {
|
||||
bail!("cargo-deny is required in CI: cargo install cargo-deny --locked");
|
||||
}
|
||||
eprintln!("deny: SKIPPED, cargo-deny is not installed (cargo install cargo-deny --locked)");
|
||||
return Ok(());
|
||||
}
|
||||
run_args(&["deny", "--log-level", "error", "check"])
|
||||
}
|
||||
|
||||
fn run_args(args: &[&str]) -> anyhow::Result<()> {
|
||||
let mut c = cargo();
|
||||
c.args(args);
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ type Command = fn(&[String]) -> anyhow::Result<()>;
|
||||
const COMMANDS: &[(&str, &str, Command)] = &[
|
||||
("layers", "Enforce the crate dependency layering (plan/architecture.md §3)", gates::layers),
|
||||
("wasm", "cargo check --target wasm32-unknown-unknown for every crate below L8", gates::wasm),
|
||||
("ci", "fmt --check, clippy -D warnings, test, layers, wasm, assets (stops at first failure)", gates::ci),
|
||||
("deny", "Dependency licences, bans, sources and advisories (deny.toml; needs cargo-deny)", gates::deny),
|
||||
("ci", "fmt --check, clippy -D warnings, test, layers, wasm, assets, deny (stops at first failure)", gates::ci),
|
||||
("assets", "Enforce the asset policy (AGENTS.md §1) against ATTRIBUTION.toml; --write regenerates ATTRIBUTION.md", assets::run),
|
||||
("corpus", "Fetch test corpora into corpus/ (git-ignored): pdf.js test PDFs", gates::corpus),
|
||||
("check", "Robustness sweep over corpus/ with printcraft-cli; fails on crashes or regressions vs xtask/baselines", gates::check),
|
||||
|
||||
Reference in new issue
Block a user