-
Notifications
You must be signed in to change notification settings - Fork 0
Publish RP extension catalog with Pigments #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| name: RP extension catalog | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - "release/rp-stable" | ||
| push: | ||
| branches: | ||
| - "release/rp-stable" | ||
| schedule: | ||
| - cron: "17 5 * * *" | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: rp-extension-catalog | ||
| cancel-in-progress: false | ||
|
|
||
| env: | ||
| ZED_EXTENSION_CLI_SHA: 9ee3c503a4bbbc6b4a0f8a789acca4871d773223 | ||
|
|
||
| jobs: | ||
| validate: | ||
| if: github.repository == 'JonathonRP/extensions' | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 20 | ||
| steps: | ||
| - name: Checkout catalog | ||
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Fetch upstream | ||
| run: | | ||
| git remote add upstream https://github.com/zed-industries/extensions.git | ||
| git fetch --no-tags upstream main | ||
| echo "UPSTREAM_REVISION=$(git merge-base HEAD upstream/main)" >> "$GITHUB_ENV" | ||
|
|
||
| - uses: pnpm/setup@5d160c5bc68a09337ad0d5654e237e03253b5879 # v1 | ||
| with: | ||
| version: 11 | ||
| runtime: node@24.20.0 | ||
| cache: true | ||
|
|
||
| - name: Validate registry | ||
| run: | | ||
| pnpm install --frozen-lockfile | ||
| pnpm build | ||
| pnpm test | ||
| pnpm validate-rp-registry | ||
|
|
||
| - uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1 | ||
| with: | ||
| toolchain: "1.90" | ||
| target: "wasm32-wasip2" | ||
|
|
||
| - name: Package Pigments with official tooling | ||
| run: | | ||
| git submodule update --init --depth 1 extensions/pigments-lsp | ||
| wget --quiet "https://zed-extension-cli.nyc3.digitaloceanspaces.com/$ZED_EXTENSION_CLI_SHA/x86_64-unknown-linux-gnu/zed-extension" | ||
| chmod +x zed-extension | ||
| pnpm package-extensions pigments-lsp | ||
| env: | ||
| REF_NAME: ${{ github.ref_name }} | ||
| RUSTUP_TOOLCHAIN: "1.90" | ||
| SHOULD_PUBLISH: "false" | ||
|
|
||
| - name: Preserve package | ||
| if: github.event_name != 'pull_request' | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | ||
| with: | ||
| name: rp-pigments-package | ||
| path: | | ||
| output/archive.tar.gz | ||
| output/manifest.json | ||
| if-no-files-found: error | ||
|
|
||
| publish: | ||
| if: github.repository == 'JonathonRP/extensions' && github.event_name != 'pull_request' && github.ref == 'refs/heads/release/rp-stable' | ||
| needs: validate | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 120 | ||
| permissions: | ||
| contents: read | ||
| pages: write | ||
| id-token: write | ||
| attestations: write | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| steps: | ||
| - name: Checkout catalog | ||
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Fetch upstream | ||
| run: | | ||
| git remote add upstream https://github.com/zed-industries/extensions.git | ||
| git fetch --no-tags upstream main | ||
| echo "UPSTREAM_REVISION=$(git merge-base HEAD upstream/main)" >> "$GITHUB_ENV" | ||
| echo "FORK_REVISION=$(git rev-parse HEAD)" >> "$GITHUB_ENV" | ||
|
|
||
| - uses: pnpm/setup@5d160c5bc68a09337ad0d5654e237e03253b5879 # v1 | ||
| with: | ||
| version: 11 | ||
| runtime: node@24.20.0 | ||
| cache: true | ||
|
|
||
| - name: Restore packaged Pigments | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | ||
| with: | ||
| name: rp-pigments-package | ||
| path: output | ||
|
|
||
| - name: Generate complete integrity catalog | ||
| run: | | ||
| pnpm install --frozen-lockfile | ||
| pnpm generate-rp-catalog | ||
| env: | ||
| CURRENT_CATALOG_URL: https://jonathonrp.github.io/extensions/rp-catalog/v1/catalog.json | ||
| RP_CATALOG_CONCURRENCY: "8" | ||
|
|
||
| - name: Configure Pages | ||
| uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 | ||
|
|
||
| - name: Attest catalog provenance | ||
| uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 # v3 | ||
| with: | ||
| subject-path: public/rp-catalog/v1/catalog.json | ||
|
|
||
| - name: Upload Pages artifact | ||
| uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 | ||
| with: | ||
| path: public | ||
|
|
||
| - name: Deploy Pages | ||
| id: deployment | ||
| uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # RP Extensions catalog | ||
|
|
||
| `JonathonRP/extensions` is a history-preserving fork of | ||
| `zed-industries/extensions`. Its `main` branch is reserved for clean upstream | ||
| fast-forwards. The default, persistent `release/rp-stable` branch mirrors an | ||
| identified upstream revision and carries declared RP additions. | ||
|
|
||
| ## Endpoint | ||
|
|
||
| - Catalog: <https://jonathonrp.github.io/extensions/rp-catalog/v1/catalog.json> | ||
| - Catalog SHA-256: <https://jonathonrp.github.io/extensions/rp-catalog/v1/catalog.json.sha256> | ||
| - JSON Schema: <https://jonathonrp.github.io/extensions/rp-catalog/v1/schema.json> | ||
| - Workflow: <https://github.com/JonathonRP/extensions/actions/workflows/rp-catalog.yml> | ||
|
|
||
| Schema version 1 contains the existing Zed `ExtensionMetadata` fields in | ||
| `data`, all known official version metadata in `versions`, and one integrity | ||
| record per current package in `packages`. Each package binds its ID, version, | ||
| schema/Wasm compatibility, immutable source repository and Git revision, | ||
| archive byte size, archive SHA-256, and HTTPS download URL. | ||
|
|
||
| Official entries use Zed's exact-version download route and permit only its API | ||
| and extension object-store hosts. RP additions are packaged with the same | ||
| pinned `zed-extension` CLI as upstream and are hosted under this Pages site. | ||
| RP clients must verify the catalog digest, allowlisted hosts, archive size and | ||
| SHA-256, then validate the packaged manifest before installation. | ||
|
|
||
| ## Pigments | ||
|
|
||
| ```toml | ||
| [pigments-lsp] | ||
| submodule = "extensions/pigments-lsp" | ||
| path = "zed-pigments" | ||
| version = "0.3.1" | ||
| ``` | ||
|
|
||
| The source is `https://github.com/JonathonRP/zed-pigments.git` pinned to | ||
| `545ee63ba654a57e322e109b09ff249c908c1ec6`. | ||
|
|
||
| ## Publication and sync | ||
|
|
||
| The fork-only workflow is guarded to `JonathonRP/extensions`. It validates pull | ||
| requests targeting `release/rp-stable`, and publishes after pushes to that | ||
| branch, manual dispatches, and a daily 05:17 UTC refresh. Publication fails if | ||
| an upstream entry is removed or modified, an undeclared RP entry appears, the | ||
| Pigments pin changes, package metadata is malformed, or an archive cannot be | ||
| hashed. | ||
|
|
||
| To sync, fetch `zed-industries/extensions`, merge its `main` into | ||
| `release/rp-stable`, resolve only around declared RP files, and open a focused | ||
| fork PR. Never force-push the release branch or overwrite an existing | ||
| ID/version package. GitHub Pages and the official Zed archive service remain | ||
| availability dependencies; RP clients must fail closed rather than silently | ||
| fall back to a partial catalog. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "schema_version": 1, | ||
| "channel": "rp-stable", | ||
| "label": "RP Extensions", | ||
| "base_url": "https://jonathonrp.github.io/extensions/rp-catalog/v1", | ||
| "upstream_repository": "https://github.com/zed-industries/extensions", | ||
| "fork_repository": "https://github.com/JonathonRP/extensions", | ||
| "upstream_api_url": "https://api.zed.dev", | ||
| "upstream_archive_host": "zed-extensions.nyc3.digitaloceanspaces.com", | ||
| "additions": { | ||
| "pigments-lsp": { | ||
| "submodule": "extensions/pigments-lsp", | ||
| "path": "zed-pigments", | ||
| "version": "0.3.1", | ||
| "source_repository": "https://github.com/JonathonRP/zed-pigments.git", | ||
| "source_revision": "545ee63ba654a57e322e109b09ff249c908c1ec6", | ||
| "published_at": "2026-09-02T23:00:44Z" | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| { | ||
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$id": "https://jonathonrp.github.io/extensions/rp-catalog/v1/schema.json", | ||
| "title": "RP Extensions catalog", | ||
| "type": "object", | ||
| "required": [ | ||
| "schema_version", | ||
| "channel", | ||
| "label", | ||
| "generated_at", | ||
| "source", | ||
| "integrity", | ||
| "entry_count", | ||
| "upstream_entry_count", | ||
| "additions", | ||
| "data", | ||
| "versions", | ||
| "packages" | ||
| ], | ||
| "properties": { | ||
| "schema_version": { "const": 1 }, | ||
| "channel": { "const": "rp-stable" }, | ||
| "label": { "const": "RP Extensions" }, | ||
| "generated_at": { "type": "string", "format": "date-time" }, | ||
| "source": { | ||
| "type": "object", | ||
| "required": [ | ||
| "fork_repository", | ||
| "fork_revision", | ||
| "upstream_repository", | ||
| "upstream_revision" | ||
| ] | ||
| }, | ||
| "integrity": { | ||
| "type": "object", | ||
| "required": [ | ||
| "catalog_digest_algorithm", | ||
| "catalog_digest_url", | ||
| "allowed_archive_hosts" | ||
| ] | ||
| }, | ||
| "entry_count": { "type": "integer", "minimum": 1 }, | ||
| "upstream_entry_count": { "type": "integer", "minimum": 1 }, | ||
| "additions": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "object", | ||
| "required": ["id", "version", "source_repository", "source_revision"] | ||
| } | ||
| }, | ||
| "data": { "type": "array" }, | ||
| "versions": { "type": "object" }, | ||
| "packages": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "object", | ||
| "required": [ | ||
| "id", | ||
| "version", | ||
| "schema_version", | ||
| "wasm_api_version", | ||
| "source_repository", | ||
| "source_revision", | ||
| "archive_url", | ||
| "archive_size", | ||
| "archive_sha256" | ||
| ] | ||
| } | ||
|
Comment on lines
+55
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -euo pipefail
# Expect exit status 0 before the fix: package items have no field constraints.
jq -e '
.properties.packages.items as $item
| (($item | has("properties")) | not)
and (($item | has("additionalProperties")) | not)
' rp-catalog.schema.jsonRepository: JonathonRP/extensions Length of output: 164 🏁 Script executed: sed -n '1,90p' rp-catalog.schema.jsonRepository: JonathonRP/extensions Length of output: 1924 Define constraints for each package field.
Define 🤖 Prompt for AI Agents |
||
| } | ||
| }, | ||
| "additionalProperties": false | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Authenticate the packaging CLI before execution.
The workflow downloads and executes
zed-extensionfrom an HTTPS revision-named URL, but does not verify the executable bytes. If that artifact is replaced, the workflow can publish a tampered Pigments package. Pin and verify an official SHA-256, signature, or trusted attestation before granting execute permission.The separate cache-URL concern is not an additional finding here: reuse is gated by equality with the current configured archive URL, so the prior catalog cannot select a different request target.
📍 Affects 2 files
.github/workflows/rp-catalog.yml#L59-L59(this comment)src/generate-rp-catalog.js#L188-L188🤖 Prompt for AI Agents