feat(skills): privacy/visibility controls for agent-owned skills#1011
feat(skills): privacy/visibility controls for agent-owned skills#1011
Conversation
Closes #1009 - Add private/public visibility enum with validator + normalizer (internal/skills/visibility.go) - Add IsSkillVisibleTo/FilterVisibleSkills authorization helper with three-identity ownership check (actor/user/sender) matching #915 - Propagate owner_id into SkillInfo and all PG/SQLite SELECTs so the filter has the data it needs - Agent injection path (FilterSkills, nil allowList) now hides private skills owned by other users — fixes the leak vector across tenant members - publish_skill: accept visibility param (defaults to private), replaces hardcoded literal - skill_manage: visibility settable on create and editable via patch, including a content-less visibility-only patch that skips version bump - skills.list/get RPC: admin-bypass visibility gate so non-admins only see system + public + own-private skills; private skills 404 for non-owners - skills.update RPC: validate + normalize visibility enum before persist (fail closed on unknown values)
|
@claude review |
|
Claude finished @mrgoonie's task in 2m 40s —— View job PR Review: feat(skills): privacy/visibility controls for agent-owned skillsTasks:
SummarySolid security feature overall — the core visibility model ( 🔴 Critical:
|
…th-first - Add MsgInvalidVisibility i18n key (en/vi/zh) and use it in skills.update RPC instead of raw validator error text. - Reorder skills.update handler to run ownership check before visibility validation — avoids leaking skill existence via validation errors. - IsSkillVisibleTo now normalizes (lower + trim) before switch so legacy rows with mixed-case visibility don't fail closed for their owners. - Extend TestIsSkillVisibleTo with uppercase/whitespace cases.
Closes #1009
Summary
private/publicvisibility enum (validator + normalizer) ininternal/skills/visibility.go. Default:private.IsSkillVisibleTo/FilterVisibleSkillsauthorization helper ininternal/store/visibility_filter.go, using the same three-identity ownership check (actor/user/sender) introduced for Bug - Telegram group:write_filechecks writer permission againstgroup:telegram:<id>instead of sender user #915.owner_idintoSkillInfoand all PG/SQLite SELECTs so the filter has the data it needs.FilterSkillswith nil allowList) now hides other users' private skills — closes the leak across tenant members.publish_skill: acceptvisibilityparameter (replaces hardcoded"private").skill_manage: visibility settable oncreateand editable viapatch, including a content-less visibility-only patch path (no version bump).skills.list/skills.getRPC: admin bypass + visibility gate — non-admins only see system + public + own-private skills; private skills404for non-owners.skills.updateRPC: validate + normalize visibility enum before persist (fail closed on unknown).Test plan
go build ./...(PG) greengo build -tags sqliteonly ./...(desktop/lite) greengo vet ./...cleanTestValidateVisibility,TestNormalizeVisibility,TestIsSkillVisibleTo,TestFilterVisibleSkillspassinternal/skills,internal/store/...,internal/tools,internal/gateway/...)skills.listdoes not include it →skills.getreturns NotFoundNotes
teamvisibility rejected in v1 (deferred until team-scoping semantics resolved) — surfaces as validator error.visibilitytreated as public; private rows withoutowner_idalso treated as public to avoid hiding legacy/system-like records.