🛡️ fix: Sanitize Agent List Skill Scope#13122
Conversation
|
@codex review |
There was a problem hiding this comment.
Pull request overview
This PR hardens the /api/agents list response to prevent VIEW callers from receiving raw per-agent skill scope configuration, while still enabling the client to render the $ skill popover using a viewer-scoped “effective” skill scope.
Changes:
- Adds an
includeSkillConfigflag togetListAgentsByAccessto excludeskills/skills_enabledfrom the default projection unless explicitly requested. - Updates the agents list controller to sanitize skill scope for VIEW callers by intersecting configured skills with the caller’s VIEW-accessible skills.
- Adds regression tests covering default projection behavior, safe VIEW list shape, VIEW skill filtering, and EDIT raw skill config behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/data-schemas/src/methods/agent.ts | Adds opt-in projection control (includeSkillConfig) for returning raw skill configuration in list results. |
| packages/data-schemas/src/methods/agent.spec.ts | Updates/extends data-layer tests to lock in the new default projection and the opt-in behavior. |
| api/server/controllers/agents/v1.js | Sanitizes skill scope for VIEW list responses while allowing EDIT list callers to receive raw skill config. |
| api/server/controllers/agents/v1.spec.js | Adds controller-level regression tests for safe VIEW list fields and skill scope filtering behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const hasEditBit = (permission) => (permission & PermissionBits.EDIT) === PermissionBits.EDIT; | ||
|
|
||
| const sanitizeViewerSkillScope = (agent, accessibleSkillSet) => { | ||
| const skillScopeEnabled = agent.skills_enabled === true; | ||
| delete agent.skills_enabled; | ||
|
|
||
| if (!skillScopeEnabled) { | ||
| delete agent.skills; | ||
| return agent; | ||
| } | ||
|
|
||
| const configuredSkills = Array.isArray(agent.skills) ? agent.skills : []; | ||
| if (configuredSkills.length === 0) { | ||
| delete agent.skills; | ||
| if (accessibleSkillSet.size > 0) { | ||
| agent.skills_enabled = true; | ||
| } | ||
| return agent; | ||
| } | ||
|
|
||
| const visibleSkills = configuredSkills | ||
| .map((skillId) => String(skillId)) | ||
| .filter((skillId) => accessibleSkillSet.has(skillId)); | ||
|
|
||
| if (visibleSkills.length === 0) { | ||
| delete agent.skills; | ||
| return agent; | ||
| } | ||
|
|
||
| agent.skills = visibleSkills; | ||
| agent.skills_enabled = true; | ||
| return agent; | ||
| }; |
| let accessibleSkillSet = null; | ||
| if (!canReturnSkillConfig) { | ||
| const accessibleSkillIds = await findAccessibleResources({ | ||
| userId, | ||
| role: req.user.role, | ||
| resourceType: ResourceType.SKILL, | ||
| requiredPermissions: PermissionBits.VIEW, | ||
| }); | ||
| accessibleSkillSet = new Set(accessibleSkillIds.map((oid) => oid.toString())); | ||
| } |
|
Codex Review: Didn't find any major issues. Keep them coming! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
GitNexus: 🚀 deployedThe |
Summary
I fixed the agent list response so VIEW callers no longer receive raw skill-scope configuration, while preserving the
$skill popover behavior through a viewer-scoped effective skill response.includeSkillConfigprojection flag togetListAgentsByAccessso rawskillsandskills_enabledare excluded by default./api/agentsVIEW responses by intersecting configured skill IDs with the caller's VIEW-accessible skill IDs before returning any skill scope.Change Type
Testing
node --check api/server/controllers/agents/v1.js.node --check api/server/controllers/agents/v1.spec.js.git diff --check.apiis missingcross-env, andpackages/data-schemasis missingjest-junit.Test Configuration:
danny-avila/fix-agent-list-skill-scope-leakChecklist