KeiSeiKit-1.0/_primitives/_rust/kei-atom-discovery/tests/smoke.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

165 lines
4.9 KiB
Rust

//! Smoke tests covering the 4 critical fixes consolidated in this crate.
use kei_atom_discovery::{
classify_wikilink, discover_atoms, parse_frontmatter, parse_wikilink, safe_join, AtomKind,
Error, WikilinkTarget, MAX_FRONTMATTER_BYTES,
};
use std::fs;
use std::path::Path;
use tempfile::tempdir;
const ATOM_OK: &str = r#"---
atom: kei-task::create
kind: command
version: "0.1.0"
input:
schema: schemas/create-input.json
output:
schema: schemas/create-output.json
side_effects:
- { op: write, domain: kei-task-db }
idempotent: false
stability: stable
keywords: [task, todo]
related:
- "[[kei-task::add-dependency]]"
- "[[rules/RULE 0.12]]"
---
# kei-task::create
Body text.
"#;
fn write_atom(root: &Path, crate_name: &str, verb: &str, body: &str) {
let atoms_dir = root.join(crate_name).join("atoms");
fs::create_dir_all(atoms_dir.join("schemas")).unwrap();
fs::write(atoms_dir.join(format!("{verb}.md")), body).unwrap();
fs::write(atoms_dir.join("schemas").join("create-input.json"), "{}").unwrap();
fs::write(atoms_dir.join("schemas").join("create-output.json"), "{}").unwrap();
}
// FIX 2 happy path — shared Frontmatter correctly parses and exposes typed kind
#[test]
fn discovery_returns_well_formed_atom_meta() {
let tmp = tempdir().unwrap();
write_atom(tmp.path(), "kei-task", "create", ATOM_OK);
let atoms = discover_atoms(tmp.path());
assert_eq!(atoms.len(), 1);
let a = &atoms[0];
assert_eq!(a.full_id, "kei-task::create");
assert_eq!(a.kind, AtomKind::Command);
assert_eq!(a.crate_name, "kei-task");
assert_eq!(a.verb, "create");
assert!(a.input_schema.is_some());
assert!(a.output_schema.is_some());
assert_eq!(a.side_effects.len(), 1);
assert_eq!(a.side_effects[0].op, "write");
assert_eq!(a.side_effects[0].domain, "kei-task-db");
assert!(a.body.contains("Body text"));
}
// FIX 1 — path traversal rejection via safe_join
#[test]
fn safe_join_rejects_parent_component() {
let tmp = tempdir().unwrap();
let err = safe_join(tmp.path(), "../etc/shadow").unwrap_err();
assert!(matches!(err, Error::PathParent(_)));
}
#[test]
fn safe_join_rejects_absolute_path() {
let tmp = tempdir().unwrap();
let err = safe_join(tmp.path(), "/etc/shadow").unwrap_err();
assert!(matches!(err, Error::PathAbsolute(_)));
}
#[test]
fn safe_join_accepts_plain_relative() {
let tmp = tempdir().unwrap();
let target = tmp.path().join("schemas");
fs::create_dir_all(&target).unwrap();
let joined = safe_join(tmp.path(), "schemas").unwrap();
assert!(joined.ends_with("schemas"));
}
// FIX 3 — YAML size cap enforced pre-parse
#[test]
fn frontmatter_size_cap_enforced() {
let huge = "x".repeat(MAX_FRONTMATTER_BYTES + 100);
let md = format!("---\n{huge}\n---\nbody\n");
let err = parse_frontmatter(&md).unwrap_err();
assert!(matches!(err, Error::FrontmatterTooLarge { .. }));
}
#[test]
fn frontmatter_missing_start_rejected() {
let err = parse_frontmatter("no fence\nbody\n").unwrap_err();
assert!(matches!(err, Error::FrontmatterMissingStart));
}
#[test]
fn frontmatter_missing_end_rejected() {
let err = parse_frontmatter("---\nkey: val\nno-end\n").unwrap_err();
assert!(matches!(err, Error::FrontmatterMissingEnd));
}
// FIX — symlink not followed (walkdir follow_links=false)
#[test]
fn discover_does_not_follow_symlinks() {
let tmp = tempdir().unwrap();
write_atom(tmp.path(), "kei-real", "create", ATOM_OK);
// Create a symlink named `kei-link` pointing at `kei-real`.
#[cfg(unix)]
{
let target = tmp.path().join("kei-real");
let link = tmp.path().join("kei-link");
std::os::unix::fs::symlink(&target, &link).unwrap();
}
let atoms = discover_atoms(tmp.path());
// Only 1 atom — symlinked tree is NOT walked.
assert_eq!(atoms.len(), 1, "symlink was traversed — follow_links must be false");
}
// Wikilink strictness
#[test]
fn wikilink_malformed_returns_none() {
assert_eq!(parse_wikilink("[[[foo]]"), None); // triple-bracket open
assert_eq!(parse_wikilink("foo"), None);
assert_eq!(parse_wikilink("[[ ]]"), None);
assert_eq!(
parse_wikilink("[[kei-task::create]]"),
Some("kei-task::create".to_string())
);
}
// classify_wikilink — 3 variants (Atom / Rule / Other)
#[test]
fn classify_atom_target() {
assert_eq!(
classify_wikilink("kei-task::create"),
WikilinkTarget::Atom("kei-task::create".into())
);
}
#[test]
fn classify_rule_targets() {
assert_eq!(
classify_wikilink("rules/RULE 0.12"),
WikilinkTarget::Rule("0.12".into())
);
assert_eq!(
classify_wikilink("rules/memory-protocol"),
WikilinkTarget::Rule("memory-protocol".into())
);
assert_eq!(
classify_wikilink("rule 0.12"),
WikilinkTarget::Rule("0.12".into())
);
}
#[test]
fn classify_other_target() {
assert_eq!(
classify_wikilink("random-note"),
WikilinkTarget::Other("random-note".into())
);
}