{"record":{"id":"f05ea47e09bee6a8","repo":"Hmbown/CodeWhale","slug":"refusing-to-trust-skill-outside-codewhale-owned-roots","errorCode":null,"errorMessage":"refusing to trust skill outside Codewhale-owned roots","messagePattern":"refusing to trust skill outside Codewhale-owned roots","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/skills/mutation.rs","lineNumber":975,"sourceCode":"    Ok(SkillMutationReceipt {\n        action: SkillActionKind::Remove,\n        name: skill_id.canonical_name,\n        scope,\n        safe_target_path: safe_display_path(&path, Some(ctx.workspace), ctx.home),\n        before_digest: before,\n        after_digest: None,\n        outcome: SkillMutationOutcome::Removed,\n    })\n}\n\nfn trust_skill(\n    skill_id: AuditedSkillId,\n    expected_digest: String,\n    ctx: &MutationContext<'_>,\n) -> Result<SkillMutationReceipt> {\n    let (skill, path) = find_audited_skill(ctx, &skill_id)?;\n    if !skill.root.is_writable_owned() {\n        bail!(\"refusing to trust skill outside Codewhale-owned roots\");\n    }\n    if skill.source_kind != SkillSourceKind::CodeWhaleManaged {\n        bail!(\"only Codewhale managed skills can be trusted\");\n    }\n    validate_owned_skill_path(ctx, &skill, &path)?;\n    let before = verify_expected_digest(&path, Some(&expected_digest))?;\n    validate_owned_skill_path(ctx, &skill, &path)?;\n    write_trust_v2(&path, &expected_digest)?;\n    let scope = match skill.root.kind {\n        SkillRootKind::CodeWhaleProject => SkillScope::Project,\n        SkillRootKind::CodeWhaleGlobal => SkillScope::Global,\n        _ => SkillScope::Logical,\n    };\n    Ok(SkillMutationReceipt {\n        action: SkillActionKind::Trust,\n        name: skill_id.canonical_name,\n        scope,\n        safe_target_path: safe_display_path(&path, Some(ctx.workspace), ctx.home),","sourceCodeStart":957,"sourceCodeEnd":993,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/skills/mutation.rs#L957-L993","documentation":"trust_skill() refuses to mark a skill as trusted when its root does not pass skill.root.is_writable_owned(), i.e. the skill lives outside roots that Codewhale owns and can write. Trust records are bound to the skill's on-disk digest, so trusting a skill outside managed roots would create a trust attestation the library cannot enforce or update. This is a trust-boundary guard, checked before the managed-source check and digest verification.","triggerScenarios":"Calling trust_skill (directly or via trust_writes_v2_digest_binding / execute_sync) with a skill_id whose skill.root is a non-owned (e.g. user home, external path, read-only mount) skill root.","commonSituations":"A user points Codewhale at skills stored in a shared or personal directory and then tries to trust one; or a symlink/config change moved a previously-owned skill outside managed roots.","solutions":["Move or reinstall the skill into a Codewhale-owned root (project or global skills dir) before trusting it","Check skill.root.is_writable_owned() before calling trust_skill","Update the skills-root configuration so the skill's directory is registered as an owned, writable root","Trust the skill manually via the UI/configuration if supported, accepting it stays outside managed roots"],"exampleFix":"// before\nctx.trust_skill(skill_id, digest)?; // skill lives in ~/.my-skills\n// after\n// move the skill into the managed project skills dir first\n// ~/.codewhale/skills/<name> or .codewhale/skills/<name>, then:\nctx.trust_skill(skill_id, digest)?;","handlingStrategy":"validation","validationCode":"if !skill.root.is_writable_owned() { return Err(anyhow!(\"skill root is not owned; move it into a Codewhale skills dir\")); }","typeGuard":"fn trustable_root(s: &Skill) -> bool { s.root.is_writable_owned() && matches!(s.source_kind, SkillSourceKind::CodeWhaleManaged) }","tryCatchPattern":null,"preventionTips":["Keep all trusted skills inside configured Codewhale-owned roots","Verify root ownership in UI before enabling trust actions","Reinstall rather than symlink external skill directories into managed roots"],"tags":["rust","skills","trust","permissions"],"backgroundTag":"permission-denied","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}