{"record":{"id":"945aa084dbc78ab2","repo":"slint-ui/slint","slug":"license-symlink-points-outside-the-repository","errorCode":null,"errorMessage":"LICENSE symlink \"{}\" points outside the repository","messagePattern":"LICENSE symlink \"(.+?)\" points outside the repository","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xtask/src/reuse_compliance_check.rs","lineNumber":218,"sourceCode":"            continue;\n        }\n        if link_target_extension != ext || link_target_file_stem != file_stem {\n            if !fix_it {\n                anyhow::bail!(\n                    \"LICENSE symlink \\\"{}\\\" renames the license.\",\n                    child.to_string_lossy()\n                );\n            } else {\n                to_remove.push(child.clone());\n                to_add.push(file_stem.clone());\n                continue;\n            }\n        }\n\n        if !validated_link_target.is_absolute() || !validated_link_target.starts_with(&top_dir) {\n            if !fix_it {\n                let c = child.to_string_lossy();\n                anyhow::bail!(\"LICENSE symlink \\\"{}\\\" points outside the repository\", c);\n            } else {\n                to_remove.push(child.clone());\n                to_add.push(file_stem.clone());\n                continue;\n            }\n        }\n\n        if !validated_link_target.starts_with(top_dir.join(\"LICENSES\")) {\n            if !fix_it {\n                let c = child.to_string_lossy();\n                anyhow::bail!(\n                    \"LICENSE symlink \\\"{}\\\" points to a random place in the repository\",\n                    c\n                );\n            } else {\n                to_remove.push(child.clone());\n                to_add.push(file_stem.clone());\n                continue;","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/slint-ui/slint/blob/bb937076de3f7919766c1f25e2e969367cf77e9a/xtask/src/reuse_compliance_check.rs#L200-L236","documentation":"After canonicalization, the symlink target must be an absolute path inside the repository top directory. This bail fires when the canonicalized target escapes the repo (relative ../ chains that go above the root) or is not absolute, blocking license files from being sourced outside the repository.","triggerScenarios":"A symlink in a sub-LICENSES/ dir whose relative target contains too many `../` components and escapes the repository root, or points at an absolute path elsewhere on disk — detected when running without --fix-symlinks.","commonSituations":"Wrong number of ../ in a hand-made symlink; symlink pointing to a license installed on the system (e.g. /usr/share/common-licenses/GPL-3); repo checked out at a shallow depth so ../ resolves above it.","solutions":["Recreate the symlink with the correct number of ../ so it lands on the repo's top-level LICENSES/ directory","Run `cargo xtask reuse-compliance-check --fix-symlinks` to replace offending links","Never point LICENSES symlinks outside the repo; copy the license text into the top-level LICENSES/ dir first"],"exampleFix":"// before\npackage/a/b/LICENSES/MIT.txt -> ../../../../../usr/share/common-licenses/MIT\n// after\npackage/a/b/LICENSES/MIT.txt -> ../../../../LICENSES/MIT.txt","handlingStrategy":"validation","validationCode":"let canon = std::fs::canonicalize(link.parent().unwrap().join(std::fs::read_link(link)?))?;\nlet top = std::fs::canonicalize(\".\")?;\nif !canon.starts_with(&top) { eprintln!(\"escapes repo: {}\", canon.display()); }","typeGuard":"fn target_inside_repo(link: &std::path::Path, top: &std::path::Path) -> bool {\n    link.parent().and_then(|p| std::fs::read_link(link).ok().map(|t| p.join(t))).and_then(|p| std::fs::canonicalize(p).ok()).map(|c| c.starts_with(top)).unwrap_or(false)\n}","tryCatchPattern":"if let Err(e) = run_check() {\n    if e.to_string().contains(\"points outside the repository\") { /* recompute the relative path within the repo */ }\n    else { return Err(e); }\n}","preventionTips":["Compute relative symlink targets from the repo root, counting ../ per directory level","Never link to system-wide license files; copy the text into LICENSES/ first","Test symlinks after changing repository nesting depth"],"tags":["reuse","symlink","licensing","path-safety"],"backgroundTag":"path-traversal-blocked","analyzedSha":"bb937076de3f7919766c1f25e2e969367cf77e9a","analyzedAt":"2026-09-16T01:37:20.251Z","contentChangedAt":"2026-09-16T01:37:20.251Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}