use assert_cmd::Command;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::process::Command as StdCommand;
type TestResult = Result<(), Box<dyn std::error::Error>>;
const MANIFEST: &str = r#"
version = 1
canonical = "json-schema-2020-12"
authoring = "zod"
[[contracts]]
name = "user"
source = "contracts/user.zod.ts"
emit = ["zod"]
[[mappings]]
glob = "app/api/**/*.ts"
contracts = ["user"]
require = "boundary-validation"
[gates]
protected_paths = ["pushkin.toml"]
"#;
const CONTRACT: &str = "import { z } from \"zod\";\n\
export const UserCreateSchema = z.object({ name: z.string() });\n\
export type UserCreate = z.infer<typeof UserCreateSchema>;\n";
const VIOLATION: &str = "export async function POST(req: Request) {\n \
const body = await req.json();\n \
return Response.json({ name: body.name });\n}\n";
const COMPLIANT: &str = "import { UserCreateSchema } from \"../../../contracts/user.zod\";\n\n\
export async function POST(req: Request) {\n \
const body = UserCreateSchema.parse(await req.json());\n \
return Response.json(body);\n}\n";
const SHIM: &str = ".git/hooks/pre-commit";
fn git(root: &Path, args: &[&str]) -> Result<(), Box<dyn std::error::Error>> {
let status = StdCommand::new("git")
.current_dir(root)
.args(args)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()?;
if !status.success() {
return Err(format!("git {args:?} failed").into());
}
Ok(())
}
fn binary_dir() -> Result<String, Box<dyn std::error::Error>> {
Ok(Path::new(env!("CARGO_BIN_EXE_pushkin"))
.parent()
.ok_or("binary under test has no parent")?
.to_string_lossy()
.into_owned())
}
fn staged_repo(handler: &str) -> Result<tempfile::TempDir, Box<dyn std::error::Error>> {
let dir = tempfile::tempdir()?;
let root = dir.path();
fs::write(root.join("pushkin.toml"), MANIFEST)?;
fs::create_dir_all(root.join("contracts"))?;
fs::create_dir_all(root.join("app/api/users"))?;
fs::write(root.join("contracts/user.zod.ts"), CONTRACT)?;
fs::write(root.join("app/api/users/route.ts"), handler)?;
git(root, &["init", "-q", "."])?;
git(root, &["add", "-A"])?;
Ok(dir)
}
fn run(dir: &Path, args: &[&str]) -> Result<(Option<i32>, String), Box<dyn std::error::Error>> {
let output = Command::cargo_bin("pushkin")?
.current_dir(dir)
.env("PATH", provisioned_path()?)
.env("HERMES_HOME", dir.join(".hermes-home"))
.args(args)
.output()?;
Ok((
output.status.code(),
format!(
"{}{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
),
))
}
fn commit(dir: &Path, path: &str) -> Result<(bool, String), Box<dyn std::error::Error>> {
let output = StdCommand::new("git")
.current_dir(dir)
.env("PATH", path)
.args([
"-c",
"user.name=Shim Suite",
"-c",
"user.email=shim@test",
"commit",
"-qm",
"through the shim",
])
.output()?;
Ok((
output.status.success(),
format!(
"{}{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
),
))
}
fn provisioned_path() -> Result<String, Box<dyn std::error::Error>> {
Ok(format!("{}:/usr/bin:/bin", binary_dir()?))
}
#[test]
fn install_writes_an_executable_guarded_shim() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
let (code, output) = run(dir.path(), &["init", "--agent", "git"])?;
assert_eq!(code, Some(0), "install must succeed: {output}");
let shim = fs::read_to_string(dir.path().join(SHIM))?;
assert!(
shim.starts_with("#!/bin/sh"),
"a hook is a shell script: {shim}"
);
assert!(
shim.contains("GENERATED by pushkin init"),
"the shim is marked as pushkin-owned: {shim}"
);
assert!(
shim.contains("command -v pushkin") && shim.contains("exec pushkin check --staged --json"),
"the shim carries the N13 guard around the spec command: {shim}"
);
for forbidden in ["$?", "case ", "-eq 1", "-eq 2", "elif"] {
assert!(
!shim.contains(forbidden),
"no exit-code case analysis in the guard ({forbidden:?}): {shim}"
);
}
let mode = fs::metadata(dir.path().join(SHIM))?.permissions().mode();
assert_eq!(mode & 0o111, 0o111, "the shim must be executable: {mode:o}");
Ok(())
}
#[test]
fn install_outside_a_git_repo_refuses_with_a_named_reason() -> TestResult {
let dir = tempfile::tempdir()?;
fs::write(dir.path().join("pushkin.toml"), MANIFEST)?;
let (code, output) = run(dir.path(), &["init", "--agent", "git"])?;
assert_ne!(code, Some(0), "no git repo, no shim: {output}");
assert!(
output.contains("not a git repository"),
"the refusal names the reason: {output}"
);
Ok(())
}
#[test]
fn a_foreign_hook_is_never_clobbered() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
let foreign = "#!/bin/sh\necho custom hook\n";
fs::create_dir_all(dir.path().join(".git/hooks"))?;
fs::write(dir.path().join(SHIM), foreign)?;
let (code, output) = run(dir.path(), &["init", "--agent", "git"])?;
assert_eq!(
code,
Some(0),
"detect-don't-clobber is not an error: {output}"
);
assert_eq!(
fs::read_to_string(dir.path().join(SHIM))?,
foreign,
"the existing hook is the user's and must survive byte-identical"
);
assert!(
output.contains("pushkin check --staged --json"),
"the integration snippet names the command to add: {output}"
);
Ok(())
}
#[test]
fn a_hooks_path_override_defers_to_the_manager() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
git(dir.path(), &["config", "core.hooksPath", ".husky"])?;
let (code, output) = run(dir.path(), &["init", "--agent", "git"])?;
assert_eq!(code, Some(0), "deferring is not an error: {output}");
assert!(
!dir.path().join(SHIM).exists(),
"hooks are owned elsewhere; nothing may be written: {output}"
);
assert!(
output.contains("core.hooksPath"),
"the deferral names what owns the hooks: {output}"
);
Ok(())
}
#[test]
fn reinstall_is_idempotent() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
run(dir.path(), &["init", "--agent", "git"])?;
let first = fs::read_to_string(dir.path().join(SHIM))?;
run(dir.path(), &["init", "--agent", "git"])?;
let second = fs::read_to_string(dir.path().join(SHIM))?;
assert_eq!(first, second, "a second install is a byte-level no-op");
Ok(())
}
#[test]
fn remove_deletes_a_pushkin_shim() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
run(dir.path(), &["init", "--agent", "git"])?;
let (code, output) = run(dir.path(), &["init", "--remove-agent", "git"])?;
assert_eq!(code, Some(0), "remove must succeed: {output}");
assert!(
!dir.path().join(SHIM).exists(),
"a pushkin-owned shim is removed entirely"
);
Ok(())
}
#[test]
fn remove_leaves_a_foreign_hook_alone() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
let foreign = "#!/bin/sh\necho custom hook\n";
fs::create_dir_all(dir.path().join(".git/hooks"))?;
fs::write(dir.path().join(SHIM), foreign)?;
let (code, output) = run(dir.path(), &["init", "--remove-agent", "git"])?;
assert_eq!(
code,
Some(0),
"remove on a foreign hook is a no-op: {output}"
);
assert_eq!(
fs::read_to_string(dir.path().join(SHIM))?,
foreign,
"the foreign hook survives byte-identical"
);
Ok(())
}
#[test]
fn a_staged_violation_blocks_the_commit_through_the_shim() -> TestResult {
let dir = staged_repo(VIOLATION)?;
run(dir.path(), &["init", "--agent", "git"])?;
git(dir.path(), &["add", "-A"])?;
let (ok, output) = commit(dir.path(), &provisioned_path()?)?;
assert!(
!ok,
"a provisioned commit with a staged violation must be blocked: {output}"
);
Ok(())
}
#[test]
fn a_compliant_tree_commits_through_the_shim() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
run(dir.path(), &["init", "--agent", "git"])?;
git(dir.path(), &["add", "-A"])?;
let (ok, output) = commit(dir.path(), &provisioned_path()?)?;
assert!(ok, "a compliant staged tree must commit: {output}");
Ok(())
}
#[test]
fn an_unprovisioned_commit_fails_open_with_the_notice() -> TestResult {
let dir = staged_repo(VIOLATION)?;
run(dir.path(), &["init", "--agent", "git"])?;
git(dir.path(), &["add", "-A"])?;
let (ok, output) = commit(dir.path(), "/usr/bin:/bin")?;
assert!(
ok,
"an unprovisioned teammate's commit must NOT be blocked: {output}"
);
assert!(
output.contains("failing open") && output.contains("cargo install pushkin"),
"the notice reaches the developer with the actionable hint: {output}"
);
Ok(())
}
#[test]
fn doctor_stays_healthy_when_no_shim_is_installed() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
run(dir.path(), &["init", "--agent", "claude"])?;
let (_, output) = run(dir.path(), &["doctor"])?;
assert!(
output.contains("hooks healthy"),
"an absent shim is never a finding (presence-keyed): {output}"
);
Ok(())
}
#[test]
fn doctor_flags_a_non_executable_shim_and_repair_restores_it() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
run(dir.path(), &["init", "--agent", "claude"])?;
run(dir.path(), &["init", "--agent", "git"])?;
let shim = dir.path().join(SHIM);
fs::set_permissions(&shim, fs::Permissions::from_mode(0o644))?;
let (code, output) = run(dir.path(), &["doctor"])?;
assert_eq!(code, Some(1), "a dead hook is a red finding: {output}");
assert!(
output.contains("executable"),
"the finding names the lost executable bit: {output}"
);
run(dir.path(), &["doctor", "--repair"])?;
let mode = fs::metadata(&shim)?.permissions().mode();
assert_eq!(mode & 0o111, 0o111, "repair restores the bit: {mode:o}");
let (_, after) = run(dir.path(), &["doctor"])?;
assert!(
after.contains("hooks healthy"),
"the finding clears: {after}"
);
Ok(())
}
#[test]
fn doctor_reports_a_foreign_hook_as_not_ours_and_repair_leaves_it() -> TestResult {
let dir = staged_repo(COMPLIANT)?;
run(dir.path(), &["init", "--agent", "claude"])?;
let foreign = "#!/bin/sh\necho custom hook\n";
fs::create_dir_all(dir.path().join(".git/hooks"))?;
fs::write(dir.path().join(SHIM), foreign)?;
let (_, output) = run(dir.path(), &["doctor"])?;
assert!(
output.contains("hooks healthy"),
"a foreign hook is not ours to flag: {output}"
);
run(dir.path(), &["doctor", "--repair"])?;
assert_eq!(
fs::read_to_string(dir.path().join(SHIM))?,
foreign,
"repair never rewrites a hook pushkin does not own"
);
Ok(())
}