{"record":{"id":"efc520ff18c23b42","repo":"AprilNEA/OpenLogi","slug":"relationship-verification-failed-fixture-case-name-case-name","errorCode":null,"errorMessage":"relationship verification failed: fixture case name {case_name:?} is not a safe file name","messagePattern":"relationship verification failed: fixture case name (.+?) is not a safe file name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/openlogi-cli/src/cmd/fixture/verify.rs","lineNumber":172,"sourceCode":"        let cassette: HidCassette = read_json(&entry.path(), \"HID cassette\")?;\n        if cassette.name != *case_name {\n            bail!(\n                \"relationship verification failed: cassette file {file_name:?} contains case {:?}\",\n                cassette.name\n            );\n        }\n        found.insert(file_name, cassette);\n    }\n\n    if let Some(missing) = expected.keys().find(|name| !found.contains_key(*name)) {\n        bail!(\"relationship verification failed: missing declared fixture case file {missing:?}\");\n    }\n    Ok(found.into_values().collect())\n}\n\nfn case_file_name(case_name: &str) -> Result<String> {\n    if matches!(case_name, \".\" | \"..\") || case_name.contains('/') || case_name.contains('\\\\') {\n        bail!(\n            \"relationship verification failed: fixture case name {case_name:?} is not a safe file name\"\n        );\n    }\n    Ok(format!(\"{case_name}.json\"))\n}\n\nfn require_directory_id(directory: &Path, fixture_id: &str) -> Result<()> {\n    if directory.file_name().and_then(|name| name.to_str()) == Some(fixture_id) {\n        Ok(())\n    } else {\n        bail!(\n            \"relationship verification failed: fixture directory name must equal manifest id {fixture_id:?}\"\n        )\n    }\n}\n\nfn read_json<T: DeserializeOwned>(path: &Path, asset: &str) -> Result<T> {\n    let bytes = fs::read(path).with_context(|| {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/AprilNEA/OpenLogi/blob/e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8/crates/openlogi-cli/src/cmd/fixture/verify.rs#L154-L190","documentation":"`case_file_name` refuses to turn a fixture case name into a filename when the name would be dangerous as a path component: exactly `.` or `..`, or containing `/` or `\\`. This is a path-traversal guard ensuring manifest case names map to safe files inside the fixture directory.","triggerScenarios":"`load_cassettes` calls `case_file_name` with a manifest case name that is `.`/`..` or contains a slash or backslash; the error then aborts fixture verification.","commonSituations":"A hand-edited manifest accidentally embeds a path or separator in a case name (e.g. `sub/case`); an auto-generated case name concatenates strings with `/`; a copy-paste introduced `..` or a Windows separator.","solutions":["Edit the fixture manifest so the case name contains only safe filename characters (no `/`, `\\`, and not `.` or `..`).","If the case genuinely needs hierarchy, model it as a separate fixture directory whose name equals the manifest id, not as a slashed case name.","Fix any code that generates case names to sanitize or reject separators at authoring time.","Re-run `openlogi fixture verify`."],"exampleFix":"// before\n[fixtures.cases]\n\"sensor/report\" = true\n// after\n[fixtures.cases]\n\"sensor-report\" = true","handlingStrategy":"validation","validationCode":"fn is_safe_case_name(name: &str) -> bool {\n    !matches!(name, \".\" | \"..\") && !name.contains('/') && !name.contains('\\\\') && !name.is_empty()\n}\nassert!(is_safe_case_name(&case_name));","typeGuard":"fn is_safe_case_name(name: &str) -> bool {\n    !matches!(name, \".\" | \"..\") && !name.contains('/') && !name.contains('\\\\')\n}","tryCatchPattern":null,"preventionTips":["Validate case names at manifest-authoring time, not only at verification time","Reject or sanitize user/generated names containing path separators","Keep case names to kebab-case to make unsafe names obvious"],"tags":["fixture","path-safety","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"e846e6f4b4405e33bd6a9aaf949a482ce34cb6d8","analyzedAt":"2026-09-13T03:07:16.451Z","contentChangedAt":"2026-09-13T03:07:16.451Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}