From f004a6e6e463c6789129883e78a765f584ec660b Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Sun, 1 Nov 2026 12:12:09 +0200 Subject: [PATCH 1/5] build: qualify the package and dependency licences - Run every test of the packaged crate from its unpacked archive, with the oracle and a disposable token, through a new hardening phase. - Keep test files that read sibling packages out of the package; they run in the workspace. Drop the include entry that had no effect. - Check licences on the production and fuzz graphs against an explicit allow-list, and declare the fuzz crate's licence. Closes #354 --- .github/workflows/ci.yml | 2 + Cargo.toml | 6 +- deny.toml | 14 +++++ docs/ci-hardening.md | 17 ++++- fuzz/Cargo.toml | 1 + tools/xml-sec-tools/src/hardening.rs | 72 +++++++++++++++++++++- tools/xml-sec-tools/src/hardening/tests.rs | 64 ++++++++++++++++++- 7 files changed, 167 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19312c9c..8859d9f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,6 +100,8 @@ jobs: echo "OPENSSL_BIN=$XMLSEC1_PREFIX/bin/openssl" >> "$GITHUB_ENV" - name: Execute every workspace target and enforce canonical coverage run: cargo run --quiet -p xml-sec-tools -- hardening coverage "$RUNNER_TEMP/coverage" + - name: Build the packaged crate and run every test from its archive + run: cargo run --quiet -p xml-sec-tools -- hardening package "$RUNNER_TEMP/package" - uses: actions/upload-artifact@v7 if: always() with: diff --git a/Cargo.toml b/Cargo.toml index 410051f0..5fdac9ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,11 @@ include = [ "/benchmarks/dashboard/**", "/benchmarks/Dockerfile", "/tests/**", - "/tools/xmlsec1/**", + # These read files of sibling packages, which Cargo never packages; they run + # in the workspace. + "!/tests/capability_ledger.rs", + "!/tests/donor_negative_vectors.rs", + "!/tests/opc_relationship_transform.rs", "/compatibility/**", "/scripts/**", ] diff --git a/deny.toml b/deny.toml index ab6c4b40..2018b434 100644 --- a/deny.toml +++ b/deny.toml @@ -2,6 +2,20 @@ yanked = "deny" ignore = [] +[licenses] +# One list serves the production and fuzz graphs, which use different licences. +unused-allowed-license = "allow" +allow = [ + "Apache-2.0", + "BSD-3-Clause", + "ISC", + "MIT", + "NCSA", + "OpenSSL", + "Unicode-3.0", + "Zlib", +] + [sources] unknown-registry = "deny" unknown-git = "deny" diff --git a/docs/ci-hardening.md b/docs/ci-hardening.md index b028cb68..8ff4b809 100644 --- a/docs/ci-hardening.md +++ b/docs/ci-hardening.md @@ -42,14 +42,27 @@ cargo nextest run -p xml-sec-tools cargo-deny 0.19.0 checks both the production and fuzz graphs, including optional features and development dependencies. Vulnerable, unsound and notice advisories fail under the tool's policy; yanked crates and unapproved git/registry sources -are refused. There is no blanket ignore list. Refresh an ignored local lockfile -when it retains a yanked dependency; do not weaken the gate to accept that lock. +are refused. Every crate must satisfy the licence allow-list in `deny.toml`. +There is no blanket ignore list. Refresh an ignored local lockfile when it +retains a yanked dependency; do not weaken the gate to accept that lock. The native safety gate lints all workspace library targets with unsafe-code refusal. Test/benchmark diagnostic allocator probes are not product library permission to use unsafe. Native dependencies retain their separate upstream safety and FIPS/module boundaries; this check is not an audit of external code. +## Packaged Crate + +```sh +PKCS11_MODULE=/path/to/libsofthsm2.so \ + cargo run -p xml-sec-tools -- hardening package /new/directory/outside/the/repository +``` + +The phase packages `xml-sec` with all features and runs every test target from +the unpacked archive, with the xmlsec1 oracle and a disposable token. A test that +reads a file of a sibling package cannot pass there, so it stays out of the +package through `include` in the root manifest and runs in the workspace. + ## Pedantic Lint `clippy::pedantic` is part of the workspace lint table in the root diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 067dee5f..bff75450 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "xml-sec-fuzz" version = "0.0.0" +license = "Apache-2.0 AND MIT" publish = false edition = "2024" diff --git a/tools/xml-sec-tools/src/hardening.rs b/tools/xml-sec-tools/src/hardening.rs index 718cd269..3865d939 100644 --- a/tools/xml-sec-tools/src/hardening.rs +++ b/tools/xml-sec-tools/src/hardening.rs @@ -1,6 +1,7 @@ -//! `hardening [all|dependencies|safety|coverage] [EVIDENCE_DIR]`: dependency -//! policy, native safety and canonical line coverage. Coverage evidence is -//! kept outside build output. +//! `hardening [all|dependencies|safety|coverage|package] [DIR]`: dependency +//! policy, native safety, canonical line coverage and the packaged crate's own +//! tests. `DIR` receives the evidence or the package build and lies outside the +//! repository, because a package unpacked inside it would join its workspace. use crate::repo::{Failure, Run, Step, System, require}; use serde_json::Value; @@ -30,6 +31,8 @@ pub(crate) enum Action { ShowEnv(Step), /// The token-backed workspace tests under the instrumented build. TokenTests(Vec), + /// Every test of the unpacked package, token-backed ones included. + PackagedTests, /// Validates the JSON coverage report. CheckReport, /// A process whose stdout becomes the named evidence file. @@ -74,6 +77,24 @@ pub(crate) fn plan(phase: &str, coverage: Option<&Coverage>) -> Result (true, false, false), "safety" => (false, true, false), "coverage" => (false, false, true), + "package" => { + let inputs = coverage.ok_or("pass a package build directory and PKCS11_MODULE")?; + let target = inputs.evidence.display().to_string(); + return Ok(vec![ + Action::Run(cargo( + "package", + &[ + "package", + "-p", + "xml-sec", + "--all-features", + "--target-dir", + &target, + ], + )), + Action::PackagedTests, + ]); + } _ => { return Err(Failure { code: 2, @@ -93,6 +114,7 @@ pub(crate) fn plan(phase: &str, coverage: Option<&Coverage>) -> Result) -> Result Result<(), String>; fn check_report(&mut self, path: &Path) -> Result; fn write(&mut self, path: &Path, text: &str) -> Result<(), String>; + fn unpacked(&mut self, target: &Path) -> Result; +} + +/// The directory `cargo package` unpacked under `target`; the name holds the +/// version, and a second match means a stale build rather than this package. +pub(crate) fn unpacked_package(target: &Path) -> Result { + let root = target.join("package"); + let entries = + std::fs::read_dir(&root).map_err(|error| format!("read {}: {error}", root.display()))?; + let mut found = Vec::new(); + for entry in entries { + let path = entry + .map_err(|error| format!("read {}: {error}", root.display()))? + .path(); + if path.is_dir() { + found.push(path); + } + } + match found.as_slice() { + [package] => Ok(package.clone()), + _ => Err(format!( + "expected one unpacked package in {}, found {}", + root.display(), + found.len() + )), + } } impl Runner for System { @@ -257,6 +306,10 @@ impl Runner for System { fn write(&mut self, path: &Path, text: &str) -> Result<(), String> { std::fs::write(path, text).map_err(|error| format!("write {}: {error}", path.display())) } + + fn unpacked(&mut self, target: &Path) -> Result { + unpacked_package(target) + } } /// `step` with the environment accumulated by earlier actions. @@ -288,6 +341,19 @@ pub(crate) fn execute( env.extend(parse_env(&listing)?); } Action::TokenTests(args) => runner.token_tests(&measured()?.module, args, &env)?, + Action::PackagedTests => { + let inputs = measured()?; + let manifest = runner.unpacked(&inputs.evidence)?.join("Cargo.toml"); + let args = [ + "--workspace".into(), + "--manifest-path".into(), + manifest.display().to_string(), + "--all-features".into(), + "--target-dir".into(), + inputs.evidence.display().to_string(), + ]; + runner.token_tests(&inputs.module, &args, &env)?; + } Action::CheckReport => { let summary = runner.check_report(&measured()?.evidence.join("coverage.json"))?; println!("{summary}"); diff --git a/tools/xml-sec-tools/src/hardening/tests.rs b/tools/xml-sec-tools/src/hardening/tests.rs index 9f9e8faa..f95f52d4 100644 --- a/tools/xml-sec-tools/src/hardening/tests.rs +++ b/tools/xml-sec-tools/src/hardening/tests.rs @@ -1,4 +1,4 @@ -use super::{Action, Coverage, Runner, execute, parse_env, plan, remapped_flags}; +use super::{Action, Coverage, Runner, execute, parse_env, plan, remapped_flags, unpacked_package}; use crate::repo::{Failure, Run, Step, require}; use serde_json::{Value, json}; use std::os::unix::process::ExitStatusExt as _; @@ -77,6 +77,10 @@ impl Runner for Recorder { self.calls.push(format!("write {}", path.display())); Ok(()) } + + fn unpacked(&mut self, target: &Path) -> Result { + Ok(target.join("package/xml-sec-1.2.3")) + } } fn index(calls: &[String], prefix: &str) -> usize { @@ -96,8 +100,8 @@ fn the_runner_preserves_every_source_and_delegates_the_85_percent_gate_to_llvm() execute(&actions, Some(&coverage), &mut recorder).unwrap(); let calls = &recorder.calls; for expected in [ - "cargo deny --all-features check --config deny.toml advisories sources", - "cargo deny --manifest-path fuzz/Cargo.toml", + "cargo deny --all-features check --config deny.toml advisories sources licenses", + "cargo deny --manifest-path fuzz/Cargo.toml --all-features check --config deny.toml advisories sources licenses", "cargo clippy --workspace --lib --all-features -- -D warnings -D unsafe_code", "tokens /test/module --workspace --all-features", "cargo llvm-cov report --package * --fail-under-lines 85", @@ -143,6 +147,60 @@ fn the_runner_preserves_every_source_and_delegates_the_85_percent_gate_to_llvm() assert!(remapped_flags(Some(""), Some("-A b"), Path::new("/repo")).starts_with("-A\x1fb\x1f")); } +#[test] +fn the_package_phase_tests_the_archive_rather_than_the_workspace() { + // Workspace tests cannot notice a target that needs a file outside the + // archive, so the tests must run from the unpacked package. + let inputs = coverage(""); + let actions = plan("package", Some(&inputs)).unwrap(); + let mut recorder = Recorder::default(); + execute(&actions, Some(&inputs), &mut recorder).unwrap(); + assert_eq!( + recorder.calls, + [ + "cargo package -p xml-sec --all-features --target-dir /evidence", + "tokens /test/module --workspace --manifest-path /evidence/package/xml-sec-1.2.3/Cargo.toml --all-features --target-dir /evidence", + ] + ); +} + +#[test] +fn the_package_phase_refuses_a_missing_directory_and_stops_on_failure() { + // A failed package must not fall through to tests of an older unpacked copy. + assert!(plan("package", None).is_err()); + let inputs = coverage(""); + let actions = plan("package", Some(&inputs)).unwrap(); + let mut recorder = Recorder { + fail: Some("cargo package"), + ..Recorder::default() + }; + assert_eq!( + execute(&actions, Some(&inputs), &mut recorder) + .unwrap_err() + .code, + 37 + ); + assert_eq!(recorder.calls.len(), 1); +} + +#[test] +fn unpacked_package_is_the_single_directory_named_for_the_crate() { + // The compressed archive beside the directory shares its name prefix. + let root = tempfile::tempdir().unwrap(); + assert!(unpacked_package(root.path()).is_err()); + let package = root.path().join("package"); + std::fs::create_dir(&package).unwrap(); + std::fs::write(package.join("xml-sec-1.2.3.crate"), "").unwrap(); + assert!(unpacked_package(root.path()).is_err()); + std::fs::create_dir(package.join("xml-sec-1.2.3")).unwrap(); + assert_eq!( + unpacked_package(root.path()).unwrap(), + package.join("xml-sec-1.2.3") + ); + std::fs::create_dir(package.join("xml-sec-1.2.2")).unwrap(); + assert!(unpacked_package(root.path()).is_err()); +} + #[test] fn every_failed_gate_stops_qualification_with_the_original_exit_status() { // A report or later command must never mask setup, safety or test failure. From 9cd99235479064c71fe3caa24facfd8441948eb0 Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Sun, 1 Nov 2026 12:13:44 +0200 Subject: [PATCH 2/5] fix(tooling): select the crate among package directories --- tools/xml-sec-tools/src/hardening.rs | 5 ++++- tools/xml-sec-tools/src/hardening/tests.rs | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/xml-sec-tools/src/hardening.rs b/tools/xml-sec-tools/src/hardening.rs index 3865d939..2389f8e7 100644 --- a/tools/xml-sec-tools/src/hardening.rs +++ b/tools/xml-sec-tools/src/hardening.rs @@ -271,7 +271,10 @@ pub(crate) fn unpacked_package(target: &Path) -> Result { let path = entry .map_err(|error| format!("read {}: {error}", root.display()))? .path(); - if path.is_dir() { + let named = path + .file_name() + .is_some_and(|name| name.to_string_lossy().starts_with("xml-sec-")); + if named && path.is_dir() { found.push(path); } } diff --git a/tools/xml-sec-tools/src/hardening/tests.rs b/tools/xml-sec-tools/src/hardening/tests.rs index f95f52d4..8c90fd48 100644 --- a/tools/xml-sec-tools/src/hardening/tests.rs +++ b/tools/xml-sec-tools/src/hardening/tests.rs @@ -193,6 +193,8 @@ fn unpacked_package_is_the_single_directory_named_for_the_crate() { std::fs::write(package.join("xml-sec-1.2.3.crate"), "").unwrap(); assert!(unpacked_package(root.path()).is_err()); std::fs::create_dir(package.join("xml-sec-1.2.3")).unwrap(); + // `cargo package` keeps its own scratch registry beside the unpacked crate. + std::fs::create_dir(package.join("tmp-registry")).unwrap(); assert_eq!( unpacked_package(root.path()).unwrap(), package.join("xml-sec-1.2.3") From 496a5fbeae73beab8b7bc7d6fe43a6f0cfab55d0 Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Sun, 1 Nov 2026 12:22:21 +0200 Subject: [PATCH 3/5] build: keep donor-dependent interop tests out of the package --- Cargo.toml | 5 +++-- docs/ci-hardening.md | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5fdac9ff..497045f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,12 @@ include = [ "/benchmarks/dashboard/**", "/benchmarks/Dockerfile", "/tests/**", - # These read files of sibling packages, which Cargo never packages; they run - # in the workspace. + # These read sibling packages, which Cargo never packages, or the donor + # checkout; they run in the workspace. "!/tests/capability_ledger.rs", "!/tests/donor_negative_vectors.rs", "!/tests/opc_relationship_transform.rs", + "!/tests/xmlsec1_interop.rs", "/compatibility/**", "/scripts/**", ] diff --git a/docs/ci-hardening.md b/docs/ci-hardening.md index 8ff4b809..44604400 100644 --- a/docs/ci-hardening.md +++ b/docs/ci-hardening.md @@ -60,8 +60,8 @@ PKCS11_MODULE=/path/to/libsofthsm2.so \ The phase packages `xml-sec` with all features and runs every test target from the unpacked archive, with the xmlsec1 oracle and a disposable token. A test that -reads a file of a sibling package cannot pass there, so it stays out of the -package through `include` in the root manifest and runs in the workspace. +reads a sibling package or the donor checkout cannot pass there, so it stays out +of the package through `include` in the root manifest and runs in the workspace. ## Pedantic Lint From 1c845e98a3dbfaf3477d12a922960804dd38c90f Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Sun, 1 Nov 2026 12:52:19 +0200 Subject: [PATCH 4/5] build: package the oracle interop tests and license tooling --- Cargo.toml | 7 ++- tests/xmlsec1_donor_interop.rs | 69 ++++++++++++++++++++++++++++++ tests/xmlsec1_interop.rs | 62 +-------------------------- tools/capability-ledger/Cargo.toml | 1 + tools/xml-sec-tools/Cargo.toml | 1 + 5 files changed, 78 insertions(+), 62 deletions(-) create mode 100644 tests/xmlsec1_donor_interop.rs diff --git a/Cargo.toml b/Cargo.toml index 497045f0..df295e75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ include = [ "!/tests/capability_ledger.rs", "!/tests/donor_negative_vectors.rs", "!/tests/opc_relationship_transform.rs", - "!/tests/xmlsec1_interop.rs", + "!/tests/xmlsec1_donor_interop.rs", "/compatibility/**", "/scripts/**", ] @@ -227,6 +227,11 @@ name = "xmlsec1_interop" path = "tests/xmlsec1_interop.rs" required-features = ["xmldsig-sign", "c14n"] +[[test]] +name = "xmlsec1_donor_interop" +path = "tests/xmlsec1_donor_interop.rs" +required-features = ["xmldsig-sign", "c14n"] + [[test]] name = "signing_digest" required-features = ["xmldsig-sign", "c14n"] diff --git a/tests/xmlsec1_donor_interop.rs b/tests/xmlsec1_donor_interop.rs new file mode 100644 index 00000000..0c43a67a --- /dev/null +++ b/tests/xmlsec1_donor_interop.rs @@ -0,0 +1,69 @@ +//! Interoperability checks that read the donor checkout, which is not packaged. + +use std::fs; +use std::path::Path; + +#[path = "common/xmlsec1.rs"] +mod xmlsec1; + +use xml_sec::policy::{EcdsaSignatureValueEncoding, VerificationPolicy}; +use xml_sec::xmldsig::{DsigStatus, SignatureAlgorithm, VerificationKey, VerifyContext}; + +#[test] +fn asn1_ecdsa_compatibility_matches_pinned_xmlsec1() { + // The upstream vector is intentionally invalid under XMLDSig framing and + // valid only when both implementations select libxmlsec1's ASN.1 mode. + if !xmlsec1::is_available() { + eprintln!("{}", xmlsec1::skip_reason()); + return; + } + let fixture = Path::new( + "donors/xmlsec/tests/aleksey-xmldsig-01/enveloped-sha256-ecdsa-sha256-with-asn1.xml", + ); + let public_key = Path::new("donors/xmlsec/tests/keys/ec/ec-prime256v1-pubkey.pem"); + let donor_key_option = "--pubkey-pem:TestKeyName-ec-prime256v1"; + + let donor_default = xmlsec1::command() + .args(["--verify", donor_key_option]) + .arg(public_key) + .arg(fixture) + .output() + .expect("pinned xmlsec1 must run"); + assert!(!donor_default.status.success()); + let donor_compatible = xmlsec1::command() + .args([ + "--verify", + "--enable-asn1-signatures-hack", + donor_key_option, + ]) + .arg(public_key) + .arg(fixture) + .output() + .expect("pinned xmlsec1 must run"); + assert!( + donor_compatible.status.success(), + "{}", + String::from_utf8_lossy(&donor_compatible.stderr) + ); + + let xml = fs::read_to_string(fixture).expect("upstream ASN.1 fixture must load"); + let (_, pem) = x509_parser::pem::parse_x509_pem(&fs::read(public_key).unwrap()) + .expect("upstream EC public key must parse"); + let key = VerificationKey { + algorithm: SignatureAlgorithm::EcdsaSha256, + public_key_bytes: pem.contents, + certificate_der: None, + name: Some("TestKeyName-ec-prime256v1".into()), + }; + assert!(VerifyContext::new().key(&key).verify(&xml).is_err()); + let policy = VerificationPolicy { + ecdsa_signature_value_encoding: EcdsaSignatureValueEncoding::XmlSecAsn1Der, + ..VerificationPolicy::default() + }; + let native = VerifyContext::new() + .key(&key) + .policy(policy) + .verify(&xml) + .expect("native ASN.1 compatibility verification must run"); + assert_eq!(native.status, DsigStatus::Valid); +} diff --git a/tests/xmlsec1_interop.rs b/tests/xmlsec1_interop.rs index 094cef48..78e206a3 100644 --- a/tests/xmlsec1_interop.rs +++ b/tests/xmlsec1_interop.rs @@ -13,8 +13,7 @@ mod cryptographic; use xml_sec::c14n::{C14nAlgorithm, C14nMode}; use xml_sec::policy::{ - EcdsaSignatureValueEncoding, SameDocumentIdSemantics, SigningPolicy, TransformPolicy, - VerificationPolicy, + SameDocumentIdSemantics, SigningPolicy, TransformPolicy, VerificationPolicy, }; use xml_sec::xmldsig::{ DefaultKeyResolver, DigestAlgorithm, DsaSigningKey, DsigStatus, EcdsaP256SigningKey, @@ -194,65 +193,6 @@ fn xmlsec1_version_gate_requires_pinned_snapshot() { } } -#[test] -fn asn1_ecdsa_compatibility_matches_pinned_xmlsec1() { - // The upstream vector is intentionally invalid under XMLDSig framing and - // valid only when both implementations select libxmlsec1's ASN.1 mode. - if !xmlsec1::is_available() { - eprintln!("{}", xmlsec1::skip_reason()); - return; - } - let fixture = Path::new( - "donors/xmlsec/tests/aleksey-xmldsig-01/enveloped-sha256-ecdsa-sha256-with-asn1.xml", - ); - let public_key = Path::new("donors/xmlsec/tests/keys/ec/ec-prime256v1-pubkey.pem"); - let donor_key_option = "--pubkey-pem:TestKeyName-ec-prime256v1"; - - let donor_default = xmlsec1::command() - .args(["--verify", donor_key_option]) - .arg(public_key) - .arg(fixture) - .output() - .expect("pinned xmlsec1 must run"); - assert!(!donor_default.status.success()); - let donor_compatible = xmlsec1::command() - .args([ - "--verify", - "--enable-asn1-signatures-hack", - donor_key_option, - ]) - .arg(public_key) - .arg(fixture) - .output() - .expect("pinned xmlsec1 must run"); - assert!( - donor_compatible.status.success(), - "{}", - String::from_utf8_lossy(&donor_compatible.stderr) - ); - - let xml = fs::read_to_string(fixture).expect("upstream ASN.1 fixture must load"); - let (_, pem) = x509_parser::pem::parse_x509_pem(&fs::read(public_key).unwrap()) - .expect("upstream EC public key must parse"); - let key = VerificationKey { - algorithm: SignatureAlgorithm::EcdsaSha256, - public_key_bytes: pem.contents, - certificate_der: None, - name: Some("TestKeyName-ec-prime256v1".into()), - }; - assert!(VerifyContext::new().key(&key).verify(&xml).is_err()); - let policy = VerificationPolicy { - ecdsa_signature_value_encoding: EcdsaSignatureValueEncoding::XmlSecAsn1Der, - ..VerificationPolicy::default() - }; - let native = VerifyContext::new() - .key(&key) - .policy(policy) - .verify(&xml) - .expect("native ASN.1 compatibility verification must run"); - assert_eq!(native.status, DsigStatus::Valid); -} - #[test] fn visa3d_direct_id_compatibility_matches_pinned_xmlsec1() { // An apostrophe breaks libxmlsec1's default xpointer(id('...')) wrapper. diff --git a/tools/capability-ledger/Cargo.toml b/tools/capability-ledger/Cargo.toml index 547f0e98..9aa060b3 100644 --- a/tools/capability-ledger/Cargo.toml +++ b/tools/capability-ledger/Cargo.toml @@ -2,6 +2,7 @@ name = "xml-sec-capability-ledger" version = "0.0.0" edition = "2024" +license = "Apache-2.0 AND MIT" publish = false [dependencies] diff --git a/tools/xml-sec-tools/Cargo.toml b/tools/xml-sec-tools/Cargo.toml index 17265062..08a04698 100644 --- a/tools/xml-sec-tools/Cargo.toml +++ b/tools/xml-sec-tools/Cargo.toml @@ -2,6 +2,7 @@ name = "xml-sec-tools" version = "0.0.0" edition = "2024" +license = "Apache-2.0 AND MIT" publish = false [dependencies] From 0f13d9c410a670bdf29ae36fa8278e77974cfcbc Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Sun, 1 Nov 2026 13:29:53 +0200 Subject: [PATCH 5/5] fix(compat): point ledger evidence at the moved donor test --- compatibility/libxmlsec1-1.3.13-behavior-rules.json | 4 ++-- compatibility/libxmlsec1-1.3.13-behavior.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compatibility/libxmlsec1-1.3.13-behavior-rules.json b/compatibility/libxmlsec1-1.3.13-behavior-rules.json index 5125c464..839cf237 100644 --- a/compatibility/libxmlsec1-1.3.13-behavior-rules.json +++ b/compatibility/libxmlsec1-1.3.13-behavior-rules.json @@ -2,8 +2,8 @@ "schema_version": 1, "evidence": { "asn1-signatures": { - "positive": [{"file":"tests/xmlsec1_interop.rs","test":"asn1_ecdsa_compatibility_matches_pinned_xmlsec1","description":"Pinned donor and native verification accept the upstream DER fixture only in explicit compatibility mode."},{"file":"tests/signing_digest.rs","test":"ecdsa_asn1_compatibility_is_explicit_across_the_signing_pipeline","description":"Native signing emits ASN.1 DER only under explicit policy and verifies the result under the matching policy."},{"file":"tools/xmlsec1/tests/process_contract.rs","test":"cli_asn1_signature_mode_requires_the_explicit_donor_flag","description":"The native CLI flag controls both ASN.1 signing output and verification acceptance."}], - "negative": [{"file":"tests/xmlsec1_interop.rs","test":"asn1_ecdsa_compatibility_matches_pinned_xmlsec1","description":"Pinned donor and native standards defaults both reject the upstream DER fixture."},{"file":"tests/signing_digest.rs","test":"ecdsa_asn1_compatibility_is_explicit_across_the_signing_pipeline","description":"Standards-default native verification rejects DER emitted by compatibility-mode signing."},{"file":"tools/xmlsec1/tests/process_contract.rs","test":"cli_asn1_signature_mode_requires_the_explicit_donor_flag","description":"CLI verification without the compatibility flag rejects ASN.1 DER SignatureValue framing."}] + "positive": [{"file":"tests/xmlsec1_donor_interop.rs","test":"asn1_ecdsa_compatibility_matches_pinned_xmlsec1","description":"Pinned donor and native verification accept the upstream DER fixture only in explicit compatibility mode."},{"file":"tests/signing_digest.rs","test":"ecdsa_asn1_compatibility_is_explicit_across_the_signing_pipeline","description":"Native signing emits ASN.1 DER only under explicit policy and verifies the result under the matching policy."},{"file":"tools/xmlsec1/tests/process_contract.rs","test":"cli_asn1_signature_mode_requires_the_explicit_donor_flag","description":"The native CLI flag controls both ASN.1 signing output and verification acceptance."}], + "negative": [{"file":"tests/xmlsec1_donor_interop.rs","test":"asn1_ecdsa_compatibility_matches_pinned_xmlsec1","description":"Pinned donor and native standards defaults both reject the upstream DER fixture."},{"file":"tests/signing_digest.rs","test":"ecdsa_asn1_compatibility_is_explicit_across_the_signing_pipeline","description":"Standards-default native verification rejects DER emitted by compatibility-mode signing."},{"file":"tools/xmlsec1/tests/process_contract.rs","test":"cli_asn1_signature_mode_requires_the_explicit_donor_flag","description":"CLI verification without the compatibility flag rejects ASN.1 DER SignatureValue framing."}] }, "c-boundary-state": { "positive": [{"file":"tests/behavioral_compatibility.rs","test":"pinned_c_oracle_reports_context_callback_and_dom_contracts","description":"A compiled probe measures successful and invalid context state, retained references, pre-execution callback order, userData propagation, and in-place signing mutation against pinned libxmlsec1."},{"file":"tests/behavioral_compatibility.rs","test":"c_boundary_behaviors_are_explicitly_planned","description":"Measured donor-only context, callback, and in-place mutation contracts are named compatibility work."}], diff --git a/compatibility/libxmlsec1-1.3.13-behavior.json b/compatibility/libxmlsec1-1.3.13-behavior.json index c33a562f..b6df49ed 100644 --- a/compatibility/libxmlsec1-1.3.13-behavior.json +++ b/compatibility/libxmlsec1-1.3.13-behavior.json @@ -11,7 +11,7 @@ "asn1-signatures": { "positive": [ { - "file": "tests/xmlsec1_interop.rs", + "file": "tests/xmlsec1_donor_interop.rs", "test": "asn1_ecdsa_compatibility_matches_pinned_xmlsec1", "description": "Pinned donor and native verification accept the upstream DER fixture only in explicit compatibility mode." }, @@ -28,7 +28,7 @@ ], "negative": [ { - "file": "tests/xmlsec1_interop.rs", + "file": "tests/xmlsec1_donor_interop.rs", "test": "asn1_ecdsa_compatibility_matches_pinned_xmlsec1", "description": "Pinned donor and native standards defaults both reject the upstream DER fixture." },