use std::{
path::Path,
process::{Command, Output},
};
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
const ENTIRE_CHECKPOINTS_V1_REF: &str = "entire/checkpoints/v1";
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct EntireCheckpointRef {
pub ref_name: String,
pub object_sha: String,
}
pub fn entire_checkpoint_for_commit(
repo_root: &Path,
commit_sha: &str,
) -> Option<EntireCheckpointRef> {
let commit_sha = commit_sha.trim();
if !looks_like_commit_sha(commit_sha) {
return None;
}
let commit_object = git_stdout(
repo_root,
&[
"rev-parse",
"--verify",
"--quiet",
"--end-of-options",
&format!("{commit_sha}^{{commit}}"),
],
)
.ok()?;
let message = git_stdout(
repo_root,
&["show", "-s", "--format=%B", "--end-of-options", commit_sha],
)
.ok()?;
let checkpoint = entire_checkpoint_trailer(&message)?;
resolve_entire_checkpoint(repo_root, checkpoint, commit_object.trim())
.ok()
.flatten()
}
fn looks_like_commit_sha(value: &str) -> bool {
let value = value.trim();
(6..=64).contains(&value.len()) && value.chars().all(|character| character.is_ascii_hexdigit())
}
fn resolve_entire_checkpoint(
repo_root: &Path,
checkpoint: &str,
commit_object: &str,
) -> Result<Option<EntireCheckpointRef>> {
if let Some(checkpoint_id) = normalize_entire_checkpoint_id(checkpoint) {
return resolve_entire_checkpoint_id(repo_root, &checkpoint_id);
}
let Some(ref_name) = normalize_entire_ref(checkpoint) else {
return Ok(None);
};
resolve_legacy_entire_ref(repo_root, &ref_name, commit_object)
}
fn resolve_entire_checkpoint_id(
repo_root: &Path,
checkpoint_id: &str,
) -> Result<Option<EntireCheckpointRef>> {
let full_ref = format!("refs/heads/{ENTIRE_CHECKPOINTS_V1_REF}");
let output = git_output(
repo_root,
&[
"rev-parse",
"--verify",
"--quiet",
"--end-of-options",
&format!("{full_ref}^{{commit}}"),
],
)?;
if !output.status.success() {
return Ok(None);
}
if !checkpoint_metadata_mentions_id(repo_root, checkpoint_id, &full_ref)? {
return Ok(None);
}
let object_sha = String::from_utf8_lossy(&output.stdout).trim().to_owned();
if object_sha.is_empty() {
return Ok(None);
}
Ok(Some(EntireCheckpointRef {
ref_name: ENTIRE_CHECKPOINTS_V1_REF.to_owned(),
object_sha,
}))
}
fn checkpoint_metadata_mentions_id(
repo_root: &Path,
checkpoint_id: &str,
full_ref: &str,
) -> Result<bool> {
let output = git_output(
repo_root,
&["grep", "-F", "--quiet", checkpoint_id, full_ref, "--", "."],
)?;
if output.status.success() {
return Ok(true);
}
if output.status.code() == Some(1) {
return Ok(false);
}
anyhow::bail!(
"git grep Entire checkpoint metadata failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
fn resolve_legacy_entire_ref(
repo_root: &Path,
ref_name: &str,
commit_object: &str,
) -> Result<Option<EntireCheckpointRef>> {
let full_ref = format!("refs/heads/{ref_name}");
let output = git_output(
repo_root,
&[
"rev-parse",
"--verify",
"--quiet",
"--end-of-options",
&format!("{full_ref}^{{commit}}"),
],
)?;
if !output.status.success() {
return Ok(None);
}
let checkpoint = EntireCheckpointRef {
ref_name: ref_name.to_owned(),
object_sha: String::from_utf8_lossy(&output.stdout).trim().to_owned(),
};
Ok((checkpoint.object_sha == commit_object).then_some(checkpoint))
}
fn entire_checkpoint_trailer(message: &str) -> Option<&str> {
let lines = message.lines().collect::<Vec<_>>();
let end = lines
.iter()
.rposition(|line| !line.trim().is_empty())
.map(|index| index + 1)?;
let start = lines[..end]
.iter()
.rposition(|line| line.trim().is_empty())
.map_or(0, |index| index + 1);
lines[start..end]
.iter()
.rev()
.find_map(|line| {
let (name, value) = line.split_once(':')?;
name.trim()
.eq_ignore_ascii_case("Entire-Checkpoint")
.then(|| value.trim())
})
.filter(|value| !value.is_empty())
}
fn normalize_entire_checkpoint_id(value: &str) -> Option<String> {
let value = value.trim();
(value.len() == 12 && value.chars().all(|character| character.is_ascii_hexdigit()))
.then(|| value.to_ascii_lowercase())
}
fn normalize_entire_ref(value: &str) -> Option<String> {
let value = value.trim();
if value.is_empty()
|| value.contains("..")
|| value.chars().any(|character| {
character.is_whitespace() || matches!(character, '~' | '^' | ':' | '@')
})
{
return None;
}
if let Some(short) = value.strip_prefix("refs/heads/") {
return short.starts_with("entire/").then(|| short.to_owned());
}
value.starts_with("entire/").then(|| value.to_owned())
}
fn git_stdout(repo_root: &Path, args: &[&str]) -> Result<String> {
let output = git_output(repo_root, args)?;
if !output.status.success() {
anyhow::bail!(
"git {} failed: {}",
args.join(" "),
String::from_utf8_lossy(&output.stderr)
);
}
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}
fn git_output(repo_root: &Path, args: &[&str]) -> Result<Output> {
Command::new("git")
.args(args)
.current_dir(repo_root)
.output()
.context("failed to run git for Entire provenance")
}
#[cfg(test)]
mod tests {
use std::{fs, path::Path, process::Command};
use super::{
ENTIRE_CHECKPOINTS_V1_REF, entire_checkpoint_for_commit, entire_checkpoint_trailer,
looks_like_commit_sha, normalize_entire_checkpoint_id, normalize_entire_ref,
};
fn git(repo: &Path, args: &[&str]) {
let status = Command::new("git")
.args(args)
.current_dir(repo)
.status()
.unwrap();
assert!(status.success(), "git {args:?} failed");
}
fn git_stdout(repo: &Path, args: &[&str]) -> String {
let output = Command::new("git")
.args(args)
.current_dir(repo)
.output()
.unwrap();
assert!(output.status.success(), "git {args:?} failed");
String::from_utf8(output.stdout).unwrap().trim().to_owned()
}
fn init_test_repo(repo: &Path) {
git(repo, &["init"]);
git(repo, &["config", "commit.gpgsign", "false"]);
git(repo, &["config", "user.email", "truth@example.invalid"]);
git(repo, &["config", "user.name", "Truth Mirror Test"]);
}
fn write_checkpoint_metadata(repo: &Path, checkpoint_id: &str) {
let path = repo
.join(".entire/checkpoints")
.join(format!("{checkpoint_id}.json"));
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, format!(r#"{{"id":"{checkpoint_id}"}}"#)).unwrap();
}
#[test]
fn parses_explicit_entire_checkpoint_trailer() {
let trailer = entire_checkpoint_trailer(
"feat: work\n\nCLAIM: done | verified: cargo test | evidence: tests:x\nEntire-Checkpoint: a1b2c3d4e5f6\n",
);
assert_eq!(trailer, Some("a1b2c3d4e5f6"));
}
#[test]
fn ignores_entire_checkpoint_outside_final_trailer_block() {
let trailer = entire_checkpoint_trailer(
"feat: work\n\nThe body mentions:\nEntire-Checkpoint: entire/body-only\n\nCLAIM: done | verified: cargo test | evidence: tests:x\n",
);
assert_eq!(trailer, None);
}
#[test]
fn normalizes_only_entire_refs() {
assert_eq!(
normalize_entire_ref("refs/heads/entire/session-abcdef"),
Some("entire/session-abcdef".to_owned())
);
assert_eq!(
normalize_entire_ref("entire/session-abcdef"),
Some("entire/session-abcdef".to_owned())
);
assert_eq!(normalize_entire_ref("main"), None);
assert_eq!(normalize_entire_ref("entire/session:bad"), None);
assert_eq!(normalize_entire_ref("entire/@{-1}"), None);
}
#[test]
fn normalizes_entire_checkpoint_ids() {
assert_eq!(
normalize_entire_checkpoint_id("A1B2C3D4E5F6"),
Some("a1b2c3d4e5f6".to_owned())
);
assert_eq!(normalize_entire_checkpoint_id("a1b2c3"), None);
assert_eq!(normalize_entire_checkpoint_id("a1b2c3d4e5fx"), None);
assert_eq!(
normalize_entire_checkpoint_id("entire/session-abcdef"),
None
);
}
#[test]
fn rejects_non_sha_commit_values_before_git_lookup() {
assert!(!looks_like_commit_sha("--all"));
assert!(!looks_like_commit_sha("HEAD"));
assert!(!looks_like_commit_sha("abc12"));
assert!(looks_like_commit_sha("abcdef1234567890"));
let sha256 = "a".repeat(64);
let too_long = "a".repeat(65);
assert!(looks_like_commit_sha(&sha256));
assert!(!looks_like_commit_sha(&too_long));
}
#[test]
fn resolves_entire_checkpoint_id_from_metadata_ref() {
let temp = tempfile::tempdir().unwrap();
let repo = temp.path().join("repo");
fs::create_dir(&repo).unwrap();
init_test_repo(&repo);
fs::write(repo.join("file.txt"), "hello\n").unwrap();
write_checkpoint_metadata(&repo, "a1b2c3d4e5f6");
git(&repo, &["add", "file.txt"]);
git(
&repo,
&["add", "-f", ".entire/checkpoints/a1b2c3d4e5f6.json"],
);
git(
&repo,
&[
"commit",
"-m",
"feat: base",
"-m",
"CLAIM: base | verified: cargo test | evidence: tests:provenance\n\nEntire-Checkpoint: a1b2c3d4e5f6",
],
);
let commit = git_stdout(&repo, &["rev-parse", "HEAD"]);
git(
&repo,
&[
"update-ref",
&format!("refs/heads/{ENTIRE_CHECKPOINTS_V1_REF}"),
"HEAD",
],
);
let checkpoint = entire_checkpoint_for_commit(&repo, &commit).unwrap();
assert_eq!(checkpoint.ref_name, ENTIRE_CHECKPOINTS_V1_REF);
assert_eq!(checkpoint.object_sha, commit);
}
#[test]
fn resolves_legacy_entire_ref_from_commit_trailer() {
let temp = tempfile::tempdir().unwrap();
let repo = temp.path().join("repo");
fs::create_dir(&repo).unwrap();
init_test_repo(&repo);
fs::write(repo.join("file.txt"), "hello\n").unwrap();
git(&repo, &["add", "file.txt"]);
git(
&repo,
&[
"commit",
"-m",
"feat: base",
"-m",
"CLAIM: base | verified: cargo test | evidence: tests:provenance\n\nEntire-Checkpoint: entire/session-abcdef",
],
);
let commit = git_stdout(&repo, &["rev-parse", "HEAD"]);
git(
&repo,
&["update-ref", "refs/heads/entire/session-abcdef", "HEAD"],
);
let checkpoint = entire_checkpoint_for_commit(&repo, &commit).unwrap();
assert_eq!(checkpoint.ref_name, "entire/session-abcdef");
assert_eq!(checkpoint.object_sha, commit);
}
#[test]
fn missing_entire_ref_for_trailer_returns_none() {
let temp = tempfile::tempdir().unwrap();
let repo = temp.path().join("repo");
fs::create_dir(&repo).unwrap();
init_test_repo(&repo);
fs::write(repo.join("file.txt"), "hello\n").unwrap();
git(&repo, &["add", "file.txt"]);
git(
&repo,
&[
"commit",
"-m",
"feat: base",
"-m",
"CLAIM: base | verified: cargo test | evidence: tests:provenance\n\nEntire-Checkpoint: a1b2c3d4e5f6",
],
);
let commit = git_stdout(&repo, &["rev-parse", "HEAD"]);
assert_eq!(
entire_checkpoint_for_commit(&repo, &format!(" {commit}\n")),
None
);
}
#[test]
fn checkpoint_id_missing_from_metadata_returns_none() {
let temp = tempfile::tempdir().unwrap();
let repo = temp.path().join("repo");
fs::create_dir(&repo).unwrap();
init_test_repo(&repo);
fs::write(repo.join("file.txt"), "hello\n").unwrap();
git(&repo, &["add", "file.txt"]);
git(
&repo,
&[
"commit",
"-m",
"feat: base",
"-m",
"CLAIM: base | verified: cargo test | evidence: tests:provenance\n\nEntire-Checkpoint: a1b2c3d4e5f6",
],
);
let commit = git_stdout(&repo, &["rev-parse", "HEAD"]);
git(
&repo,
&[
"update-ref",
&format!("refs/heads/{ENTIRE_CHECKPOINTS_V1_REF}"),
"HEAD",
],
);
assert_eq!(entire_checkpoint_for_commit(&repo, &commit), None);
}
#[test]
fn stale_entire_ref_for_trailer_returns_none() {
let temp = tempfile::tempdir().unwrap();
let repo = temp.path().join("repo");
fs::create_dir(&repo).unwrap();
init_test_repo(&repo);
fs::write(repo.join("file.txt"), "base\n").unwrap();
git(&repo, &["add", "file.txt"]);
git(
&repo,
&[
"commit",
"-m",
"feat: base",
"-m",
"CLAIM: base | verified: cargo test | evidence: tests:provenance",
],
);
let stale_commit = git_stdout(&repo, &["rev-parse", "HEAD"]);
git(
&repo,
&[
"update-ref",
"refs/heads/entire/session-stale",
&stale_commit,
],
);
fs::write(repo.join("file.txt"), "next\n").unwrap();
git(&repo, &["add", "file.txt"]);
git(
&repo,
&[
"commit",
"-m",
"feat: next",
"-m",
"CLAIM: next | verified: cargo test | evidence: tests:provenance\n\nEntire-Checkpoint: entire/session-stale",
],
);
let reviewed_commit = git_stdout(&repo, &["rev-parse", "HEAD"]);
assert_eq!(entire_checkpoint_for_commit(&repo, &reviewed_commit), None);
}
}