crates/gunnar-cli/tests/forge_spine.rs
#![cfg(feature = "server")]
//! **The forge's evidence spine, through the real stores** (roadmap phase 1).
//!
//! The claim under test is the one the roadmap makes about this phase:
//!
//! > An approval gets the same evidential weight as a commit.
//!
//! So the arms are about *evidence*, not about features. What is asserted is
//! that an approval is signed by the reviewer's own key, that it names the
//! commit it approved, that a key gunnar does not know cannot write one at all,
//! and — the one that matters most — that **a force-push does not inherit a
//! review**.
mod common;
use common::Harness;
use gunnar_core::forge::{fold, sign_event, verify_event, Event, EventProblem, ForgeEvent};
use gunnar_core::HashKind;
fn read_events(harness: &Harness) -> Vec<gunnar_core::SignedEvent> {
harness
.stores
.forge_log()
.lines_of()
.expect("read the forge log")
.iter()
.map(|line| serde_json::from_str(line).expect("decode a forge event"))
.collect()
}
fn append(harness: &Harness, signed: &gunnar_core::SignedEvent) {
use std::io::Write as _;
let log = harness.stores.forge_log();
let mut line = serde_json::to_string(signed).expect("json");
line.push('\n');
let mut file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(log.records_path())
.expect("open the forge log");
file.write_all(line.as_bytes()).expect("append");
}
fn event(pull: u64, actor: &str, at: i64, event: Event) -> ForgeEvent {
ForgeEvent {
repo: "team/reviewed".into(),
pull,
actor: actor.into(),
at_unix_ms: at,
event,
}
}
/// **An approval is checkable against the identity key table, later, by anybody.**
///
/// The harness's key is registered, so the approval it signs is evidence; a key
/// nobody registered produces a signature with nothing to check it against,
/// which is the state the `forge` verb refuses to create and this arm shows the
/// consequence of.
#[test]
fn an_approval_is_signed_by_a_registered_key_and_verifies_against_the_table() {
let harness = Harness::start("team", "reviewed", HashKind::Sha1);
let commit = "a".repeat(40);
let opened = sign_event(
&harness.private_key,
event(
1,
"tester",
1_700_000_000_000,
Event::Commented {
body: "here is why".into(),
path: String::new(),
line: 0,
blob_oid: String::new(),
},
),
)
.expect("sign");
let approved = sign_event(
&harness.private_key,
event(
1,
"tester",
1_700_000_001_000,
Event::Approved {
commit: commit.clone(),
},
),
)
.expect("sign");
append(&harness, &opened);
append(&harness, &approved);
// A reader with the identity table and nothing else can check it.
let registered: Vec<gunnar_core::ssh_key::PublicKey> = harness
.stores
.auth()
.signing_keys()
.expect("keys")
.iter()
.filter_map(|row| gunnar_core::ssh_key::PublicKey::from_openssh(&row.openssh).ok())
.collect();
assert!(
!registered.is_empty(),
"the harness registers a key; without one this arm proves nothing"
);
let stored = read_events(&harness);
let approval = stored
.iter()
.find(|e| matches!(e.event.event, Event::Approved { .. }))
.expect("the approval was written");
let key = registered
.iter()
.find(|k| {
k.fingerprint(gunnar_core::ssh_key::HashAlg::Sha256)
.to_string()
== approval.key_fingerprint
})
.expect("the signing key is in the identity table");
assert_eq!(verify_event(approval, key), Ok(()));
// …and a different registered key must not verify it.
let stranger =
gunnar_core::ssh_key::PrivateKey::from_openssh(gunnar_core::mint_ed25519().expect("mint"))
.expect("parse");
assert!(matches!(
verify_event(approval, stranger.public_key()),
Err(EventProblem::WrongKey { .. })
));
}
/// **A force-push does not inherit a review.**
///
/// The approval names the commit it approved. Move the branch and the approval
/// still names the old one — visibly, in the fold — which is exactly the fact a
/// mutable `approved: bool` destroys and the reason this log is events.
#[test]
fn an_approval_does_not_follow_the_branch_when_it_moves() {
let harness = Harness::start("team", "reviewed", HashKind::Sha1);
let reviewed = "1".repeat(40);
let force_pushed = "2".repeat(40);
for signed in [
sign_event(
&harness.private_key,
event(
1,
"tester",
1,
Event::Commented {
body: String::new(),
path: String::new(),
line: 0,
blob_oid: String::new(),
},
),
)
.expect("sign"),
sign_event(
&harness.private_key,
event(
1,
"tester",
2,
Event::Approved {
commit: reviewed.clone(),
},
),
)
.expect("sign"),
] {
append(&harness, &signed);
}
let events: Vec<ForgeEvent> = read_events(&harness).into_iter().map(|s| s.event).collect();
let review = fold(1, &events);
assert_eq!(
review.approvers_of(&reviewed),
vec!["tester"],
"the commit that was reviewed must be approved"
);
assert!(
review.approvers_of(&force_pushed).is_empty(),
"the branch moved and the approval followed it. A review of one commit is not a review \
of another, and a forge that lets it follow is one where a force-push after approval \
ships unreviewed code"
);
}
/// The log is covered by the **same** transparency machinery, so a rewritten
/// approval is caught the same way a rewritten push attestation is.
#[test]
fn the_forge_log_is_covered_by_a_signed_tree_head() {
let harness = Harness::start("team", "reviewed", HashKind::Sha1);
let commit = "3".repeat(40);
for signed in [
sign_event(
&harness.private_key,
event(
1,
"tester",
1,
Event::Commented {
body: String::new(),
path: String::new(),
line: 0,
blob_oid: String::new(),
},
),
)
.expect("sign"),
sign_event(
&harness.private_key,
event(1, "tester", 2, Event::Approved { commit }),
)
.expect("sign"),
] {
append(&harness, &signed);
}
let log = harness.stores.forge_log();
let key = harness.stores.transparency_key().expect("key");
log.issue_head(&key, 1_700_000_000_000).expect("head");
assert!(
log.audit(key.public_key()).expect("audit").is_consistent(),
"the control: a freshly headed log must audit clean"
);
// Rewrite the approval to name a different commit — the edit an attacker
// with the disk would actually make.
let path = log.records_path().to_path_buf();
let text = std::fs::read_to_string(&path).expect("read");
let tampered = text.replacen(&"3".repeat(40), &"4".repeat(40), 1);
assert_ne!(tampered, text, "the rewrite changed nothing");
std::fs::write(&path, tampered).expect("rewrite");
assert!(
!log.audit(key.public_key()).expect("audit").is_consistent(),
"an approval was rewritten under a signed head and the audit did not notice"
);
}