feat: browser UI v2 — repository version picker + sanitized SKILL.md render (spec 003)#216
Merged
Conversation
… drawer (spec 003 v2)
Adds two additive drawer features on top of the existing browser console:
a Raw/Rendered toggle for SKILL.md (Rendered fetches ?format=html, trusting
the server's comrak+ammonia sanitization for the one intentional innerHTML
assignment), and a version picker for repository-origin skills only
(fetches /registry/skills/{id}/versions, applies via POST /skills/update
with { skillId, version }), gated on the existing writable capability.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0153XpJc4DrMRAJJqVDchxRm
…r, version-pinned update (spec 003 v2)
Adds the three backend v2 add-ons for spec 003 browser skill management:
GET /api/v1/registry/skills/{id}/versions (sourced from PackageResolver over
the same SourcesManager the other /registry/* browse routes use, sorted
descending by semver), GET /api/v1/skills/{id}/content?format=html (comrak
render + ammonia allowlist-sanitize, safe for innerHTML), and version-pinned
POST /api/v1/skills/update via a new `version` field that resolves to an exact
VersionConstraint pin on a repository-origin skill's Origin.
…rsion-pinned update)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The two deferred v2 items from spec 003 (browser skill management). Grilled the two consequential forks, built by parallel sonnet agents, opus-reviewed (verdict: SHIP, sanitization boundary double-verified with an adversarial probe).
1. Repository version picker
GET /api/v1/registry/skills/{id}/versions→{ id, versions: [{version, repo?}] }, sorted newest-first (semver desc, unparseable lowest). Empty list →200(not 404) when no registry/unknown id.repository-origin skills only (git/local/zip-url are versionless). Picking a version →POST /skills/update { skillId, version }, which pins the repositoryOrigin'sVersionConstraintand re-installs viaadd_from_origin(Update)— recorded in manifest + lock.versionwithoutskillId→ 400;versionon a non-repository origin → 400. Update stays write-gated.2. Sanitized SKILL.md render
GET /api/v1/skills/{id}/content?format=html|raw(defaultraw, unchanged).htmlrenders Markdown server-side withcomrak(safe mode, no raw-HTML passthrough) then allowlist-sanitizes withammoniabefore returning.<pre>, default). Rendered assigns the server-sanitized HTML viainnerHTML— the one intentional, clearly-commented trust boundary; sanitization is entirely server-side (no client-side markdown parser or sanitizer, keeping the no-build ethos). Belt-and-suspendersrel="noopener noreferrer"pass over rendered links.Security
Opus review confirmed the sanitization boundary sound and ran an adversarial probe (mixed-case
javascript:, base64/svgdata:URIs,<svg><script>, entity-encoded hrefs,<style>url(javascript:)) — every executable vector neutralized. Path-confinement on the content endpoint unchanged. Version string is parsed viaVersionConstraint, never interpolated into a path or shelled. Test asserts a malicious SKILL.md payload is absent from rendered output.Testing
Full workspace
cargo test+clippy -D warningsgreen. New tests: versions endpoint (populated + empty + unknown-id), semver-desc sort,?format=htmlsanitization (payload stripped), version-pinned update happy path (wiremock registry, asserts=2.0.0pin) + both 400 guards.Deps
Adds
comrak+ammonia(Cargo deps; no build-step change).Follow-up (not in this PR)
/registry/*handlers resolve the project from process cwd rather thanAppState.project_file_path. Not a serve bug today (serve derivesAppStatefrom the same fixed cwd), but worth threadingproject_file_paththrough for consistency and to drop the test cwd-serialization — a latent mismatch only if a future--projectoverride is added.🤖 Generated with Claude Code