feat(#3597): skills marketplace route improvements and runtime config#3599
feat(#3597): skills marketplace route improvements and runtime config#3599fullsend-ai-coder[bot] wants to merge 1 commit into
Conversation
Refactor skills marketplace routes per openspec section 8 tasks: - 8b.1: Add boost.skillsMarketplace.runtimes[] Zod schema to schemas.ts with yaml-only scope defining runtime fields (id, name, description, image, language, footprint, features, status) - 8b.2: Refactor GET /skills/runtimes to read from local app-config instead of proxying to external catalog - 8c.1: Change POST /skills/deploy to accept runtimeId instead of ociImage; resolve container image from configured runtimes - 8c.2: Extract manifest generation into manifestBuilder.ts with buildDeploymentManifest() and validateRfc1123Label() functions - 8c.3: Add manifestBuilder unit tests and update deploy tests for runtimeId resolution - 8a.3: Add proxy tests for GET /skills and GET /skills/domains covering URL construction, query param forwarding, feature gate, permission checks, and non-JSON upstream handling Additional improvements from issue review section: - Add boostAdminPermission fallback to requireAccess middleware matching the pattern in chat/routes.ts and mcp/routes.ts - Add AbortSignal.timeout() to proxyToSkillsCatalog fetch calls - Validate skillId and deployment name against K8s RFC 1123 rules - Accept separate resources.requests and resources.limits in deploy Closes #3597
Missing ChangesetsThe following package(s) are changed by this PR but do not have a changeset:
See CONTRIBUTING.md for more information about how to add changesets. Changed Packages
|
|
|
|
🤖 Finished Review · ✅ Success · Started 2:36 AM UTC · Completed 2:47 AM UTC |
ReviewFindingsHigh
Medium
Low
Labels: PR modifies boost workspace backend plugin with feature-level route and schema changes. |
| * @public | ||
| */ | ||
| export function validateRfc1123Label(value: string, fieldName: string): void { | ||
| if (!RFC_1123_LABEL_RE.test(value)) { |
There was a problem hiding this comment.
[high] error-handling
validateRfc1123Label throws a plain Error, but the Backstage Express error handler maps error types by name: InputError -> 400, NotAllowedError -> 403, NotFoundError -> 404, and everything else -> 500. Since this function throws a generic Error, invalid user input (bad skillId or deployment name) surfaces as HTTP 500 Internal Server Error instead of HTTP 400 Bad Request. The test at routes.test.ts explicitly asserts expect(res.status).toBe(500) for an RFC 1123 violation, confirming the wrong behavior is encoded as expected.
Suggested fix: Change validateRfc1123Label to throw InputError from @backstage/errors instead of a plain Error. Update the test assertion from toBe(500) to toBe(400).
| // Resolve container image from configured runtimes | ||
| const runtimes = getRuntimes(); | ||
| const runtime = runtimes.find(r => r.id === runtimeId); | ||
| if (!runtime) { |
There was a problem hiding this comment.
[medium] input-validation
The namespace parameter from req.body flows directly into the K8s Deployment manifest without RFC 1123 validation. Both skillId and name are validated via validateRfc1123Label, but namespace is not.
Suggested fix: Add validateRfc1123Label(deploymentNamespace, 'namespace') after the namespace is resolved.
| @@ -96,10 +145,22 @@ export function createSkillsRoutes(options: SkillsRoutesOptions): Router { | |||
| [{ permission: boostAccessPermission }], | |||
There was a problem hiding this comment.
[low] permission-scope-change
The requireAccess middleware now grants access to users with boostAdminPermission as a fallback when boostAccessPermission is denied. This widens the set of identities that can access read endpoints. The change is consistent with the same pattern used in chat/routes.ts and chat/conversationRoutes.ts.
| requireSkillsEnabled, | ||
| requireAdmin, | ||
| async (req, res, next) => { | ||
| try { |
There was a problem hiding this comment.
[low] data-exposure
The GET /skills/runtimes endpoint returns the full SkillRuntime object including the image field (OCI container registry URL) to any user with boost access permission. The config field description states 'The backend resolves runtimeId to an image server-side so frontends never see registry URLs,' but the runtimes endpoint exposes these URLs.
Suggested fix: Strip the image field from the runtime objects returned by the GET /skills/runtimes endpoint.
| // Resolve container image from configured runtimes | ||
| const runtimes = getRuntimes(); | ||
| const runtime = runtimes.find(r => r.id === runtimeId); | ||
| if (!runtime) { |
There was a problem hiding this comment.
[low] input-validation
The resources object from req.body contains arbitrary user-supplied strings placed directly into the K8s Deployment manifest without format validation.



Refactor skills marketplace routes per openspec section 8 tasks:
schemas.ts with yaml-only scope defining runtime fields (id,
name, description, image, language, footprint, features, status)
instead of proxying to external catalog
ociImage; resolve container image from configured runtimes
buildDeploymentManifest() and validateRfc1123Label() functions
runtimeId resolution
covering URL construction, query param forwarding, feature gate,
permission checks, and non-JSON upstream handling
Additional improvements from issue review section:
matching the pattern in chat/routes.ts and mcp/routes.ts
Closes #3597
Post-script verification
agent/3597-skills-routes-improvements)d196266107606e76ba67a676678bc15c6972d338..HEAD)