use crate::provider::ProviderId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Platform {
MacOs,
Linux,
Windows,
}
impl Platform {
const EACH: [Platform; 3] = [Platform::MacOs, Platform::Linux, Platform::Windows];
pub fn code(self) -> &'static str {
match self {
Platform::MacOs => "macos",
Platform::Linux => "linux",
Platform::Windows => "windows",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OnSystem {
Read(&'static str),
NotRead(&'static str),
Pending {
by: &'static [&'static str],
reads: &'static str,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PerSystem {
pub name: &'static str,
pub macos: OnSystem,
pub linux: OnSystem,
pub windows: OnSystem,
}
impl PerSystem {
pub fn on(&self, platform: Platform) -> OnSystem {
match platform {
Platform::MacOs => self.macos,
Platform::Linux => self.linux,
Platform::Windows => self.windows,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Assumption {
pub name: &'static str,
pub fact: &'static str,
pub read_from: &'static str,
pub verified_against: &'static str,
pub depends: &'static str,
pub probe: &'static [&'static str],
pub absent: &'static [&'static str],
}
pub fn of(provider: ProviderId) -> &'static [Assumption] {
match provider {
ProviderId::Claude => crate::provider::claude::assumptions::ASSUMPTIONS,
ProviderId::Codex => crate::provider::codex::assumptions::ASSUMPTIONS,
}
}
pub fn per_system(provider: ProviderId) -> &'static [PerSystem] {
match provider {
ProviderId::Claude => crate::provider::claude::assumptions::PER_SYSTEM,
ProviderId::Codex => crate::provider::codex::assumptions::PER_SYSTEM,
}
}
pub fn on(provider: ProviderId, name: &str, platform: Platform) -> Option<OnSystem> {
per_system(provider)
.iter()
.find(|line| line.name == name)
.map(|line| line.on(platform))
}
pub fn read_on(provider: ProviderId, name: &str) -> Vec<Platform> {
Platform::EACH
.into_iter()
.filter(|&platform| verified_on(provider, name, platform).is_some())
.collect()
}
pub fn verified_on(provider: ProviderId, name: &str, platform: Platform) -> Option<&'static str> {
match on(provider, name, platform)? {
OnSystem::Read(build) => Some(build),
OnSystem::NotRead(_) | OnSystem::Pending { .. } => None,
}
}
pub fn pending() -> Vec<(ProviderId, &'static str, Platform)> {
ProviderId::ALL
.iter()
.flat_map(|&provider| {
per_system(provider).iter().flat_map(move |line| {
Platform::EACH
.into_iter()
.filter(|&platform| matches!(line.on(platform), OnSystem::Pending { .. }))
.map(move |platform| (provider, line.name, platform))
})
})
.collect()
}
pub fn verified_against(provider: ProviderId, platform: Platform) -> &'static str {
use crate::provider::{claude, codex};
match (provider, platform) {
(ProviderId::Claude, Platform::MacOs | Platform::Linux) => {
claude::assumptions::VERIFIED_AGAINST
}
(ProviderId::Claude, Platform::Windows) => claude::assumptions::WINDOWS_VERIFIED_AGAINST,
(ProviderId::Codex, Platform::MacOs | Platform::Linux) => {
codex::assumptions::VERIFIED_AGAINST
}
(ProviderId::Codex, Platform::Windows) => codex::assumptions::WINDOWS_VERIFIED_AGAINST,
}
}
pub fn all() -> Vec<&'static Assumption> {
ProviderId::ALL.iter().flat_map(|&p| of(p)).collect()
}
pub fn named(name: &str) -> Option<&'static Assumption> {
all().into_iter().find(|a| a.name == name)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Reading {
Holds,
NotReadable,
Moved(Vec<&'static str>),
Appeared(Vec<&'static str>),
}
pub fn read_from_build(assumption: &Assumption, strings: &str) -> Reading {
let arrived: Vec<&'static str> = assumption
.absent
.iter()
.filter(|needle| strings.contains(**needle))
.copied()
.collect();
if !arrived.is_empty() {
return Reading::Appeared(arrived);
}
if assumption.probe.is_empty() {
return if assumption.absent.is_empty() {
Reading::NotReadable
} else {
Reading::Holds
};
}
let gone: Vec<&'static str> = assumption
.probe
.iter()
.filter(|needle| !strings.contains(**needle))
.copied()
.collect();
if gone.is_empty() {
Reading::Holds
} else {
Reading::Moved(gone)
}
}
pub fn printable_runs(bytes: &[u8], least: usize) -> String {
let mut out = String::new();
let mut run = Vec::new();
for &b in bytes {
if (0x20..0x7f).contains(&b) || b == b'\t' {
run.push(b);
continue;
}
if run.len() >= least {
out.push_str(&String::from_utf8_lossy(&run));
out.push('\n');
}
run.clear();
}
if run.len() >= least {
out.push_str(&String::from_utf8_lossy(&run));
out.push('\n');
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_keyring_arriving_where_there_was_none_is_reported() {
let no_keyring = named("no_keyring_off_macos").unwrap();
let backends = r#"tengu_windows_credman CLAUDE_CODE_FORCE_WINDOWS_CREDMAN ["keychain","plaintext","windows-credman"]"#;
assert_eq!(read_from_build(no_keyring, backends), Reading::Holds);
assert_eq!(
read_from_build(no_keyring, &format!("{backends} Bun.secrets.get")),
Reading::Appeared(vec!["Bun.secrets"])
);
}
#[test]
fn the_bundled_runtime_is_not_taken_for_a_keyring() {
let no_keyring = named("no_keyring_off_macos").unwrap();
assert!(!no_keyring.absent.contains(&"libsecret"));
let backends = r#"tengu_windows_credman CLAUDE_CODE_FORCE_WINDOWS_CREDMAN ["keychain","plaintext","windows-credman"]"#;
assert_eq!(
read_from_build(
no_keyring,
&format!("{backends} libsecret not available. libsecret-1.so.0")
),
Reading::Holds
);
}
#[test]
fn every_fact_is_read_from_some_build() {
for &provider in ProviderId::ALL {
for a in of(provider) {
assert!(
!read_on(provider, a.name).is_empty(),
"{} is read from no build",
a.name
);
}
}
}
#[test]
fn each_keychain_fact_is_read_where_the_keychain_code_is() {
for name in ["keychain_write_route", "keychain_absence_codes"] {
assert_eq!(
read_on(ProviderId::Claude, name),
[Platform::MacOs],
"{name}"
);
}
assert_eq!(
read_on(ProviderId::Claude, "no_keyring_off_macos"),
[Platform::Linux]
);
}
#[test]
fn every_fact_has_one_line_and_every_line_is_a_fact() {
for &provider in ProviderId::ALL {
let mut facts: Vec<&str> = of(provider).iter().map(|a| a.name).collect();
let mut lines: Vec<&str> = per_system(provider).iter().map(|l| l.name).collect();
facts.sort_unstable();
lines.sort_unstable();
let before = lines.len();
lines.dedup();
assert_eq!(lines.len(), before, "{provider:?}: a fact has two lines");
assert_eq!(lines, facts, "{provider:?}");
for a in of(provider) {
for platform in Platform::EACH {
assert!(on(provider, a.name, platform).is_some(), "{}", a.name);
}
}
}
}
#[test]
fn no_fact_ruling_out_bun_secrets_is_read_on_windows() {
for &provider in ProviderId::ALL {
for a in of(provider) {
if a.absent.contains(&"Bun.secrets") {
assert_eq!(
verified_on(provider, a.name, Platform::Windows),
None,
"{}",
a.name
);
assert!(
matches!(
on(provider, a.name, Platform::Windows),
Some(OnSystem::NotRead(_))
),
"{} must say why it is not read on Windows",
a.name
);
}
}
}
}
#[test]
fn every_pending_reading_names_a_pull_request_of_the_windows_work() {
for &provider in ProviderId::ALL {
for line in per_system(provider) {
for platform in Platform::EACH {
let OnSystem::Pending { by, reads } = line.on(platform) else {
continue;
};
assert_eq!(platform, Platform::Windows, "{}", line.name);
assert!(!by.is_empty(), "{} waits on nothing", line.name);
assert!(
!reads.is_empty(),
"{} says nothing of what is read",
line.name
);
for pr in by {
let number = pr.strip_prefix('W').and_then(|n| n.parse::<u32>().ok());
assert!(
matches!(number, Some(2..=27)),
"{}: `{pr}` is not a pull request of the Windows work",
line.name
);
}
}
}
}
}
#[test]
fn the_readings_still_to_come_are_listed() {
let waiting = pending();
assert!(waiting.iter().all(|&(_, _, p)| p == Platform::Windows));
for (provider, count) in [(ProviderId::Claude, 7), (ProviderId::Codex, 8)] {
let names: Vec<&str> = waiting
.iter()
.filter(|&&(p, _, _)| p == provider)
.map(|&(_, name, _)| name)
.collect();
assert_eq!(names.len(), count, "{provider:?}: {names:?}");
for name in names {
assert!(matches!(
on(provider, name, Platform::Windows),
Some(OnSystem::Pending { .. })
));
}
}
}
#[test]
fn the_field_names_the_build_of_the_macos_and_linux_readings() {
for &provider in ProviderId::ALL {
for a in of(provider) {
for platform in [Platform::MacOs, Platform::Linux] {
if let Some(build) = verified_on(provider, a.name, platform) {
assert_eq!(
build,
a.verified_against,
"{} on {}",
a.name,
platform.code()
);
}
}
}
}
}
#[test]
fn every_line_says_a_build_or_a_reason() {
for &provider in ProviderId::ALL {
for line in per_system(provider) {
for platform in Platform::EACH {
match line.on(platform) {
OnSystem::Read(build) => assert_eq!(
build.split('.').count(),
3,
"{} on {}: `{build}` is not a version",
line.name,
platform.code()
),
OnSystem::NotRead(why) => {
assert!(!why.is_empty(), "{} on {}", line.name, platform.code());
}
OnSystem::Pending { .. } => {}
}
}
}
}
}
#[test]
fn nothing_already_in_a_build_is_used_to_rule_a_backend_out() {
for a in all() {
for needle in a.absent {
assert!(
!["secret-tool", "kwallet-query", "keytar", "keyring"].contains(needle),
"{}: `{needle}` is in the build for other reasons",
a.name
);
assert!(
needle.len() >= 8,
"{}: `{needle}` is too short to mean one thing",
a.name
);
}
}
}
#[test]
fn a_fact_that_is_only_an_absence_still_reads() {
let only_absent = Assumption {
name: "x",
fact: "x",
read_from: "x",
verified_against: "9.9.9",
depends: "x",
probe: &[],
absent: &["a_thing_that_should_not_be_here"],
};
assert_eq!(
read_from_build(&only_absent, "nothing to see"),
Reading::Holds
);
assert_eq!(
read_from_build(&only_absent, "a_thing_that_should_not_be_here"),
Reading::Appeared(vec!["a_thing_that_should_not_be_here"])
);
}
#[test]
fn every_assumption_is_named_once_and_says_all_four_things() {
let mut names: Vec<&str> = all().iter().map(|a| a.name).collect();
let before = names.len();
names.sort_unstable();
names.dedup();
assert_eq!(names.len(), before, "two assumptions share a name");
for a in all() {
assert!(!a.fact.is_empty(), "{} says nothing", a.name);
assert!(!a.read_from.is_empty(), "{} says nowhere", a.name);
assert!(!a.depends.is_empty(), "{} costs nothing", a.name);
assert!(
a.verified_against.split('.').count() == 3,
"{} is dated against `{}`, which is not a version",
a.name,
a.verified_against
);
assert!(
a.name
.bytes()
.all(|b| b.is_ascii_lowercase() || b == b'_' || b.is_ascii_digit()),
"{} is not a stable code",
a.name
);
}
}
#[test]
fn a_probe_reads_what_is_there_and_names_what_is_not() {
let write_lock = named("write_lock").expect("listed");
let whole = write_lock.probe.join(" and also ");
assert_eq!(read_from_build(write_lock, &whole), Reading::Holds);
let moved = read_from_build(write_lock, "nothing of the sort");
assert_eq!(moved, Reading::Moved(write_lock.probe.to_vec()));
let cache = named("credential_cache").expect("listed");
assert_eq!(read_from_build(cache, ""), Reading::NotReadable);
}
#[test]
fn printable_runs_finds_the_strings_and_nothing_else() {
let bytes = b"\x00\x01hello there\x00\x02tiny\x00wide load\xff";
let found = printable_runs(bytes, 6);
assert!(found.contains("hello there"));
assert!(found.contains("wide load"));
assert!(
!found.contains("tiny"),
"a run shorter than asked for is not a string"
);
}
#[test]
fn an_assumption_can_be_looked_up_by_name() {
assert_eq!(
named("write_lock").expect("it is listed").name,
"write_lock"
);
assert_eq!(named("nothing_like_this"), None);
}
}