mod support;
use serde_json::Value;
use support::git_repo::GitRepo;
use support::pointbreak_env;
#[test]
fn attest_stages_attributes_and_reader_resolves_kind_and_roles() {
let repo = GitRepo::new();
let out = pointbreak_env(
[
"identity",
"attest",
"actor:git-email:kevin@swiber.dev",
"--kind",
"human",
"--role",
"author",
"--role",
"reviewer",
"--repo",
repo.path().to_str().unwrap(),
],
&[],
);
assert!(
out.status.success(),
"stderr:\n{}",
String::from_utf8_lossy(&out.stderr)
);
let doc: Value = serde_json::from_slice(&out.stdout).unwrap();
assert_eq!(doc["schema"], "pointbreak.identity-attest");
assert_eq!(doc["actor"], "actor:git-email:kevin@swiber.dev");
assert_eq!(doc["kind"], "human");
assert_eq!(doc["changed"], true);
let path = repo.path().join(".pointbreak/actor-attributes.json");
let map = pointbreak::session::ActorAttributesMap::from_attributes_file(&path).unwrap();
let resolved = map.resolve(&pointbreak::model::ActorId::new(
"actor:git-email:kevin@swiber.dev",
));
assert_eq!(resolved.kind(), Some("human"));
assert!(resolved.has_role("author") && resolved.has_role("reviewer"));
}
#[test]
fn attest_normalizes_tokens() {
let repo = GitRepo::new();
let out = pointbreak_env(
[
"identity",
"attest",
"actor:agent:review-bot",
"--kind",
"Reviewer-Model",
"--role",
"Reviewer",
"--role",
"reviewer",
"--repo",
repo.path().to_str().unwrap(),
],
&[],
);
assert!(out.status.success());
let map = pointbreak::session::ActorAttributesMap::from_attributes_file(
repo.path().join(".pointbreak/actor-attributes.json"),
)
.unwrap();
let r = map.resolve(&pointbreak::model::ActorId::new("actor:agent:review-bot"));
assert_eq!(r.kind(), Some("reviewer-model"));
assert_eq!(
r.roles().iter().cloned().collect::<Vec<_>>(),
vec!["reviewer"]
); }
#[test]
fn attest_requires_kind() {
let repo = GitRepo::new();
let out = pointbreak_env(
[
"identity",
"attest",
"actor:agent:x",
"--repo",
repo.path().to_str().unwrap(),
],
&[],
);
assert!(
!out.status.success(),
"--kind is required (ADR-0012: exactly one kind per actor)"
);
}
#[test]
fn attest_rejects_bad_role_token_and_writes_nothing() {
let repo = GitRepo::new();
let out = pointbreak_env(
[
"identity",
"attest",
"actor:agent:x",
"--kind",
"agent",
"--role",
"Has Space",
"--repo",
repo.path().to_str().unwrap(),
],
&[],
);
assert!(!out.status.success());
assert!(!String::from_utf8_lossy(&out.stderr).contains("panicked"));
assert!(
!repo
.path()
.join(".pointbreak/actor-attributes.json")
.exists()
);
}
#[test]
fn attest_local_writes_override_excludes_it_and_surfaces_full_replace_caveat() {
let repo = GitRepo::new();
let out = pointbreak_env(
[
"identity",
"attest",
"actor:git-email:kevin@swiber.dev",
"--kind",
"human",
"--local",
"--repo",
repo.path().to_str().unwrap(),
],
&[],
);
assert!(
out.status.success(),
"stderr:\n{}",
String::from_utf8_lossy(&out.stderr)
);
assert!(
repo.path()
.join(".pointbreak/actor-attributes.local.json")
.exists()
);
let ignore = std::fs::read_to_string(repo.path().join(".pointbreak/.gitignore")).unwrap();
assert!(ignore.lines().any(|l| l.trim() == "*.local.json"));
let check = std::process::Command::new("git")
.args(["check-ignore", ".pointbreak/actor-attributes.local.json"])
.current_dir(repo.path())
.status()
.unwrap();
assert!(check.success(), "the local override must be git-ignored");
let stderr = String::from_utf8_lossy(&out.stderr).to_lowercase();
assert!(
stderr.contains("replace") || stderr.contains("shadow"),
"must surface the full-replace caveat: {stderr}"
);
}
#[test]
fn attest_never_commits() {
let repo = GitRepo::new();
let _ = pointbreak_env(
[
"identity",
"attest",
"actor:agent:x",
"--kind",
"agent",
"--repo",
repo.path().to_str().unwrap(),
],
&[],
);
let log = std::process::Command::new("git")
.args(["rev-list", "--count", "--all"])
.current_dir(repo.path())
.output()
.unwrap();
assert_eq!(String::from_utf8_lossy(&log.stdout).trim(), "0");
}
#[test]
fn text_identity_attest_receipt_names_actor_and_kind() {
let repo = GitRepo::new();
let out = pointbreak_env(
[
"identity",
"attest",
"actor:git-email:kevin@swiber.dev",
"--kind",
"human",
"--role",
"author",
"--repo",
repo.path().to_str().unwrap(),
"--format",
"text",
],
&[],
);
assert!(
out.status.success(),
"stderr:\n{}",
String::from_utf8_lossy(&out.stderr)
);
let stdout = String::from_utf8(out.stdout).unwrap();
assert!(
!stdout.contains("\"schema\""),
"text lane is not JSON: {stdout}"
);
assert!(stdout.contains("attributes"), "receipt noun: {stdout}");
assert!(
stdout.contains("actor:git-email:kevin@swiber.dev"),
"actor named: {stdout}"
);
assert!(stdout.contains("human"), "kind: {stdout}");
assert!(stdout.contains("author"), "roles: {stdout}");
}