use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::sync::atomic::{AtomicU32, Ordering};
static COUNTER: AtomicU32 = AtomicU32::new(0);
struct Sandbox {
base: PathBuf,
source: PathBuf,
mind_home: PathBuf,
claude_home: PathBuf,
}
struct Run {
stdout: String,
stderr: String,
success: bool,
}
impl Sandbox {
fn new(name: &str) -> Self {
let n = COUNTER.fetch_add(1, Ordering::SeqCst);
let base = std::env::temp_dir().join(format!("mind-rw-{}-{n}", std::process::id()));
let _ = std::fs::remove_dir_all(&base);
let source = base.join(name);
Sandbox {
base: base.clone(),
source,
mind_home: base.join("mind"),
claude_home: base.join("claude"),
}
}
fn mind(&self, args: &[&str]) -> Run {
let out = Command::new(env!("CARGO_BIN_EXE_mind"))
.args(args)
.env("MIND_HOME", &self.mind_home)
.env("CLAUDE_HOME", &self.claude_home)
.env_remove("MIND_MAX_METADATA_SIZE")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.output()
.expect("run mind");
Run {
stdout: String::from_utf8_lossy(&out.stdout).into_owned(),
stderr: String::from_utf8_lossy(&out.stderr).into_owned(),
success: out.status.success(),
}
}
fn review(&self) -> Run {
let target = self.source.to_string_lossy().into_owned();
self.mind(&["review", &target])
}
fn review_with(&self, extra: &[&str]) -> Run {
let target = self.source.to_string_lossy().into_owned();
let mut args = vec!["review", target.as_str()];
args.extend_from_slice(extra);
self.mind(&args)
}
}
impl Drop for Sandbox {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.base);
}
}
fn write(path: &Path, contents: &str) {
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, contents).unwrap();
}
fn write_bytes(path: &Path, contents: &[u8]) {
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, contents).unwrap();
}
fn findings<'a>(stdout: &'a str, tag: &str) -> Vec<&'a str> {
let needle = format!("advisory [{tag}]:");
stdout
.lines()
.filter(|l| l.contains(&needle))
.collect::<Vec<_>>()
}
#[test]
fn every_workflow_draws_exactly_one_workflow_content_advisory() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/deploy.js"),
"export const meta = { name: 'deploy', description: 'Deploy it' }\n\
export default async function () {}\n",
);
write(
&sb.source.join("workflows/audit.js"),
"export const meta = { name: 'audit', description: 'Audit it' }\n\
export default async function () {}\n",
);
write(
&sb.source.join("agents/dev.md"),
"---\ndescription: dev agent\n---\n# dev\n",
);
let r = sb.review();
assert!(
r.success,
"workflow-content is advisory; review must exit 0: stdout={} stderr={}",
r.stdout, r.stderr
);
let lines = findings(&r.stdout, "workflow-content");
assert_eq!(
lines.len(),
2,
"one disclosure per workflow, none for the agent: {}",
r.stdout
);
assert!(
lines.iter().any(|l| l.contains("workflow:deploy:")),
"must name the deploy workflow: {lines:?}"
);
assert!(
lines.iter().any(|l| l.contains("workflow:audit:")),
"must name the audit workflow: {lines:?}"
);
for line in &lines {
assert!(
line.contains("JavaScript") && line.contains("harness"),
"must disclose that the harness evaluates the file: {line}"
);
assert!(
line.contains("neither reads nor validates"),
"must disclose that mind does not read the body: {line}"
);
}
}
#[test]
fn a_workflow_with_no_meta_description_draws_only_workflow_unloadable() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/deploy.js"),
"export const meta = { name: 'deploy' }\nexport default async function () {}\n",
);
write(&sb.source.join("rules/style.md"), "# style\n");
let r = sb.review();
assert!(
r.success,
"both findings are advisory; review must exit 0: stdout={} stderr={}",
r.stdout, r.stderr
);
let unloadable = findings(&r.stdout, "workflow-unloadable");
assert_eq!(
unloadable.len(),
1,
"the missing description is reported once, as unloadable: {}",
r.stdout
);
assert!(
unloadable[0].contains("workflow:deploy:")
&& unloadable[0].contains("`meta.description` is missing"),
"unloadable finding must name the missing meta key: {}",
unloadable[0]
);
let missing = findings(&r.stdout, "missing-description");
assert!(
missing.iter().all(|l| !l.contains("workflow:")),
"a workflow must never draw missing-description: {missing:?}"
);
assert!(
missing.iter().any(|l| l.contains("rule:style")),
"the generic check must still fire for a frontmatter kind: {}",
r.stdout
);
}
#[test]
fn a_workflow_with_a_meta_description_draws_neither_description_finding() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/deploy.js"),
"export const meta = { name: 'deploy', description: 'Deploy it' }\n",
);
let r = sb.review();
assert!(r.success, "stdout={} stderr={}", r.stdout, r.stderr);
assert!(
findings(&r.stdout, "workflow-unloadable").is_empty(),
"a complete meta is not unloadable: {}",
r.stdout
);
assert!(
findings(&r.stdout, "missing-description").is_empty(),
"no generic finding either: {}",
r.stdout
);
}
#[test]
fn a_meta_name_naming_a_sibling_agent_is_predicted_bare_under_a_prefix() {
let sb = Sandbox::new("wf");
write(&sb.source.join("mind.toml"), "[source]\nprefix = \"jk\"\n");
write(
&sb.source.join("agents/dev.md"),
"---\nname: dev\ndescription: dev agent\n---\n# dev\n",
);
write(
&sb.source.join("workflows/tokenized.js"),
"export const meta = { name: '{{ns:dev}}', description: 'Drive the dev agent' }\n",
);
write(
&sb.source.join("workflows/literal.js"),
"export const meta = { name: 'dev', description: 'Drive the dev agent' }\n",
);
let r = sb.review();
assert!(
r.success,
"every workflow finding is advisory: stdout={} stderr={}",
r.stdout, r.stderr
);
let divergences = findings(&r.stdout, "workflow-name");
let tokenized = divergences
.iter()
.find(|l| l.contains("workflow:jk:tokenized:"))
.unwrap_or_else(|| {
panic!(
"expected a divergence for the tokenized workflow: {}",
r.stdout
)
});
assert!(
tokenized.contains("resolves it as 'dev'"),
"the token names an agent, so install writes the bare name: {tokenized}"
);
assert!(
!tokenized.contains("jk:dev"),
"predicting a prefixed agent name is the NS-42 bug: {tokenized}"
);
let collisions = findings(&r.stdout, "workflow-name-collision");
assert_eq!(
collisions.len(),
1,
"one finding for the one shared name: {}",
r.stdout
);
assert!(
collisions[0].contains("harness name 'dev'"),
"the shared name is the bare agent name: {collisions:?}"
);
assert!(
collisions[0].contains("workflow:jk:tokenized")
&& collisions[0].contains("workflow:jk:literal"),
"and both claimants are named in it: {collisions:?}"
);
assert!(
collisions[0].contains("and mind would install both")
&& !collisions[0].contains("are installed"),
"review wording, not the installed-site wording: {collisions:?}"
);
}
#[test]
fn the_workflow_content_finding_has_a_json_shape() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/deploy.js"),
"export const meta = { name: 'deploy', description: 'Deploy it' }\n",
);
write(
&sb.source.join("skills/widget/SKILL.md"),
"---\ndescription: a widget\n---\n# widget\n",
);
let r = sb.review_with(&["--json"]);
assert!(
r.success,
"an advisory-only review exits 0: stdout={} stderr={}",
r.stdout, r.stderr
);
let v: serde_json::Value = serde_json::from_str(r.stdout.trim())
.unwrap_or_else(|e| panic!("stdout must be one JSON document: {e}\n{}", r.stdout));
assert_eq!(v["action"], "review", "{v}");
assert_eq!(
v["outcome"], "advisory",
"a workflow alone must move the outcome off `clean`: {v}"
);
assert_eq!(v["hard"], serde_json::json!([]), "{v}");
let advisory = v["advisory"]
.as_array()
.unwrap_or_else(|| panic!("advisory must be an array: {v}"));
let disclosures: Vec<&serde_json::Value> = advisory
.iter()
.filter(|f| f["kind"] == "workflow-content")
.collect();
assert_eq!(
disclosures.len(),
1,
"exactly one disclosure, for the one workflow: {v}"
);
let msg = disclosures[0]["message"]
.as_str()
.unwrap_or_else(|| panic!("the finding must carry a message: {v}"));
assert!(
msg.contains("workflow:deploy"),
"the message must name the item: {msg}"
);
assert!(
!advisory.iter().any(|f| f["kind"] == "missing-description"
&& f["message"]
.as_str()
.is_some_and(|m| m.contains("workflow:"))),
"no missing-description for a workflow, in JSON either: {v}"
);
}
#[test]
fn every_workflow_is_disclosed_whatever_else_was_found_about_it() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/aclean.js"),
"export const meta = { name: 'aclean', description: 'Clean' }\n",
);
write(
&sb.source.join("workflows/bbroken.js"),
"export const meta = { name: 'bbroken' }\n",
);
write(
&sb.source.join("workflows/cdup.js"),
"export const meta = { name: 'dup', description: 'One' }\n",
);
write(
&sb.source.join("workflows/ddup.js"),
"export const meta = { name: 'dup', description: 'Two' }\n",
);
let r = sb.review();
assert!(r.success, "stdout={} stderr={}", r.stdout, r.stderr);
let lines = findings(&r.stdout, "workflow-content");
assert_eq!(lines.len(), 4, "one disclosure per workflow: {}", r.stdout);
for key in [
"workflow:aclean:",
"workflow:bbroken:",
"workflow:cdup:",
"workflow:ddup:",
] {
assert_eq!(
lines.iter().filter(|l| l.contains(key)).count(),
1,
"{key} must be disclosed exactly once: {}",
r.stdout
);
}
assert_eq!(
findings(&r.stdout, "workflow-unloadable").len(),
1,
"{}",
r.stdout
);
assert_eq!(
findings(&r.stdout, "workflow-name-collision").len(),
1,
"one finding for the one shared name: {}",
r.stdout
);
let names = findings(&r.stdout, "workflow-name");
assert_eq!(
names.len(),
2,
"the two `dup` claimants each diverge from their item name: {}",
r.stdout
);
}
#[test]
fn a_declared_workflow_at_an_odd_path_is_disclosed_and_checked() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("mind.toml"),
"[source]\ndescription = \"odd layout\"\n\n\
[[items]]\nkind = \"workflow\"\nname = \"deploy\"\n\
path = \"packages/deploy/flow.js\"\n\
description = \"Deploy, as mind.toml says\"\n",
);
write(
&sb.source.join("packages/deploy/flow.js"),
"export const meta = { name: 'deploy' }\n",
);
write(
&sb.source.join("workflows/decoy.js"),
"export const meta = { name: 'decoy', description: 'Not in the inventory' }\n",
);
let r = sb.review();
assert!(
r.success,
"every workflow finding is advisory: stdout={} stderr={}",
r.stdout, r.stderr
);
let disclosures = findings(&r.stdout, "workflow-content");
assert_eq!(
disclosures.len(),
1,
"only the declared workflow is an item: {}",
r.stdout
);
assert!(
disclosures[0].contains("workflow:deploy:"),
"the declared workflow must be disclosed: {}",
disclosures[0]
);
let unloadable = findings(&r.stdout, "workflow-unloadable");
assert_eq!(unloadable.len(), 1, "{}", r.stdout);
assert!(
unloadable[0].contains("workflow:deploy:")
&& unloadable[0].contains("`meta.description` is missing"),
"a mind.toml description must not answer for the harness's: {}",
unloadable[0]
);
assert!(
findings(&r.stdout, "missing-description").is_empty(),
"{}",
r.stdout
);
}
#[test]
fn a_non_utf8_workflow_is_still_disclosed_and_reported_unloadable() {
let sb = Sandbox::new("wf");
let mut bytes: Vec<u8> = b"export const meta = { name: 'deploy', description: '".to_vec();
bytes.extend_from_slice(&[0x80, 0xff, 0xfe]);
bytes.extend_from_slice(b"' }\n");
write_bytes(&sb.source.join("workflows/deploy.js"), &bytes);
let r = sb.review();
assert!(
r.success,
"an unreadable workflow body is advisory, never hard: stdout={} stderr={}",
r.stdout, r.stderr
);
let disclosures = findings(&r.stdout, "workflow-content");
assert_eq!(
disclosures.len(),
1,
"a file mind cannot decode is still JavaScript the harness will run: {}",
r.stdout
);
assert!(
disclosures[0].contains("workflow:deploy:"),
"{}",
disclosures[0]
);
let unloadable = findings(&r.stdout, "workflow-unloadable");
assert_eq!(unloadable.len(), 1, "{}", r.stdout);
assert!(
unloadable[0].contains("mind read no `name`, `description`, or `whenToUse`"),
"an undecodable file reads as no readable meta: {}",
unloadable[0]
);
assert!(
!r.stderr.contains("error ["),
"nothing about a workflow's body is a hard finding: {}",
r.stderr
);
}
#[test]
fn an_over_cap_workflow_is_reported_and_review_still_exits_zero() {
let sb = Sandbox::new("wf");
let mut body = String::from("export const meta = { name: 'big', description: 'Big' }\n// ");
body.push_str(&"p".repeat(524_288));
body.push('\n');
write(&sb.source.join("workflows/big.js"), &body);
let r = sb.review();
assert!(
r.success,
"the harness's cap is reported, not enforced: stdout={} stderr={}",
r.stdout, r.stderr
);
let unloadable = findings(&r.stdout, "workflow-unloadable");
assert_eq!(
unloadable.len(),
1,
"the overage is the only complaint -- the `meta` itself is complete: {}",
r.stdout
);
assert!(
unloadable[0].contains("over the harness's 524288-byte cap"),
"{}",
unloadable[0]
);
assert_eq!(
findings(&r.stdout, "workflow-content").len(),
1,
"an over-cap file is still disclosed: {}",
r.stdout
);
assert!(
!r.stderr.contains("metadata-too-large"),
"the harness cap is far below mind's metadata cap; this file trips only \
the former: {}",
r.stderr
);
}
#[test]
fn a_workflow_past_minds_own_read_cap_reads_as_no_meta_and_spares_the_scan() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/fine.js"),
"export const meta = { name: 'fine', description: 'Fine' }\n",
);
let path = sb.source.join("workflows/huge.js");
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
let f = std::fs::File::create(&path).unwrap();
f.set_len(8 * 1024 * 1024 + 1).unwrap();
drop(f);
let r = sb.review();
assert!(
r.success,
"an over-cap workflow is advisory, not a hard finding: stdout={} stderr={}",
r.stdout, r.stderr
);
assert!(
!r.stderr.contains("error ["),
"nothing here is hard -- no scan-error, no metadata-too-large: {}",
r.stderr
);
assert!(
!r.stdout.contains("metadata-too-large") && !r.stderr.contains("metadata-too-large"),
"the cap is mind's own read bound, not a finding about the source: {} {}",
r.stdout,
r.stderr
);
let disclosures = findings(&r.stdout, "workflow-content");
assert_eq!(
disclosures.len(),
2,
"both workflows are scanned and disclosed: {}",
r.stdout
);
assert!(
disclosures.iter().any(|d| d.contains("workflow:fine")),
"the healthy sibling is disclosed: {}",
r.stdout
);
let unread = findings(&r.stdout, "workflow-unread");
assert_eq!(
unread.len(),
1,
"one unread file, one finding: {}",
r.stdout
);
assert!(
unread[0].contains("workflow:huge") && unread[0].contains("over mind's own 8 MiB"),
"the finding must name the item and mind's own cap: {}",
unread[0]
);
assert!(
unread[0].contains("--max-metadata-size"),
"and the flag that raises it: {}",
unread[0]
);
assert!(
!unread[0].contains("will not load"),
"mind read nothing, so it claims nothing about the harness: {}",
unread[0]
);
let unloadable = findings(&r.stdout, "workflow-unloadable");
assert!(
unloadable.iter().all(|u| u.contains("workflow:huge")),
"the healthy sibling draws no unloadable finding: {}",
r.stdout
);
assert!(
!unloadable.iter().any(|u| u.contains("mind read no `name`")),
"a file mind did not read must not be reported as one declaring nothing: {}",
r.stdout
);
assert!(
unloadable
.iter()
.any(|u| u.contains("over the harness's 524288-byte cap")),
"and the WF-7 overage is reported beside it: {}",
r.stdout
);
}
#[test]
fn a_lowered_cap_reports_minds_own_cap_and_not_the_harnesss() {
let sb = Sandbox::new("wf");
let mut body = String::from("export const meta = { name: 'big', description: 'Big' }\n// ");
body.push_str(&"p".repeat(2600));
body.push('\n');
write(&sb.source.join("workflows/big.js"), &body);
let r = sb.review_with(&["--max-metadata-size", "2KiB"]);
assert!(
r.success,
"a capped read is advisory, never hard: stdout={} stderr={}",
r.stdout, r.stderr
);
let unread = findings(&r.stdout, "workflow-unread");
assert_eq!(unread.len(), 1, "{}", r.stdout);
assert!(
unread[0].contains("over mind's own 2 KiB metadata read cap")
&& unread[0].contains("--max-metadata-size"),
"the finding names the effective cap and the flag: {}",
unread[0]
);
assert!(
findings(&r.stdout, "workflow-unloadable").is_empty(),
"a file only MIND declined to read is not a file the harness skips: {}",
r.stdout
);
assert!(
!r.stdout.contains("metadata-too-large") && !r.stderr.contains("metadata-too-large"),
"and the cap is not a hard error either: {} {}",
r.stdout,
r.stderr
);
}
#[test]
fn an_over_cap_workflow_body_is_not_read_by_the_body_checks() {
let sb = Sandbox::new("wf");
let mut body = String::from(
"export const meta = { name: 'big', description: 'Big' }\n// {{ns:no-such-sibling}} ",
);
body.push_str(&"p".repeat(2600));
body.push('\n');
write(&sb.source.join("workflows/big.js"), &body);
let r = sb.review_with(&["--max-metadata-size", "2KiB"]);
assert!(
r.success,
"a capped read is advisory, never hard: stdout={} stderr={}",
r.stdout, r.stderr
);
assert!(
!r.stdout.contains("no-such-sibling") && !r.stderr.contains("no-such-sibling"),
"the body of an over-cap workflow must not be read by a later check: {} {}",
r.stdout,
r.stderr
);
assert!(
!r.stdout.contains("bad-reference") && !r.stderr.contains("bad-reference"),
"no token finding for a file review did not read: {} {}",
r.stdout,
r.stderr
);
let unread = findings(&r.stdout, "workflow-unread");
assert_eq!(unread.len(), 1, "{}", r.stdout);
assert!(
unread[0].contains("checks were skipped"),
"the finding must say the token checks were skipped: {}",
unread[0]
);
}
#[test]
fn a_decoy_member_expression_cannot_choose_the_harness_name() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/decoy.js"),
"const shim = {}\n\
shim.export.const.meta = { name: 'deploy', description: 'Decoy' };\n\
export const meta = { name: 'hidden', description: 'The real one' }\n",
);
write(
&sb.source.join("workflows/deploy.js"),
"export const meta = { name: 'deploy', description: 'Deploy it' }\n",
);
let r = sb.review();
assert!(r.success, "stdout={} stderr={}", r.stdout, r.stderr);
let names = findings(&r.stdout, "workflow-name");
let decoy = names
.iter()
.find(|l| l.contains("workflow:decoy:"))
.unwrap_or_else(|| panic!("the real `meta.name` diverges from `decoy`: {}", r.stdout));
assert!(
decoy.contains("resolves it as 'hidden'"),
"the statement-position declaration is the one read: {decoy}"
);
assert!(
!r.stdout.contains("'deploy', not 'decoy'"),
"the decoy must not be read as this workflow's name: {}",
r.stdout
);
assert!(
findings(&r.stdout, "workflow-name-collision").is_empty(),
"and it must not collide with the workflow that really claims `deploy`: {}",
r.stdout
);
}
#[test]
fn many_workflows_sharing_one_name_produce_one_bounded_finding() {
let sb = Sandbox::new("wf");
const N: usize = 300;
for i in 0..N {
write(
&sb.source.join(format!("workflows/w{i:03}.js")),
"export const meta = { name: 'deploy', description: 'Deploy it' }\n",
);
}
let r = sb.review();
assert!(r.success, "stdout={} stderr={}", r.stdout, r.stderr);
let collisions = findings(&r.stdout, "workflow-name-collision");
assert_eq!(
collisions.len(),
1,
"one name, one finding, whatever the claimant count: {} lines",
collisions.len()
);
assert!(
collisions[0].contains("harness name 'deploy'"),
"{}",
collisions[0]
);
assert!(
collisions[0].contains("and 296 more"),
"the claimant list must be capped and the rest counted: {}",
collisions[0]
);
assert!(
collisions[0].ends_with("and mind would install all 300"),
"count-aware review wording: {}",
collisions[0]
);
assert!(
collisions[0].len() < 400,
"the finding must stay bounded in length: {} chars",
collisions[0].len()
);
assert_eq!(
findings(&r.stdout, "workflow-name").len(),
N,
"a divergence is a property of one item, so it is still reported per item"
);
}
#[test]
fn fix_leaves_a_workflow_js_untouched() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("agents/dev.md"),
"---\nname: dev\ndescription: dev agent\n---\n# dev\n",
);
let js = "export const meta = { name: 'drive', description: 'Drive dev' }\n\
const done = await agent('dev', 'Do the work.')\n";
write(&sb.source.join("workflows/drive.js"), js);
let md = "---\ndescription: Calls the dev agent\n---\n# helper\n\nHand off to dev.\n";
write(&sb.source.join("skills/helper/SKILL.md"), md);
let r = sb.review_with(&["--fix"]);
assert!(
r.success,
"--fix on a local source must succeed: stdout={} stderr={}",
r.stdout, r.stderr
);
let after_js = std::fs::read_to_string(sb.source.join("workflows/drive.js")).unwrap();
assert_eq!(
after_js, js,
"--fix must leave a workflow's .js byte-identical (NS-54)"
);
let after_md = std::fs::read_to_string(sb.source.join("skills/helper/SKILL.md")).unwrap();
assert_ne!(
after_md, md,
"the markdown control must have been rewritten, or this test proves \
only that --fix did nothing: {after_md}"
);
assert_eq!(
findings(&r.stdout, "workflow-content").len(),
1,
"{}",
r.stdout
);
}
fn prefixed_source_with_workflow(sb: &Sandbox, name: &str, pad: usize) {
write(&sb.source.join("mind.toml"), "[source]\nprefix = \"pre\"\n");
write(
&sb.source.join("skills/helper/SKILL.md"),
"---\ndescription: helper skill\n---\n# helper\n",
);
write(&sb.source.join("tools/mytool/run.sh"), "#!/bin/sh\n");
let mut body = format!(
"export const meta = {{ name: '{name}', description: 'D' }}\n\
// {{{{ns:nonesuch}}}} {{{{tools:nonesuch}}}} {{{{ns:mytool}}}}\n\
// Ask helper to do it.\n"
);
body.push_str(&"p".repeat(pad));
body.push('\n');
write(&sb.source.join(format!("workflows/{name}.js")), &body);
}
#[test]
fn an_under_cap_workflow_body_draws_the_token_and_reference_findings() {
let sb = Sandbox::new("wf");
prefixed_source_with_workflow(&sb, "small", 0);
let r = sb.review_with(&["--max-metadata-size", "2KiB"]);
let all = format!("{}{}", r.stdout, r.stderr);
assert!(all.contains("bad-reference"), "{all}");
assert!(all.contains("unguarded-reference"), "{all}");
assert!(all.contains("ns-tool-reference"), "{all}");
assert!(all.contains("nonesuch"), "{all}");
}
#[test]
fn an_over_cap_workflow_under_a_prefix_is_skipped_by_every_content_check() {
let sb = Sandbox::new("wf");
prefixed_source_with_workflow(&sb, "big", 2600);
let r = sb.review_with(&["--max-metadata-size", "2KiB"]);
let all = format!("{}{}", r.stdout, r.stderr);
assert!(r.success, "{all}");
for tag in [
"bad-reference",
"unguarded-reference",
"ns-tool-reference",
"nonesuch",
] {
assert!(
!all.contains(tag),
"{tag} leaked from an unread file: {all}"
);
}
let unread = findings(&r.stdout, "workflow-unread");
assert_eq!(unread.len(), 1, "{}", r.stdout);
assert!(
unread[0].contains("checks were skipped"),
"the skip is disclosed: {}",
unread[0]
);
}
#[test]
fn the_json_workflow_unread_finding_says_checks_were_skipped() {
let sb = Sandbox::new("wf");
prefixed_source_with_workflow(&sb, "big", 2600);
let r = sb.review_with(&["--max-metadata-size", "2KiB", "--json"]);
assert!(r.success, "{}{}", r.stdout, r.stderr);
assert!(
r.stdout.contains("workflow-unread")
&& r.stdout
.contains("token and reference checks were skipped for this file"),
"{}",
r.stdout
);
}
#[test]
fn a_malformed_config_is_an_error_not_a_default_cap() {
let sb = Sandbox::new("wf");
write(
&sb.source.join("workflows/w.js"),
"export const meta = { name: 'w', description: 'D' }\n",
);
write(
&sb.mind_home.join("config.toml"),
"max-metadata-size = = 1MiB\n",
);
let r = sb.review();
assert!(
!r.success,
"a malformed config must not be ignored: stdout={} stderr={}",
r.stdout, r.stderr
);
assert!(
r.stderr.contains("config"),
"the error names the config: {}",
r.stderr
);
}
#[test]
fn a_workflow_exactly_at_the_cap_is_still_read() {
let sb = Sandbox::new("wf");
let body = "export const meta = { name: 'edge', description: 'D' }\n// {{ns:nonesuch}}\n";
let mut padded = body.to_string();
padded.push_str(&"p".repeat(2048 - body.len()));
assert_eq!(padded.len(), 2048);
write(&sb.source.join("workflows/edge.js"), &padded);
let r = sb.review_with(&["--max-metadata-size", "2KiB"]);
let all = format!("{}{}", r.stdout, r.stderr);
assert!(findings(&r.stdout, "workflow-unread").is_empty(), "{all}");
assert!(all.contains("bad-reference"), "{all}");
}