#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use uuid::Uuid;
use crate::secret_gate::reject_reserved_secret_gate_property;
use crate::secret_gate_finalizer::declaration::{
Substrate as DeclSubstrate, FINALIZER_ENTRY_POINTS,
};
use crate::secret_gate_finalizer::faults;
use crate::secret_gate_finalizer::log_sink::CapturingLogSink;
use crate::secret_gate_finalizer::manifest::fixture::TestOnlyManifestFixture;
use crate::secret_gate_finalizer::manifest::{
canonical_empty_document_sha256_hex, digest_to_hex, resolve_match, scoped_digest,
ManifestManager, ManifestSnapshot, RuntimeFieldScope,
};
use crate::secret_gate_finalizer::matrix::{generated_acceptance_matrix, MatrixCaseKind};
use crate::secret_gate_finalizer::outcome::{
FailureClass, FailureDiagnostic, FinalizerOutcome, ManifestFault, Substrate,
};
use crate::secret_gate_finalizer::transaction::{
finalize, ExemptionMatch, FinalizationEffects, FinalizationInput,
};
#[derive(Default)]
struct AcceptanceEffects {
record_written: bool,
stamp_written: bool,
audit_written: bool,
failure_audits: Vec<FailureDiagnostic>,
}
impl AcceptanceEffects {
fn state(&self) -> (bool, bool, bool) {
(self.record_written, self.stamp_written, self.audit_written)
}
}
impl FinalizationEffects for AcceptanceEffects {
fn resolve_manifest(&mut self) -> Result<ExemptionMatch, ManifestFault> {
Ok(ExemptionMatch {
digest_sha256: digest_to_hex(&scoped_digest(
RuntimeFieldScope::RecordContent,
"acceptance-harness-fixture-value",
)),
field_scope: "record-content",
manifest_id: "khive-secret-gate-empty-v1".to_string(),
})
}
fn write_record(&mut self) -> Result<(), ()> {
self.record_written = true;
Ok(())
}
fn write_stamp(&mut self) -> Result<(), ()> {
self.stamp_written = true;
Ok(())
}
fn write_success_audit(&mut self) -> Result<(), ()> {
self.audit_written = true;
Ok(())
}
fn rollback(&mut self) {
self.record_written = false;
self.stamp_written = false;
self.audit_written = false;
}
fn write_failure_audit(&mut self, diagnostic: &FailureDiagnostic) -> Result<(), ()> {
self.failure_audits.push(diagnostic.clone());
Ok(())
}
}
fn substrate_for(decl: DeclSubstrate) -> Substrate {
match decl {
DeclSubstrate::Entity => Substrate::Entity,
DeclSubstrate::Note => Substrate::Note,
}
}
const FINALIZE_OBSERVABLE: &[MatrixCaseKind] = &[
MatrixCaseKind::FixtureMatch,
MatrixCaseKind::SupportedEcho,
MatrixCaseKind::RecordWriteFailure,
MatrixCaseKind::StampFailure,
MatrixCaseKind::SuccessAuditFailure,
MatrixCaseKind::SecondOrderFailureAuditFailure,
];
const DEFERRED_TO_OWNING_FUNCTION: &[MatrixCaseKind] = &[
MatrixCaseKind::LegacyScannerBehavior,
MatrixCaseKind::OneByteMiss,
MatrixCaseKind::WrongScopeMiss,
MatrixCaseKind::ReservedKeyMutation,
MatrixCaseKind::OneSnapshotRefreshRace,
];
#[test]
fn generated_matrix_drives_finalize_for_every_declared_entry_point() {
let rows = generated_acceptance_matrix();
assert_eq!(
rows.len(),
FINALIZER_ENTRY_POINTS.len() * MatrixCaseKind::ALL.len(),
"harness must consume the full generated cross product, not a subset"
);
let mut covered: BTreeSet<(&str, MatrixCaseKind)> = BTreeSet::new();
let pre_state = AcceptanceEffects::default().state();
for row in &rows {
if !FINALIZE_OBSERVABLE.contains(&row.case) {
continue;
}
let ns = format!("acceptance-{}-{:?}", row.entry_point.id, row.case);
let input = FinalizationInput {
record_id: Uuid::new_v4(),
substrate: substrate_for(row.entry_point.substrate),
namespace: ns.clone(),
entry_point: row.entry_point.id,
};
match row.case {
MatrixCaseKind::FixtureMatch | MatrixCaseKind::SupportedEcho => {
let mut effects = AcceptanceEffects::default();
let sink = CapturingLogSink::new();
let outcome = finalize(&mut effects, &sink, &input);
match &outcome {
FinalizerOutcome::Exempted(commit) => {
assert_eq!(commit.entry_point, row.entry_point.id);
assert_eq!(commit.record_id, input.record_id);
}
other => panic!(
"{}/{:?}: expected Exempted, got {other:?}",
row.entry_point.id, row.case
),
}
assert_eq!(effects.state(), (true, true, true));
assert!(sink.snapshot().is_empty());
}
MatrixCaseKind::RecordWriteFailure => {
let _arm = faults::arm_record_write_fail(&ns);
let mut effects = AcceptanceEffects::default();
let sink = CapturingLogSink::new();
let outcome = finalize(&mut effects, &sink, &input);
match outcome {
FinalizerOutcome::RecordWriteFailed(d) => {
assert_eq!(d.failure_class, FailureClass::RecordWrite);
assert_eq!(d.entry_point, row.entry_point.id);
}
other => panic!(
"{}/{:?}: expected RecordWriteFailed, got {other:?}",
row.entry_point.id, row.case
),
}
assert_eq!(
effects.state(),
pre_state,
"{}/{:?}: no partial mutation may survive rollback",
row.entry_point.id,
row.case
);
assert_eq!(effects.failure_audits.len(), 1);
assert!(sink.snapshot().is_empty());
}
MatrixCaseKind::StampFailure => {
let _arm = faults::arm_stamp_fail(&ns);
let mut effects = AcceptanceEffects::default();
let sink = CapturingLogSink::new();
let outcome = finalize(&mut effects, &sink, &input);
match outcome {
FinalizerOutcome::StampFailed(d) => {
assert_eq!(d.failure_class, FailureClass::Stamp)
}
other => panic!(
"{}/{:?}: expected StampFailed, got {other:?}",
row.entry_point.id, row.case
),
}
assert_eq!(effects.state(), pre_state);
}
MatrixCaseKind::SuccessAuditFailure => {
let _arm = faults::arm_success_audit_fail(&ns);
let mut effects = AcceptanceEffects::default();
let sink = CapturingLogSink::new();
let outcome = finalize(&mut effects, &sink, &input);
match outcome {
FinalizerOutcome::AuditFailed(d) => {
assert_eq!(d.failure_class, FailureClass::SuccessAudit)
}
other => panic!(
"{}/{:?}: expected AuditFailed, got {other:?}",
row.entry_point.id, row.case
),
}
assert_eq!(effects.state(), pre_state);
}
MatrixCaseKind::SecondOrderFailureAuditFailure => {
let _record_arm = faults::arm_record_write_fail(&ns);
let _failure_audit_arm = faults::arm_failure_audit_fail(&ns);
let mut effects = AcceptanceEffects::default();
let sink = CapturingLogSink::new();
let outcome = finalize(&mut effects, &sink, &input);
let diagnostic = match outcome {
FinalizerOutcome::RecordWriteFailed(d) => d,
other => panic!(
"{}/{:?}: expected RecordWriteFailed, got {other:?}",
row.entry_point.id, row.case
),
};
assert_eq!(
effects.state(),
pre_state,
"second-order case must still leave no survivor"
);
assert!(
effects.failure_audits.is_empty(),
"failure-audit write was injected to fail; nothing should have recorded"
);
let gaps = sink.snapshot();
assert_eq!(
gaps.len(),
1,
"exactly one independent audit-gap record for the second-order case"
);
assert_eq!(gaps[0].diagnostic_id, diagnostic.diagnostic_id);
assert_eq!(gaps[0].entry_point, row.entry_point.id);
assert_eq!(gaps[0].failure_class, FailureClass::RecordWrite);
}
_ => unreachable!("filtered by FINALIZE_OBSERVABLE above"),
}
covered.insert((row.entry_point.id, row.case));
}
for ep in FINALIZER_ENTRY_POINTS {
for case in FINALIZE_OBSERVABLE {
assert!(
covered.contains(&(ep.id, *case)),
"missing acceptance coverage for {}/{:?}",
ep.id,
case
);
}
}
}
#[test]
fn finalize_observable_and_deferred_partition_every_case_kind_exactly() {
let observable: BTreeSet<MatrixCaseKind> = FINALIZE_OBSERVABLE.iter().copied().collect();
let deferred: BTreeSet<MatrixCaseKind> =
DEFERRED_TO_OWNING_FUNCTION.iter().copied().collect();
assert!(
observable.is_disjoint(&deferred),
"a case kind must not be both finalize-observable and deferred"
);
let union: BTreeSet<MatrixCaseKind> = observable.union(&deferred).copied().collect();
let all: BTreeSet<MatrixCaseKind> = MatrixCaseKind::ALL.iter().copied().collect();
assert_eq!(
union, all,
"every declared MatrixCaseKind must be finalize-observable or explicitly deferred"
);
}
#[test]
fn deferred_case_kinds_are_covered_by_their_owning_functions() {
let empty = ManifestSnapshot::empty();
let secret_like = "AKIAFAKELEGACYSCANNER0000000000";
let scanned = [(RuntimeFieldScope::RecordContent, secret_like)];
assert_eq!(
resolve_match(&empty, &scanned).expect("empty snapshot never faults"),
None,
"LegacyScannerBehavior: empty manifest must report no candidate hit"
);
assert!(
crate::secret_gate::check(secret_like).is_err(),
"LegacyScannerBehavior: the unchanged legacy scanner must still reject \
secret-shaped content when no manifest entry matches"
);
let fixture = TestOnlyManifestFixture::new();
let fixture_snapshot = fixture.snapshot();
let exact = fixture.exact_value();
assert!(
resolve_match(&fixture_snapshot, &[(fixture.field_scope(), exact)])
.expect("fixture snapshot never faults")
.is_some(),
"OneByteMiss baseline: the exact fixture value must hit"
);
let mut mutated = exact.as_bytes().to_vec();
let last = mutated.len() - 1;
mutated[last] = mutated[last].wrapping_add(1);
let mutated = String::from_utf8(mutated).expect("mutated byte stays valid UTF-8");
assert_eq!(
resolve_match(
&fixture_snapshot,
&[(fixture.field_scope(), mutated.as_str())]
)
.expect("fixture snapshot never faults"),
None,
"OneByteMiss: a one-byte-mutated value must miss"
);
let wrong_scope = if fixture.field_scope() == RuntimeFieldScope::RecordContent {
RuntimeFieldScope::NameDescription
} else {
RuntimeFieldScope::RecordContent
};
assert_eq!(
resolve_match(&fixture_snapshot, &[(wrong_scope, exact)])
.expect("fixture snapshot never faults"),
None,
"WrongScopeMiss: the same exact value under the wrong scope must miss"
);
let reserved =
serde_json::json!({"khive:secret_gate": "exempted:content-sha256-manifest-v1"});
assert!(
reject_reserved_secret_gate_property(Some(&reserved)).is_err(),
"ReservedKeyMutation: the shared reservation validator must reject the key"
);
let manager = ManifestManager::new();
let pinned = manager.current();
assert!(
pinned.is_empty(),
"manager starts on the empty default snapshot"
);
let _ = manager.refresh(None, None);
assert!(
pinned.is_empty(),
"OneSnapshotRefreshRace: a snapshot cloned before refresh must stay pinned"
);
}
#[test]
fn reservation_rejects_top_level_key_regardless_of_value_shape() {
for value in [
serde_json::json!("exempted:content-sha256-manifest-v1"),
serde_json::json!("something-else-entirely"),
serde_json::json!(null),
serde_json::json!(42),
serde_json::json!({"nested": true}),
serde_json::json!([1, 2, 3]),
] {
let props = serde_json::json!({ "khive:secret_gate": value, "other": "ok" });
assert!(
reject_reserved_secret_gate_property(Some(&props)).is_err(),
"reservation must reject top-level key regardless of value shape: {props}"
);
}
}
#[test]
fn reservation_allows_absent_properties_and_nested_occurrences() {
assert!(reject_reserved_secret_gate_property(None).is_ok());
let nested = serde_json::json!({"notes": {"khive:secret_gate": "not-a-stamp"}});
assert!(reject_reserved_secret_gate_property(Some(&nested)).is_ok());
}
#[test]
fn manifest_empty_value_vectors_match_the_executable_contract_table() {
let vectors: &[(RuntimeFieldScope, &str)] = &[
(
RuntimeFieldScope::RecordContent,
"8babc16495ddbc04d2fd382d3b423d452bedb7567e64cfbe5bb85a5bcb4ff04a",
),
(
RuntimeFieldScope::NameDescription,
"db6c4a6305fabfdc246bfc3f37cba55907ee65e5035827f06598a37b478e97d1",
),
(
RuntimeFieldScope::JsonProperties,
"2d1a970af8016a1721b1457c7675b08355b6da0b3c859934da1fabf7e660ee28",
),
(
RuntimeFieldScope::Tags,
"a1037f3591a751f9d34748fd090a4551d87cbdbb819e7b612e470b6a3a58f833",
),
(
RuntimeFieldScope::CodeSource,
"1a53a3a30c62d6c805aabd11ace2124699821b5f046df4c08cf96ac9fa18e892",
),
];
for (scope, expected) in vectors {
let actual = digest_to_hex(&scoped_digest(*scope, ""));
assert_eq!(
&actual, expected,
"empty-value vector mismatch for {scope:?}"
);
assert_eq!(actual.len(), 64, "SHA-256 hex must be exactly 64 chars");
}
}
#[test]
fn canonical_empty_document_hash_matches_the_executable_contract_value() {
let expected = "ee4e2ab801099252459bcf930583bed9e8107aad2cc7af2db361f85ee65a31b9";
let actual = canonical_empty_document_sha256_hex();
assert_eq!(actual.len(), 64);
assert_eq!(actual, expected);
}
}