Repository navigation
Marketplace registration - #677
SarthakJoshi18 wants to merge 50 commits into
Conversation
Replace the previous PRD revision. Package versions and package comparison are out of scope for v1; the remaining requirements are unchanged.
…place placeholder' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…ling' Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
A skill is any folder with a SKILL.md, at any depth, so both skills/{skillName}/ and plugins/{plugin}/skills/{skillName}/ work. All other files in the folder are documents. Duplicate skill names keep the first and log a warning. Tested against clear-route/claude-skills-marketplace: 7 of 7 skills found.
Allow callers to classify GitHub and Redis outages with errors.Is while preserving their underlying causes. Refs: https://app.notion.com/768d125495bf82108a27013e0da17ee8
… search, pagination and field projection
Refs: docs/adr/2026-08-28-marketplace-adr-backend.md
Add a signed delegation token row to TestControllerAuthorization. Check that the delegation reaches the policy evaluator, and that requests without a delegation header send none. ticket: https://app.notion.com/p/3ded125495bf80fe9f7bf0f5cc9b1c34
Service calls FetchTree, then FetchSkills, but Crawler had no FetchSkills. Crawl now calls FetchTree, then FetchSkills. ticket: https://app.notion.com/p/3ded125495bf809aa8d8ed09b1f096dc
…down The policy bundle poll used context.Background(), so it did not stop at shutdown. main.go now passes backgroundCtx to initServer. stopBackground ends the poll and the registry watch after the server stops. ApplyEnvOverrides requires GITHUB_APP_ID, GITHUB_APP_INSTALLATION_ID and GITHUB_APP_PRIVATE_KEY_PATH, as "Wire typed config" specifies. The config tests cover each missing variable and the policy defaults. ticket: https://app.notion.com/p/3ded125495bf809aa8d8ed09b1f096dc
Keep the published source list and source statuses up to date. - Add a controller for source creation, spec changes, and deletion. - Update sources after tenant approval changes, suspension, reactivation, deletion, and periodic checks. - Share one aggregator between both controllers and register the source controller at startup. - Ignore source status changes to prevent repeated runs. - Add tests for source status, approvals, removal, and failed writes. - Test that tenant changes leave other tenants' sources unchanged. Refs: https://app.notion.com/p/3f9d125495bf819d9525ea1a2e1e8ffd
Add repository approval and a marketplace source to the existing local fixtures. Document the setup and required GitHub access. Refs: https://app.notion.com/p/3f9d125495bf81bd94cbef843a5b84ec
…arketplace-registration # Conflicts: # backend/internal/operator/skillmarketplacesource_controller.go # backend/internal/operator/skillmarketplacesource_controller_test.go # deploy/local/README.md
Visual WalkthroughThis change adds skill marketplace source registration, from the CRD to the skills-service read path. Registration componentsA SkillMarketplaceSource flows through the operator into the sources ConfigMap, which the skills service reads. flowchart TB
src[SkillMarketplaceSource CR]
tenant[OrbitTenant allowlist]
subgraph operator [Operator]
rec[Reconciler]
agg[Aggregator]
end
cm[Sources ConfigMap]
subgraph skillsService [Skills service]
reg[Registry]
ctl[Controller]
svc[Service]
crawl[Crawler]
end
gh[GitHub API]
src --> rec
rec --> agg
tenant --> agg
agg --> cm
cm --> reg
ctl --> svc
reg --> svc
svc --> crawl
crawl --> gh
classDef added fill:#1f883d,stroke:#1a7f37,stroke-width:2px,color:#ffffff
classDef changed fill:#bf8700,stroke:#9a6700,stroke-width:2px,color:#ffffff
classDef removed fill:#cf222e,stroke:#a40e26,stroke-width:2px,stroke-dasharray:5,color:#ffffff
classDef context fill:transparent,stroke:#8c959f,stroke-width:1px,stroke-dasharray:3,color:#8c959f
linkStyle default stroke:#8c959f,stroke-width:2px
class src,rec,agg,cm,reg,ctl,svc,crawl added
class tenant,gh context
style operator fill:transparent,stroke:#8c959f
style skillsService fill:transparent,stroke:#8c959f
Legend: green = added, amber = changed, red = removed, dashed grey = context
Operator verdict pathsOnly aggregated sources reach the sources file, and each source gets a status verdict. sequenceDiagram
participant K as Kubernetes API
participant R as Reconciler
participant A as Aggregator
participant C as Sources ConfigMap
K->>R: source created or spec changed
R->>A: sync all sources
A->>K: list tenants and sources
A->>C: patch rendered sources file
loop each source with a changed verdict
alt namespace is system namespace
A->>K: status Invalid, global sources
else no active tenant
A->>K: status Pending, tenant not active
else name already held
A->>K: status Invalid, duplicate name
else repo already held
A->>K: status Invalid, duplicate repository
else repo not allowlisted
A->>K: status Pending, not allowlisted
else aggregated
A->>K: status Aggregated
end
end
Skill read pathA skills request checks the cursor, the declared sources and the cache before it crawls GitHub. sequenceDiagram
participant C as Controller
participant S as Service
participant R as Registry
participant K as Cache
participant W as Crawler
participant G as GitHub
C->>S: list or get skill
alt cursor is invalid
S-->>C: 400 invalid cursor
else cursor is valid
S->>R: find source by slug
alt slug not declared
S-->>C: 404 marketplace not found
else slug declared
S->>K: read cached entries
alt cache read fails
S-->>C: 503 unavailable
else cache hit
K-->>S: sorted entries
S-->>C: skills page
else cache miss
S->>W: fetch tree and skills
W->>G: read repository files
alt rate limited or GitHub down
G-->>W: failure
W-->>S: failure
S-->>C: 503 unavailable
else crawl succeeds
G-->>W: file contents
W-->>S: skill entries
S->>K: store entries
S-->>C: skills page
end
end
end
end
|
There was a problem hiding this comment.
Walkthrough
The pull request adds skill marketplace source registration with a skills-service, operator aggregator and frontend pages. It also renames the Terra design system package to Hades and adds sandbox environments and run scheduling.
| Severity | Finding | Location |
|---|---|---|
| Remove merge-conflict markers and duplicate index entries | docs/adr/README.md:130 |
|
| Restrict the LOCAL_TENANT_ID auth bypass to local environments | backend/internal/skills/handlers_skills_entry.go:53 |
|
| Mint the installation token under a detached context | backend/internal/skills/token.go:172 |
|
| Cap the size of fetched raw content | backend/internal/platform/clients/github/client.go:336 |
|
| Escape path segments separately in the contents URL | backend/internal/platform/clients/github/client.go:317 |
|
| Backfill not_before for runs already pending | backend/cmd/orbit-agents/migrations/20261012025607_run_scheduling_queue.sql:9 |
|
| Does searchRepoQualifier treat OR queries as repo-scoped? | backend/internal/credentials/adapters/githubapp/githubapp.go:361 |
|
| Honor skillsService.replicas, pull secrets and scheduling | charts/orbit/templates/skills-service/deployment.yaml:11 |
|
| Do not rebuild the skill slug inline | frontend/src/app/(dashboard)/marketplace/[marketplace]/_components/skills-page.tsx:67 |
|
| Revalidate the sandbox image only when it changed | backend/internal/agents/environments.go:308 |
|
| Is tenant-controlled spec.image restricted to allowed registries? | backend/internal/operator/sandboximage_registry.go:58 |
Further minor points: setting-row.test.tsx:18 queries .text-[11.5px] but the class is text-[11px], so the absence test cannot fail; GetTree and GetRawContent errors, the nit-level test and doc mismatches in ADR 2026-10-13 (stale 8085 bullet, template comment) and docs/prd/agent-marketplace.md diverging from the base branch.
Review effort: Very high. Split into marketplace, sandbox and scheduling, and the Hades rename.
Risk: High, changes authentication bypass, stored data schema and public APIs
Coverage: 1093 of 1093 files reviewed
Where to focus
| Area | Why it needs a person |
|---|---|
backend/internal/skills |
Confirm the auth bypass and token sharing behave safely in production. |
backend/internal/credentials/adapters/githubapp |
Decide whether search query scoping can leak other repositories. |
backend/cmd/orbit-agents/migrations |
Verify pending runs survive the scheduling queue migration. |
charts/orbit/templates/skills-service |
Confirm the template should match sibling services' scheduling and replicas. |
backend/internal/operator |
Decide which registry hosts tenants may reference. |
Lower risk
| Area | Why |
|---|---|
frontend/src/packages/hades |
Mechanical Terra to Hades rename with stories and tests. |
frontend/src/app/(dashboard)/model-gateway |
Import path rename only. |
frontend/src/app/(dashboard)/policy |
Import path rename only. |
docs/adr |
Documentation and renamed ADR text. |
Changes by area
| Area | Files | Change |
|---|---|---|
backend/ |
220 | Skills service, operator marketplace and sandbox images, run scheduling, inference gateway System One. |
frontend/src/app |
319 | Marketplace pages, agent overview, environments wizard, Hades imports. |
frontend/src/packages |
285 | Terra package renamed to Hades. |
charts/, deploy/ |
40 | New skills-service chart, CRDs, sandbox mount and values. |
docs/ |
70 | New ADRs and PRDs, renames. |
.github/, scripts, build |
25 | CI gates, bake and version pins. |
Checked
Inference gateway routes, egress gateway, trigger deliveries, Hades rename consistency.
| - [Hades Wizard Component](2026-08-03-terra-wizard-component.md) — `Proposed` · 2026-08-03 | ||
| - [Agent Marketplace — Cache-Aside, Tenant-Scoped Redis Keys, and Resource-Aware Skills](2026-08-28-marketplace-adr-backend.md) — `Proposed` · 2026-08-28 | ||
| - [Hades Wizard Component](2026-08-03-terra-wizard-component.md) — `Proposed` · 2026-08-03 | ||
| >>>>>>> origin/main |
There was a problem hiding this comment.
|
|
||
| var middleware mw.MiddlewareHandler | ||
|
|
||
| if localTenantID != "" { |
There was a problem hiding this comment.
Restrict the LOCAL_TENANT_ID auth bypass to local environments
Problem: Setting LOCAL_TENANT_ID skips authentication, delegation and scope checks. Nothing limits it to local runs, so one stray env var in a deployed pod exposes every route.
Fix: Reject LOCAL_TENANT_ID in ApplyEnvOverrides unless the environment is local.
| p.inflight = ch | ||
| p.mu.Unlock() | ||
|
|
||
| res := p.mint(ctx) |
There was a problem hiding this comment.
| return nil, statusError(resp, c.HandleErrorResponse(span, resp, ErrUnexpectedStatus)) | ||
| } | ||
|
|
||
| data, err := io.ReadAll(resp.Body) |
| // Returns an error that matches ErrUnavailable when GitHub is down or | ||
| // rate-limits the call. | ||
| func (c *Client) GetRawContent(ctx context.Context, token, org, repo, ref, path string) ([]byte, error) { | ||
| endpoint := fmt.Sprintf("%s/repos/%s/%s/contents/%s?ref=%s", c.baseURL, url.PathEscape(org), url.PathEscape(repo), url.PathEscape(path), url.QueryEscape(ref)) |
| // searchRepoQualifier returns the repository name when every repo:owner/name | ||
| // term in q names the same repository of owner, and "" otherwise. A negated | ||
| // -repo: term never scopes the query. | ||
| func searchRepoQualifier(q, owner string) string { |
There was a problem hiding this comment.
Does searchRepoQualifier treat OR queries as repo-scoped?
Problem: A query such as repo:o/a OR is:open yields the qualifier a, yet GitHub boolean search may return results from other repositories under a grant limited to one repository.. Question: return an empty qualifier when the query has OR or parentheses?
| app: orbit-skills-service | ||
|
|
||
| spec: | ||
| replicas: 1 |
There was a problem hiding this comment.
Honor skillsService.replicas, pull secrets and scheduling
Problem: replicas: 1 ignores skillsService.replicas. The pod spec also omits orbit.imagePullSecrets and orbit.scheduling, which policy-service includes, so private registries and node selectors are ignored.
Fix: Use the value and add the two includes as in policy-service/deployment.yaml.
| ) : ( | ||
| <Stack gap="snug"> | ||
| {filtered.map((skill) => { | ||
| const skillSlug = skill.name |
There was a problem hiding this comment.
Do not rebuild the skill slug inline
Problem: The inline regex strips _, . and non-ASCII characters, so a skill named pdf_tools links as pdftools and the detail page reports not found. marketplaceSlug duplicates similar logic.
Fix: Link with the raw skill name, which the route helper already encodes.
| return nil, ErrEnvironmentNameTaken | ||
| } | ||
| env.CreatedAt = existing.CreatedAt | ||
| if err = s.validate(ctx, env); err != nil { |
There was a problem hiding this comment.
| break | ||
| } | ||
| } | ||
| parsed, err := name.ParseReference(ref, opts...) |
df4a76a to
c215a15
Compare
|
Superseded by #225 |
What and why
How it was tested
Checklist
make checkpasses.