app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit f42d764f528b99c99906dc8f1dda915e8b83f358
parent ddab572e2868872596c234df3952c3f7fdc56c80
Author: triesap <tyson@radroots.org>
Date:   Tue, 11 Aug 2026 23:13:43 +0000

tools: enforce the hardened shell boundary

- Inventory every production Kotlin Compose surface, including moved UI.
- Reject legacy paths, tags, colors, and raw primitive bypasses.
- Block fake commerce plus nested documentation and workflow surfaces.
- Add positive source proof and stable negative policy fixtures.

Diffstat:
Mtools/xtask/src/lib.rs | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 189 insertions(+), 10 deletions(-)

diff --git a/tools/xtask/src/lib.rs b/tools/xtask/src/lib.rs @@ -179,10 +179,7 @@ fn repo_audit(root: &Path, inventory: &Inventory, findings: &mut Vec<String>) { } for path in &inventory.paths { let normalized = path.to_ascii_lowercase(); - if ["docs/", "spec/", ".github/", ".act/"] - .iter() - .any(|prefix| normalized.starts_with(prefix)) - { + if is_forbidden_documentation_or_workflow_path(&normalized) { findings.push(format!("{path}: forbidden repository root")); } if fs::symlink_metadata(root.join(path)) @@ -439,25 +436,65 @@ fn product_shell_audit(root: &Path, inventory: &Inventory, findings: &mut Vec<St } } for path in &inventory.paths { - if !path.starts_with("app/shared/src/commonMain/kotlin/org/harvestcircle/ui/shell/") - || !path.ends_with(".kt") - { + if !is_production_kotlin(path) { continue; } let source = read_text(root, path); - if path != "app/shared/src/commonMain/kotlin/org/harvestcircle/ui/shell/GlobalTopBar.kt" - && source.contains("Color(0x") + let normalized_path = path.to_ascii_lowercase(); + let compact = source + .chars() + .filter(|character| !character.is_whitespace()) + .collect::<String>(); + if normalized_path.ends_with("/harvestcirclescreen.kt") { + findings.push(format!("{path}: superseded product-shell screen path")); + } + for marker in [ + "home-screen", + "inactive-identities", + "WindowBackgroundColor", + "ButtonBackgroundColor", + "InputBackgroundColor", + ] { + if source.contains(marker) { + findings.push(format!("{path}: superseded product-shell marker {marker}")); + } + } + if is_production_compose(path, &source) + && path + != "app/shared/src/commonMain/kotlin/org/harvestcircle/ui/shell/HarvestCircleTheme.kt" + && contains_direct_call(&compact, "Color(") { findings.push(format!( - "{path}: hard-coded shell color outside the token adapter" + "{path}: hard-coded Compose color outside the theme adapter" )); } + if is_production_compose(path, &source) + && path + != "app/shared/src/commonMain/kotlin/org/harvestcircle/ui/shell/ShellControls.kt" + { + if contains_direct_call(&compact, "BasicText(") { + findings.push(format!( + "{path}: BasicText bypasses the shell primitive adapter" + )); + } + if contains_direct_call(&compact, "BasicTextField(") { + findings.push(format!( + "{path}: BasicTextField bypasses the shell primitive adapter" + )); + } + } let lowercase = source.to_ascii_lowercase(); for marker in [ "sample farm", "sample commitment", + "sample price", + "sample event", + "fake farm", + "fake commitment", "pricecents", "commitmentid", + "allocationid", + "fulfillmentid", ] { if lowercase.contains(marker) { findings.push(format!( @@ -468,6 +505,37 @@ fn product_shell_audit(root: &Path, inventory: &Inventory, findings: &mut Vec<St } } +fn is_forbidden_documentation_or_workflow_path(path: &str) -> bool { + path.split('/').any(|part| { + matches!( + part, + "doc" | "docs" | "spec" | "specs" | ".github" | ".act" | "workflow" | "workflows" + ) + }) +} + +fn is_production_kotlin(path: &str) -> bool { + path.starts_with("app/") + && path.ends_with(".kt") + && ["/src/main/", "/src/commonMain/", "/src/desktopMain/"] + .iter() + .any(|segment| path.contains(segment)) +} + +fn is_production_compose(path: &str, source: &str) -> bool { + is_production_kotlin(path) + && (source.contains("@Composable") || source.contains("androidx.compose.")) +} + +fn contains_direct_call(source: &str, call: &str) -> bool { + source.match_indices(call).any(|(index, _)| { + source[..index] + .chars() + .next_back() + .is_none_or(|character| !character.is_ascii_alphanumeric() && character != '_') + }) +} + fn provenance_check(root: &Path, inventory: &Inventory, findings: &mut Vec<String>) { let legacy = ["stu", "dio"].concat(); let legacy_repository = format!("https://github.com/radrootslabs/{legacy}_app"); @@ -893,6 +961,117 @@ mod tests { fs::remove_dir_all(root).expect("remove fixture"); } + #[test] + fn current_product_shell_sources_pass_the_expanded_policy() { + let root = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .canonicalize() + .expect("repository root"); + let inventory = Inventory::load(&root).expect("current source inventory"); + let mut findings = Vec::new(); + product_shell_audit(&root, &inventory, &mut findings); + assert!(findings.is_empty(), "{findings:?}"); + } + + #[test] + fn product_shell_audit_rejects_legacy_screen_paths_tags_and_colors() { + let root = fixture("legacy-shell"); + let path = "app/shared/src/commonMain/kotlin/org/harvestcircle/identities/ui/HarvestCircleScreen.kt"; + write( + &root, + path, + "@Composable fun Legacy() { val tag = \"home-screen\"; val color = WindowBackgroundColor }\n", + ); + let inventory = Inventory::load(&root).expect("legacy inventory"); + let mut findings = Vec::new(); + product_shell_audit(&root, &inventory, &mut findings); + assert!( + findings + .iter() + .any(|finding| finding.contains("superseded product-shell screen path")) + ); + assert!( + findings + .iter() + .any(|finding| finding.contains("superseded product-shell marker home-screen")) + ); + assert!(findings.iter().any(|finding| { + finding.contains("superseded product-shell marker WindowBackgroundColor") + })); + fs::remove_dir_all(root).expect("remove fixture"); + } + + #[test] + fn product_shell_audit_rejects_color_and_primitive_bypasses_after_a_move() { + let root = fixture("moved-compose"); + let path = "app/desktop/src/main/kotlin/org/harvestcircle/desktop/MovedScreen.kt"; + write( + &root, + path, + "import androidx.compose.runtime.Composable\n@Composable fun Moved() { Color(0xFF000000); BasicText(\"bypass\"); BasicTextField(\"\", {}) }\n", + ); + let inventory = Inventory::load(&root).expect("moved UI inventory"); + let mut findings = Vec::new(); + product_shell_audit(&root, &inventory, &mut findings); + assert!( + findings + .iter() + .any(|finding| finding + .contains("hard-coded Compose color outside the theme adapter")) + ); + assert!( + findings + .iter() + .any(|finding| finding.contains("BasicText bypasses the shell primitive adapter")) + ); + assert!(findings.iter().any(|finding| { + finding.contains("BasicTextField bypasses the shell primitive adapter") + })); + fs::remove_dir_all(root).expect("remove fixture"); + } + + #[test] + fn product_shell_audit_rejects_fake_commercial_data_outside_the_shell_package() { + let root = fixture("commercial-data"); + write( + &root, + "app/shared/src/commonMain/kotlin/org/harvestcircle/product/FakeData.kt", + "data class FakeData(val commitmentId: String, val priceCents: Long)\n", + ); + let inventory = Inventory::load(&root).expect("commercial inventory"); + let mut findings = Vec::new(); + product_shell_audit(&root, &inventory, &mut findings); + assert!(findings.iter().any(|finding| finding + .contains("fake commercial product data marker commitmentid"))); + assert!( + findings + .iter() + .any(|finding| finding.contains("fake commercial product data marker pricecents")) + ); + fs::remove_dir_all(root).expect("remove fixture"); + } + + #[test] + fn repository_policy_rejects_nested_documentation_and_workflow_roots() { + let root = fixture("nested-docs"); + write(&root, "app/docs/notes.md", "fixture\n"); + write(&root, "app/.github/workflows/remote.yml", "fixture\n"); + let inventory = Inventory::load(&root).expect("nested docs inventory"); + let mut findings = Vec::new(); + repo_audit(&root, &inventory, &mut findings); + assert!( + findings + .iter() + .any(|finding| finding.starts_with("app/docs/")) + ); + assert!( + findings + .iter() + .any(|finding| finding.starts_with("app/.github/workflows/")) + ); + fs::remove_dir_all(root).expect("remove fixture"); + } + #[cfg(unix)] #[test] fn repository_policy_rejects_symbolic_links() {