mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-15 17:25:26 -04:00
fix(skills): scope skill reads to caller owner (#777)
read_skill_md and read_skill_reference walk all skill files via _iter_skill_files and return the first match by slug, regardless of owner. In a multi-user deployment where two users have skills with the same slug under different categories, a caller scoped to owner='alice' can read Bob's skill content. This is the same cross-tenant leak class as the update_skill / delete_skill fix (PR #755, merged), but on the read path. Changes: - read_skill_md / read_skill_reference accept owner= param (default None = match ownerless only, matching the write-path convention). - 7 callers updated: tool_implementations.py (view, view_ref, patch), builtin_actions.py (test_skills), skills_routes.py (audit, source, test routes). - Tests: read scoping (alice reads hers, not bob's), positive update scoping (alice can mutate her own), ownerless-match default.
This commit is contained in:
@@ -766,7 +766,7 @@ async def _audit_one_skill(skills_manager, skill, url, model, headers,
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
md = skills_manager.read_skill_md(name)
|
||||
md = skills_manager.read_skill_md(name, owner=owner)
|
||||
if not md:
|
||||
log(f"{name}: no source — skipped")
|
||||
return {"skill": name, "result": "skipped"}
|
||||
@@ -1246,7 +1246,7 @@ def setup_skills_routes(skills_manager: SkillsManager) -> APIRouter:
|
||||
if not match:
|
||||
raise HTTPException(404, "Skill not found")
|
||||
_verify_owner(match, user)
|
||||
md = skills_manager.read_skill_md(match.get("name"))
|
||||
md = skills_manager.read_skill_md(match.get("name"), owner=user)
|
||||
if md is None:
|
||||
raise HTTPException(404, "Skill source unavailable (legacy entry?)")
|
||||
return {"name": match.get("name"), "markdown": md}
|
||||
@@ -1273,7 +1273,7 @@ def setup_skills_routes(skills_manager: SkillsManager) -> APIRouter:
|
||||
raise HTTPException(404, "Skill not found")
|
||||
_verify_owner(match, user)
|
||||
name = match.get("name")
|
||||
md = skills_manager.read_skill_md(name) or ""
|
||||
md = skills_manager.read_skill_md(name, owner=user) or ""
|
||||
|
||||
if not task:
|
||||
task = _skill_test_task(match)
|
||||
|
||||
Reference in New Issue
Block a user