use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::process::Command;
use joeira_core::shell::AmbienteShell;
use joeira_core::{Ponto, Regra, Veredito, avalia};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Balde {
Concorda,
Discorda,
Omitido,
Cego,
Triado,
}
#[derive(Debug, Clone)]
pub struct Linha {
pub commit: String,
pub regra: String,
pub balde: Balde,
pub joeira_recusa: Option<bool>,
pub incumbente_recusa: Option<bool>,
pub causa: Option<&'static str>,
}
const ATRIBUICAO: &[(&str, &str)] = &[
("credential material", "sec-plaintext-credential"),
("gen delta tie", "gen-lock-tie"),
("merge-conflict markers", "vcs-conflict-markers"),
("placeholder subject", "msg-placeholder-subject"),
];
const SEM_CONTRAPARTE: &[(&str, &str)] = &[(
"msg-ai-attribution-trailer",
"the incumbent REWRITES the trailer (stripCoAuthored) rather than refusing \
it, so there is no refusal to compare against",
)];
fn triagem(dir: &Path, regra: &str, joeira: bool, incumbente: bool) -> Option<&'static str> {
if joeira && !incumbente && regra.starts_with("sec-") {
let nomeia_marcador = git(
dir,
&["diff", "--cached", "--name-only", "--diff-filter=ACMR"],
)
.ok()?
.lines()
.any(|p| {
git(dir, &["show", &format!(":{p}")])
.map(|t| {
t.contains("ENC[AES256_GCM")
&& !t.lines().any(|l| {
l.contains(": ENC[AES256_GCM,data:") || l.trim_start() == "sops:"
})
})
.unwrap_or(false)
});
if nomeia_marcador {
return Some(
"incumbent SOPS-exemption bypass: a staged blob NAMES \
ENC[AES256_GCM without carrying one in value position, and the \
incumbent's string-contains? predicate exempted the whole file \
from every credential rule. Fixed at the cause in blackmatter; \
this attribution stops matching once the fixed hook deploys.",
);
}
}
None
}
fn git(dir: &Path, args: &[&str]) -> anyhow::Result<String> {
let saida = Command::new("git")
.current_dir(dir)
.args(args)
.output()
.map_err(|e| anyhow::anyhow!("running git {args:?} in {}: {e}", dir.display()))?;
anyhow::ensure!(
saida.status.success(),
"git {args:?} in {} exited {:?}: {}",
dir.display(),
saida.status.code(),
String::from_utf8_lossy(&saida.stderr).trim()
);
Ok(String::from_utf8_lossy(&saida.stdout).into_owned())
}
fn roda_incumbente(
dir: &Path,
gancho: &Path,
arg: Option<&Path>,
) -> anyhow::Result<(bool, String)> {
anyhow::ensure!(
gancho.exists(),
"the deployed hook {} is absent — refusing to report agreement against \
a hook that does not run",
gancho.display()
);
let mut cmd = Command::new(gancho);
cmd.current_dir(dir);
if let Some(a) = arg {
cmd.arg(a);
}
let saida = cmd
.output()
.map_err(|e| anyhow::anyhow!("running {}: {e}", gancho.display()))?;
let mut texto = String::from_utf8_lossy(&saida.stderr).into_owned();
texto.push_str(&String::from_utf8_lossy(&saida.stdout));
Ok((!saida.status.success(), texto))
}
fn prepara(repo: &Path, scratch: &Path) -> anyhow::Result<PathBuf> {
if scratch.exists() {
std::fs::remove_dir_all(scratch)?;
}
git(
Path::new("."),
&[
"clone",
"--quiet",
"--shared",
"--no-checkout",
repo.to_str()
.ok_or_else(|| anyhow::anyhow!("non-utf8 repo path"))?,
scratch
.to_str()
.ok_or_else(|| anyhow::anyhow!("non-utf8 scratch path"))?,
],
)?;
git(scratch, &["config", "core.hooksPath", "/dev/null"])?;
Ok(scratch.to_path_buf())
}
fn encena(scratch: &Path, commit: &str) -> anyhow::Result<bool> {
let pais = git(scratch, &["rev-list", "--parents", "-n", "1", commit])?;
if pais.split_whitespace().count() < 2 {
return Ok(false);
}
let pai = format!("{commit}^");
git(scratch, &["update-ref", "HEAD", &pai])?;
git(scratch, &["read-tree", commit])?;
Ok(true)
}
fn calibra(regras: &[Regra]) -> anyhow::Result<()> {
let dir = std::env::temp_dir().join("joeira-calibracao");
if dir.exists() {
std::fs::remove_dir_all(&dir)?;
}
std::fs::create_dir_all(&dir)?;
git(&dir, &["init", "--quiet", "."])?;
git(&dir, &["config", "user.email", "oraculo@joeira"])?;
git(&dir, &["config", "user.name", "oraculo"])?;
git(&dir, &["config", "core.hooksPath", "/dev/null"])?;
let hooks = dirs_hooks()?;
std::fs::write(
dir.join("a.txt"),
"ordinary content
",
)?;
git(&dir, &["add", "a.txt"])?;
git(
&dir,
&["commit", "--quiet", "-m", "calibration: a clean commit"],
)?;
std::fs::write(
dir.join("b.txt"),
"<<<<<<< HEAD\nmine\n=======\ntheirs\n>>>>>>> other\n",
)?;
git(&dir, &["add", "b.txt"])?;
let (inc_recusa, texto) = roda_incumbente(&dir, &hooks.join("pre-commit"), None)?;
anyhow::ensure!(
inc_recusa && texto.contains("merge-conflict markers"),
"CALIBRATION FAILED: the deployed pre-commit hook did not refuse a \
staged conflict-marker pair. The harness cannot see, so no agreement \
it reports means anything. hook said: {}",
texto.trim()
);
let amb = AmbienteShell::novo(&dir);
let regra = regras
.iter()
.find(|r| r.nome() == "vcs-conflict-markers")
.ok_or_else(|| {
anyhow::anyhow!("the corpus has no vcs-conflict-markers rule to calibrate")
})?;
match avalia(regra, &amb) {
Veredito::Achado { .. } => {}
outro => anyhow::bail!(
"CALIBRATION FAILED: joeira did not refuse a staged conflict-marker \
pair, it returned {outro:?}. Every `pass` in the run below would be \
unfalsifiable."
),
}
git(&dir, &["reset", "--quiet", "HEAD", "--", "b.txt"])?;
std::fs::remove_file(dir.join("b.txt"))?;
let amb_limpo = AmbienteShell::novo(&dir);
match avalia(regra, &amb_limpo) {
Veredito::Limpo { .. } | Veredito::NaoSeAplica { .. } => {}
outro => anyhow::bail!(
"CALIBRATION FAILED: joeira refused a CLEAN tree ({outro:?}) — the \
rule fires unconditionally, so the positive control above proved \
nothing."
),
}
println!("calibration: both engines refuse a planted conflict marker and pass a clean tree");
Ok(())
}
pub fn corre(repo: &Path, n: usize, regras: &[Regra]) -> anyhow::Result<Vec<Linha>> {
calibra(regras)?;
let scratch = std::env::temp_dir().join("joeira-oraculo");
let scratch = prepara(repo, &scratch)?;
let hooks = dirs_hooks()?;
let commits: Vec<String> = git(
repo,
&["log", "--no-merges", "--format=%H", "-n", &n.to_string()],
)?
.lines()
.map(str::to_owned)
.collect();
anyhow::ensure!(
!commits.is_empty(),
"no non-merge commits found in {} — refusing to report agreement over \
an empty denominator",
repo.display()
);
let mut linhas = Vec::new();
for c in &commits {
let msg = git(repo, &["log", "-1", "--format=%B", c])?;
if !encena(&scratch, c)? {
for r in regras {
linhas.push(Linha {
commit: c.clone(),
regra: r.nome().to_owned(),
balde: Balde::Omitido,
joeira_recusa: None,
incumbente_recusa: None,
causa: Some("root commit — no parent, so no author ever saw this state"),
});
}
continue;
}
let (_, pre) = roda_incumbente(&scratch, &hooks.join("pre-commit"), None)?;
let msg_path = scratch.join("COMMIT_EDITMSG_oraculo");
std::fs::write(&msg_path, &msg)?;
let (_, cm) = roda_incumbente(&scratch, &hooks.join("commit-msg"), Some(&msg_path))?;
let texto = format!("{pre}{cm}");
let amb = AmbienteShell::novo(&scratch);
for r in regras {
if let Some((_, porque)) = SEM_CONTRAPARTE.iter().find(|(n, _)| *n == r.nome()) {
linhas.push(Linha {
commit: c.clone(),
regra: r.nome().to_owned(),
balde: Balde::Omitido,
joeira_recusa: None,
incumbente_recusa: None,
causa: Some(porque),
});
continue;
}
let v = match r.ponto() {
Ponto::CommitMsg => avalia(r, &AmbienteShell::novo(&scratch).com_mensagem(&msg)),
_ => avalia(r, &amb),
};
let (balde, jr) = match &v {
Veredito::Cego { .. } => (Balde::Cego, None),
Veredito::NaoSeAplica { .. } => (Balde::Concorda, Some(false)),
Veredito::Achado { .. } => (Balde::Concorda, Some(true)),
Veredito::Limpo { .. } => (Balde::Concorda, Some(false)),
};
let ir = ATRIBUICAO
.iter()
.find(|(_, nome)| *nome == r.nome())
.map(|(marca, _)| texto.contains(marca));
let (balde, causa) = match (balde, jr, ir) {
(Balde::Cego, _, _) => (
Balde::Cego,
Some("joeira's environment could not answer — never counted as a match"),
),
(_, _, None) => (
Balde::Omitido,
Some("no incumbent message attributes to this rule"),
),
(_, Some(j), Some(i)) if j == i => (Balde::Concorda, None),
(_, Some(j), Some(i)) => match triagem(&scratch, r.nome(), j, i) {
Some(porque) => (Balde::Triado, Some(porque)),
None => (Balde::Discorda, None),
},
_ => (Balde::Discorda, None),
};
linhas.push(Linha {
commit: c.clone(),
regra: r.nome().to_owned(),
balde,
joeira_recusa: jr,
incumbente_recusa: ir,
causa,
});
}
}
Ok(linhas)
}
fn dirs_hooks() -> anyhow::Result<PathBuf> {
let home = std::env::var("HOME").map_err(|_| anyhow::anyhow!("HOME is unset"))?;
let p = PathBuf::from(home).join(".config/git/hooks");
anyhow::ensure!(
p.is_dir(),
"no deployed hooks at {} — the oracle compares against what RUNS, not \
against the Nix source, so there is nothing to compare",
p.display()
);
Ok(p)
}
pub fn relata(linhas: &[Linha]) -> anyhow::Result<()> {
let mut contagem: BTreeMap<Balde, usize> = BTreeMap::new();
for l in linhas {
*contagem.entry(l.balde).or_default() += 1;
}
let total = linhas.len();
for l in linhas.iter().filter(|l| l.balde == Balde::Discorda) {
println!(
" DISAGREE {} {:<28} joeira={:?} incumbent={:?}{}",
&l.commit[..8.min(l.commit.len())],
l.regra,
l.joeira_recusa,
l.incumbente_recusa,
l.causa.map(|c| format!(" cause: {c}")).unwrap_or_default()
);
}
for l in linhas.iter().filter(|l| l.balde == Balde::Triado) {
println!(
" TRIAGED {} {:<28} joeira={:?} incumbent={:?}\n cause: {}",
&l.commit[..8.min(l.commit.len())],
l.regra,
l.joeira_recusa,
l.incumbente_recusa,
l.causa.unwrap_or("no cause recorded")
);
}
for l in linhas.iter().filter(|l| l.balde == Balde::Cego) {
println!(
" BLIND {} {:<28} {}",
&l.commit[..8.min(l.commit.len())],
l.regra,
l.causa.unwrap_or("no reason recorded")
);
}
let mut porques: BTreeMap<&str, usize> = BTreeMap::new();
for l in linhas.iter().filter(|l| l.balde == Balde::Omitido) {
*porques
.entry(l.causa.unwrap_or("no reason recorded"))
.or_default() += 1;
}
for (porque, n) in &porques {
println!(" omitted {n}: {porque}");
}
for (b, n) in &contagem {
println!(" {b:?} {n}/{total}");
}
println!(
"oracle: {} comparisons over {} rows",
contagem.get(&Balde::Concorda).copied().unwrap_or(0),
total
);
anyhow::ensure!(
total > 0,
"the oracle compared NOTHING — refusing to report agreement"
);
let d = contagem.get(&Balde::Discorda).copied().unwrap_or(0);
anyhow::ensure!(d == 0, "{d} un-triaged disagreements of {total}");
Ok(())
}