server/lib/tests/metering_doors.rs
//! **The two doors monetize has been waiting for**, driven through the real
//! handlers rather than around them.
//!
//! What each test is actually worth:
//!
//! * [`usage_reports_every_meter_and_names_the_ones_it_cannot_scope`] — the six
//! meters come back, and the three that are only ever measured server-wide say so
//! ON THE WIRE. A per-repository number that is not per-repository is the one
//! failure that would reach an invoice.
//! * [`the_conversion_is_what_monetize_signed`] — the wire fact and the signed fact
//! are different shapes, and `metered::to_signed` is the only bridge. If it drifts
//! every signature fails for a reason no message explains, so it is pinned against
//! a fact signed here with a real Ed25519 key.
//! * [`a_forged_fact_is_refused_and_nothing_is_written`] — the signature check runs
//! BEFORE the disk, and the refusal is `PERMISSION_DENIED` with the frozen code.
//! * [`a_cap_holger_cannot_police_is_refused_at_the_sale`] — a cap on a server-wide
//! meter is refused rather than stored and silently ignored for the life of the
//! plan. gunnar learned that one the expensive way.
//! * [`an_unconfigured_metered_build_refuses_rather_than_pretending`] — a metered
//! binary with no key configured says `holger-metered-4`; it does not accept a
//! fact it cannot verify.
//!
//! The open build's half of the story is `open_build_speaks_no_money.rs`: these
//! tests only run when the feature that contains the vocabulary is on.
use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;
use ed25519_dalek::{Signer, SigningKey};
use holger_server_lib::grpc::holger_metered_proto::{EntitlementFact, EntitlementState};
use holger_server_lib::metered::{self, EntitlementStore, PutRefused};
use holger_server_lib::metering::{PER_REPOSITORY_METERS, SERVER_WIDE_METERS};
use monetize_product::{EntitlementFact as SignedFact, State, TenantId};
/// A deterministic key pair — the test signs exactly the way monetize-server does,
/// over `monetize_embed::signing::fact_message`, so a green here means the real
/// signer's bytes would verify too.
fn keypair() -> (SigningKey, [u8; 32]) {
let signing = SigningKey::from_bytes(&[7u8; 32]);
let public = signing.verifying_key().to_bytes();
(signing, public)
}
/// Sign a Rust fact the way monetize does: Ed25519 over the canonical JSON of the
/// fact minus its signature.
fn sign(fact: &mut SignedFact, key: &SigningKey) {
fact.signature = key
.sign(&monetize_embed::signing::fact_message(fact))
.to_bytes()
.to_vec();
}
fn wire_fact(repo: &str, caps: &[(&str, u64)]) -> EntitlementFact {
EntitlementFact {
repository: repo.to_string(),
plan: "holger/rust-dev/2026-09-16+10gb".to_string(),
state: EntitlementState::Paid as i32,
paid_until_unix_ms: Some(1_800_000_000_000),
caps: caps.iter().map(|(k, v)| ((*k).to_string(), *v)).collect(),
source: "payment:stripe:cs_live_test".to_string(),
signature: vec![0u8; 64],
// Unstamped, which monetize_embed accepts as the legal pre-2026-09-17
// case. The stamped path has its own fixture below.
issued_unix_ms: None,
issued_signature: Vec::new(),
}
}
fn store(dir: &std::path::Path, public: &[u8; 32]) -> EntitlementStore {
EntitlementStore::new(
dir,
Arc::new(BTreeSet::from(["rust-dev".to_string()])),
public,
)
.expect("a 32-byte key is a key")
}
/// **The conversion is the load-bearing part.** A fact signed as the Rust shape must
/// verify after a round trip through the wire shape — that is the whole contract
/// between monetize and holger, and the two shapes disagree about field names, the
/// state's spelling and the map type.
#[test]
fn the_conversion_is_what_monetize_signed() {
let (signing, public) = keypair();
let mut signed = SignedFact {
tenant: TenantId("rust-dev".to_string()),
plan: "holger/rust-dev/2026-09-16+10gb".to_string(),
state: State::Paid,
paid_until_unix_ms: Some(1_800_000_000_000),
caps: BTreeMap::from([("artifacts".to_string(), 10_000u64)]),
source: "payment:stripe:cs_live_test".to_string(),
signature: Vec::new(),
issued_unix_ms: None,
issued_signature: Vec::new(),
};
sign(&mut signed, &signing);
// The wire carries what monetize signed…
let mut wire = wire_fact("rust-dev", &[("artifacts", 10_000)]);
wire.signature = signed.signature.clone();
// …and the conversion must reproduce the signed value EXACTLY, or the signature
// it carries is meaningless.
let back = metered::to_signed(&wire).expect("a well-formed fact converts");
assert_eq!(
back, signed,
"to_signed must rebuild the value monetize signed"
);
// Proof the check is real: verify with the public key, as the store does.
let key = monetize_embed::VerifyingKey::from_bytes(&public).unwrap();
monetize_embed::signing::verify_fact(&back, &key).expect("the round trip verifies");
}
/// A fact signed by a DIFFERENT key is refused, and the store never wrote a byte.
#[test]
fn a_forged_fact_is_refused_and_nothing_is_written() {
let (_, public) = keypair();
let forger = SigningKey::from_bytes(&[9u8; 32]);
let dir = tempfile::tempdir().unwrap();
let store = store(dir.path(), &public);
let mut signed = SignedFact {
tenant: TenantId("rust-dev".to_string()),
plan: "p".to_string(),
state: State::Paid,
paid_until_unix_ms: None,
caps: BTreeMap::new(),
source: "operator".to_string(),
signature: Vec::new(),
issued_unix_ms: None,
issued_signature: Vec::new(),
};
sign(&mut signed, &forger);
match store.put(&signed) {
Err(PutRefused::Signature(_)) => {}
other => panic!("a forged fact must be refused by signature, got {other:?}"),
}
// The refusal happened BEFORE the disk: nothing under the store root.
let wrote_anything = std::fs::read_dir(dir.path())
.map(|d| d.flatten().next().is_some())
.unwrap_or(false);
assert!(!wrote_anything, "a refused fact must leave no file behind");
assert!(
store.get("rust-dev").unwrap().is_none(),
"…and nothing readable"
);
}
/// The honestly-signed fact IS stored, so the refusal above discriminates rather
/// than refusing everything.
#[test]
fn an_honestly_signed_fact_is_stored_and_reads_back() {
let (signing, public) = keypair();
let dir = tempfile::tempdir().unwrap();
let store = store(dir.path(), &public);
let mut signed = SignedFact {
tenant: TenantId("rust-dev".to_string()),
plan: "holger/rust-dev/2026-09-16+10gb".to_string(),
state: State::Paid,
paid_until_unix_ms: Some(1_800_000_000_000),
caps: BTreeMap::from([("archive_bytes".to_string(), 10 << 30)]),
source: "payment:stripe:cs_live_test".to_string(),
signature: Vec::new(),
issued_unix_ms: None,
issued_signature: Vec::new(),
};
sign(&mut signed, &signing);
store
.put(&signed)
.expect("a fact signed by the configured key is stored");
let back = store.get("rust-dev").unwrap().expect("it reads back");
assert_eq!(back, signed);
assert_eq!(store.list().len(), 1);
}
/// **A cap on a meter holger only measures server-wide is refused at the sale.**
/// Storing it would be a promise about a number that is not the tenant's, and the
/// operator would hear about it from the customer months later, or never.
#[test]
fn a_cap_holger_cannot_police_is_refused_at_the_sale() {
// Every per-repository meter is accepted…
for meter in PER_REPOSITORY_METERS {
let fact = wire_fact("rust-dev", &[(meter, 1)]);
metered::well_formed(&fact)
.unwrap_or_else(|e| panic!("'{meter}' is measured per repository: {e}"));
}
// …and every server-wide one is refused BY NAME, with the frozen code.
for meter in SERVER_WIDE_METERS {
let fact = wire_fact("rust-dev", &[(meter, 1)]);
let err =
metered::well_formed(&fact).expect_err("a cap on a server-wide meter must be refused");
assert_eq!(err.code(), tonic::Code::InvalidArgument);
assert!(
err.message().contains(meter),
"the refusal must NAME the meter: {}",
err.message()
);
assert!(
err.message().contains("holger-metered-2"),
"the refusal carries its frozen code: {}",
err.message()
);
}
}
/// The shape checks tell a malformed push apart from a forged one.
#[test]
fn a_malformed_fact_is_invalid_argument_not_permission_denied() {
let mut fact = wire_fact("rust-dev", &[]);
fact.signature = vec![0u8; 63];
let err = metered::well_formed(&fact).expect_err("63 bytes is not an Ed25519 signature");
assert_eq!(err.code(), tonic::Code::InvalidArgument);
assert!(
err.message().contains("holger-metered-1"),
"{}",
err.message()
);
let mut fact = wire_fact("rust-dev", &[]);
fact.source.clear();
let err = metered::well_formed(&fact).expect_err("a fact must say where it came from");
assert!(err.message().contains("source"), "{}", err.message());
}
/// A repository this server does not serve is NOT a place to write a plan file —
/// the roster gate every metadata store here applies.
#[test]
fn the_store_is_closed_to_the_repository_roster() {
let (_, public) = keypair();
let dir = tempfile::tempdir().unwrap();
let store = store(dir.path(), &public);
assert!(store.serves("rust-dev"));
assert!(
!store.serves("maven-prod"),
"a repository this server never configured"
);
}
// ── THE ISSUE STAMP (2026-09-17) ─────────────────────────────────────────────
//
// Every fixture above builds an UNSTAMPED fact (`issued_unix_ms: None`,
// `issued_signature: Vec::new()`), which monetize_embed accepts as the legal
// pre-2026-09-17 case. That is why the full-value `assert_eq!` in
// [`the_conversion_is_what_monetize_signed`] could not see a dropped stamp:
// `None` and an empty `Vec` survive a conversion that forgets both fields, and
// the signature keeps verifying because the V1 form never covered them. The
// replay guard would then be gone with the whole suite green — which is how
// close it came on the day the fields were added.
//
// The fixtures below are STAMPED, so the two carry-through lines in
// `metered::to_signed` and `metered::to_wire` are load-bearing: delete either
// one and these go red.
/// A stamped fact and the wire message that carries it, signed both halves the
/// way monetize-server signs them: V1 over everything but the three, V2 over the
/// V1 form plus `issued_unix_ms`.
fn stamped_pair(issued: u64, key: &SigningKey) -> (SignedFact, EntitlementFact) {
let mut signed = SignedFact {
tenant: TenantId("rust-dev".to_string()),
plan: "holger/rust-dev/2026-09-16+10gb".to_string(),
state: State::Paid,
paid_until_unix_ms: Some(1_800_000_000_000),
caps: BTreeMap::from([("artifacts".to_string(), 10_000u64)]),
source: "payment:stripe:cs_live_test".to_string(),
signature: Vec::new(),
issued_unix_ms: Some(issued),
issued_signature: Vec::new(),
};
sign(&mut signed, key);
signed.issued_signature = key
.sign(&monetize_embed::signing::fact_message_issued(&signed))
.to_bytes()
.to_vec();
let mut wire = wire_fact("rust-dev", &[("artifacts", 10_000)]);
wire.signature = signed.signature.clone();
wire.issued_unix_ms = signed.issued_unix_ms;
wire.issued_signature = signed.issued_signature.clone();
(signed, wire)
}
/// **The stamp survives the wire→signed conversion, or the replay guard is gone.**
///
/// `to_signed` dropping `issued_unix_ms`/`issued_signature` does NOT break any
/// signature: the fact simply arrives at the verifier as the legal unstamped
/// case, which it accepts. So nothing but a stamped fixture can catch it. Both
/// halves are asserted separately from the whole-value compare, so the failure
/// NAMES the field rather than printing two large structs.
#[test]
fn the_conversion_carries_the_issue_stamp() {
let (signing, public) = keypair();
let (signed, wire) = stamped_pair(1_789_000_000_000, &signing);
let back = metered::to_signed(&wire).expect("a well-formed stamped fact converts");
assert_eq!(
back.issued_unix_ms,
Some(1_789_000_000_000),
"to_signed dropped issued_unix_ms — a stamped fact reaches the verifier as the \
LEGAL UNSTAMPED CASE and the replay guard is silently gone"
);
assert_eq!(
back.issued_signature, signed.issued_signature,
"to_signed dropped issued_signature — the issue time is then unsigned, which is \
not a claim about anything"
);
assert_eq!(
back, signed,
"to_signed must rebuild the value monetize signed"
);
// Both halves verify: V1 over the fact, V2 over the fact plus the issue time.
let key = monetize_embed::VerifyingKey::from_bytes(&public).unwrap();
monetize_embed::signing::verify_fact(&back, &key).expect("a stamped round trip verifies");
}
/// The same for the OUTBOUND half. `Get` and `List` hand a stored fact back over
/// the wire through `to_wire`; a stamp lost there is a stamp the next holder
/// never sees, and the fact they replay is the legal unstamped one.
#[test]
fn the_wire_shape_carries_the_issue_stamp_back_out() {
let (signing, public) = keypair();
let (signed, _) = stamped_pair(1_789_000_000_000, &signing);
let out = metered::to_wire(&signed);
assert_eq!(
out.issued_unix_ms,
Some(1_789_000_000_000),
"to_wire dropped issued_unix_ms — Get/List hand out an UNSTAMPED fact"
);
assert_eq!(
out.issued_signature, signed.issued_signature,
"to_wire dropped issued_signature"
);
// Round trip: out and back is the identity, and the result still verifies.
let back = metered::to_signed(&out).expect("the wire shape converts back");
assert_eq!(
back, signed,
"signed -> wire -> signed must be the identity"
);
let key = monetize_embed::VerifyingKey::from_bytes(&public).unwrap();
monetize_embed::signing::verify_fact(&back, &key).expect("the stamped round trip verifies");
}
/// **The negative control for the fixture itself.** If `stamped_pair` ever stopped
/// producing a stamped fact, the two tests above would go quietly vacuous in
/// exactly the way the unstamped fixtures did. So: the fixture IS stamped, and a
/// fact with the stamp removed verifies anyway — which is the property that makes
/// a dropped stamp invisible to every signature check.
#[test]
fn an_unstamped_fact_verifies_too_which_is_why_the_stamp_needs_its_own_fixture() {
let (signing, public) = keypair();
let (signed, wire) = stamped_pair(1_789_000_000_000, &signing);
assert!(
signed.issued_unix_ms.is_some(),
"the fixture must be STAMPED"
);
assert!(
!signed.issued_signature.is_empty(),
"the fixture must be STAMPED"
);
assert!(
wire.issued_unix_ms.is_some(),
"the wire fixture must be STAMPED"
);
// Strip the stamp, exactly as a forgetful `to_signed` would.
let mut stripped = metered::to_signed(&wire).expect("converts");
stripped.issued_unix_ms = None;
stripped.issued_signature.clear();
let key = monetize_embed::VerifyingKey::from_bytes(&public).unwrap();
monetize_embed::signing::verify_fact(&stripped, &key).expect(
"THE WHOLE POINT: a stamp-stripped fact still verifies, so no signature \
check can stand in for the assertions above",
);
}