feat(plugins): automate plugin release publishing on Cloudflare#63
Conversation
Add tag-driven plugin release automation with immutable artifact paths, signing, and catalog updates so plugin releases deploy consistently without per-plugin workflow changes.
|
No actionable comments were generated in the recent review. 🎉 📝 WalkthroughWalkthroughAdds an automated, tag-driven plugin publishing pipeline that resolves plugin metadata, builds WASM artifacts, signs and verifies bundles with cosign, conditionally publishes to OCI, generates a web catalog, and optionally deploys to Cloudflare Pages. Also adds plugin metadata, catalog artifacts, headers, and doc updates. Changes
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub Actions
participant Resolver as Resolver (Python step)
participant Cargo as Cargo/WASM Build
participant Catalog as Catalog Generator
participant Cosign as Cosign
participant OCI as OCI Registry
participant Pages as Cloudflare Pages
GH->>Resolver: Trigger (tag or manual) -> resolve plugin_id, path, version
Resolver->>GH: emit meta outputs (paths, urls, flags)
GH->>Cargo: build wasm (wasm32-wasip1) using meta outputs
Cargo->>GH: produce wasm artifact
GH->>Catalog: assemble bundle, compute sha256, write plugin-manifest.json & catalog.json
GH->>Cosign: sign artifact (keyed or keyless)
Cosign->>GH: return signature (+certificate if keyless)
GH->>Cosign: verify signature in CI
GH->>OCI: optional push bundle to OCI (if configured)
GH->>Pages: build catalog site and deploy to Cloudflare Pages (optional)
GH->>GH: upload artifacts and post step summary (URLs, digests)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Contributor ReportUser: @yacosta738
Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-02-21 to 2026-02-21 |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (2)
clients/web/apps/plugins/src/pages/index.astro (1)
27-34: Hardcoded version0.1.0will drift as the plugin evolves.These endpoint entries and curl examples hard-code
memory.surreal.graphs/0.1.0. Since the catalog at/catalog.jsonis the canonical runtime source for the latest version, consider either:
- Noting in the UI that these are versioned (immutable) examples and directing users to
/catalog.jsonfor the current version, or- Adding a brief comment in source indicating this section needs updating when a new version is tagged.
Also applies to: 47-52
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@clients/web/apps/plugins/src/pages/index.astro` around lines 27 - 34, Replace the hardcoded version string "memory.surreal.graphs/0.1.0" used inside the <p class="endpoint"> code elements and any other occurrences (e.g., the second occurrence at lines ~47-52) by either 1) adding a visible note in the UI near those <p class="endpoint"> elements that these are immutable, versioned examples and directing users to the canonical runtime catalog at "/catalog.json" for the latest version, or 2) adding a short inline source comment next to the code strings (the literal "memory.surreal.graphs/0.1.0") reminding maintainers to update these entries when a new plugin tag is published; ensure you update both occurrences shown and keep the displayed example path unchanged if you choose the UI note option..github/workflows/publish-plugins.yml (1)
347-364: Concurrent publishes of different plugins can clobber each other's catalog entries.The catalog upsert reads its base from the repo checkout (
clients/web/apps/plugins/public/catalog.json). Since the concurrency group is per-ref (plugins-publish-${{ github.ref }}), two different plugin tags can run simultaneously. Both start from the same base catalog, each adds only its own plugin, and whichever Cloudflare deploy finishes last overwrites the other's entry.This is acceptable for a single-plugin setup today but will cause data loss when multiple plugins are published in close succession. Consider serializing all plugin publishes under a single concurrency group, or fetching the live catalog from Cloudflare before upserting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/publish-plugins.yml around lines 347 - 364, The current upsert reads from the repo file (source_catalog / catalog_payload / existing_plugins) which allows concurrent jobs to clobber each other; modify the workflow to fetch the live published catalog from Cloudflare (or the deployment origin) before merging: retrieve the remote catalog JSON, fall back to {"plugins": []} if missing, validate it's a list, then perform the merge by filtering out existing plugin.id and appending plugin_entry (use the same filtered variable logic), sort by id and write the updated catalog to dist_dir/"catalog.json"; alternatively, change the GitHub Actions concurrency key to a single global group name so publishes are serialized (i.e., update the concurrency group instead of reading the repo file) — implement one of these two fixes and keep validation/error handling for malformed catalogs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/publish-plugins.yml:
- Around line 412-438: The workflow unconditionally passes --output-certificate
to cosign even when COSIGN_PRIVATE_KEY is set, but key-based signing (seen in
the sign-blob branch that checks COSIGN_PRIVATE_KEY) does not produce a Fulcio
identity certificate, so certificate_path will be meaningless and downstream
steps (the oras push that tries to include the .pem and the cp that stages it)
will fail under set -euo pipefail; fix by changing the sign step to only include
--output-certificate "$certificate_path" when COSIGN_PRIVATE_KEY is empty (i.e.,
in keyless mode), or alternately add file-existence guards before the downstream
oras push / cp steps to skip including/copying certificate_path when the .pem
does not exist, ensuring variables signature_path, certificate_path and
artifact_path remain consistent.
In `@clients/agent-runtime/src/onboard/wizard.rs`:
- Around line 2772-2775: The assignment config = bootstrap.memory overwrites the
user's explicit auto_save choice when install_and_handle_surreal_graphs falls
back to markdown; change the merge to preserve the user's auto_save (and any
other user-provided flags) by merging rather than blindly replacing: after
calling install_and_handle_surreal_graphs(&mut bootstrap, true) check if
bootstrap.memory.backend != backend and then set config = bootstrap.memory but
copy config.auto_save = previous_config.auto_save (or copy any non-default
user-driven fields from the original config into bootstrap.memory) so that the
user's auto_save preference survives the fallback; use the existing names
config, bootstrap.memory, install_and_handle_surreal_graphs, and
memory_config_defaults_for_backend("markdown") to locate and update the logic.
In `@clients/web/apps/docs/src/content/docs/es/guides/plugins.md`:
- Around line 118-158: In the workflow description fix three Spanish/i18n
issues: in the signature step text "si no keyless" (item starting with "Firma el
artefacto con cosign") add the missing comma or rephrase to "si no, keyless" or
"o bien keyless OIDC si no existe"; change "del app" to "de la app" in the
Cloudflare deploy line that currently reads "Hace build del app de catálogo y
deploy a Cloudflare Pages"; and replace "límites/capabilities" with
"límites/capacidades" in the important integration instructions (the line that
lists "Define límites/capabilities en `package.metadata.corvus`").
In `@clients/web/apps/plugins/public/_headers`:
- Around line 11-33: Add the missing CORS header to each artifact rule in the
_headers file so cross-origin fetches and WebAssembly.instantiateStreaming calls
succeed; for every block that starts with paths like "/artifacts/*/*/*.wasm",
"/artifacts/*/*/*.json", "/artifacts/*/*/*.sig", "/artifacts/*/*/*.pem", and the
catch-all "/artifacts/*/*/*", add the header "Access-Control-Allow-Origin: *"
alongside the existing Cache-Control and X-Content-Type-Options entries.
- Around line 11-33: Add CORS headers to the artifact routes so cross-origin
WASM/JSON fetches succeed: update each header block for the patterns
"/artifacts/*/*/*.wasm", "/artifacts/*/*/*.json", "/artifacts/*/*/*.sig",
"/artifacts/*/*/*.pem", and the catch-all "/artifacts/*/*/*" to include
"Access-Control-Allow-Origin: *" (or a scoped origin) and optionally
"Access-Control-Allow-Methods: GET, OPTIONS" and "Access-Control-Allow-Headers:
Content-Type" to cover browser preflight requests.
- Around line 11-33: The new `_headers` rules use multiple splats (e.g.
/artifacts/*/*/*.wasm, /artifacts/*/*/*.json, /artifacts/*/*/*.sig,
/artifacts/*/*/*.pem, /artifacts/*/*/*) which Cloudflare Pages rejects because
it allows only one splat; replace these with single-splat or placeholder-style
patterns such as /artifacts/:seg1/:seg2/:seg3 (or a single splat
/artifacts/:path* for a catch-all) and move shared Cache-Control and
X-Content-Type-Options entries under that single pattern; if you need
per-extension Content-Type overrides (since you referenced
.wasm/.json/.sig/.pem), implement a Pages Function (e.g.
functions/artifacts/[[path]].ts) to detect the file extension and set
Content-Type accordingly while leaving cache and security headers in the
`_headers` single-pattern rule.
- Around line 31-33: Keep the existing specific patterns for .wasm, .json, .sig,
and .pem (they correctly precede the catch-all under Netlify's "first match
wins") and do not change those; update the catch-all rule for /artifacts/*/*/*
to include a default Content-Type (for example, add "Content-Type:
application/octet-stream") so unknown/new artifact extensions still get a safe
type hint while retaining the long cache header "Cache-Control: public,
max-age=31536000, immutable".
In `@clients/web/apps/plugins/public/catalog.json`:
- Around line 2-27: The catalog entry for plugin id "memory.surreal.graphs" is
missing the required "signature" block (same omission as in the plugin
manifest); update the catalog JSON entry to include a "signature" object that
matches the schema your publish workflow and runtime expect (e.g., the same
signature fields used in the plugin-manifest.json such as signature value, key
id/type or algorithm and any timestamp/metadata), ensuring the "artifact.digest"
and "signature" correspond to the signed artifact so the catalog upsert and
runtime validation succeed.
---
Nitpick comments:
In @.github/workflows/publish-plugins.yml:
- Around line 347-364: The current upsert reads from the repo file
(source_catalog / catalog_payload / existing_plugins) which allows concurrent
jobs to clobber each other; modify the workflow to fetch the live published
catalog from Cloudflare (or the deployment origin) before merging: retrieve the
remote catalog JSON, fall back to {"plugins": []} if missing, validate it's a
list, then perform the merge by filtering out existing plugin.id and appending
plugin_entry (use the same filtered variable logic), sort by id and write the
updated catalog to dist_dir/"catalog.json"; alternatively, change the GitHub
Actions concurrency key to a single global group name so publishes are
serialized (i.e., update the concurrency group instead of reading the repo file)
— implement one of these two fixes and keep validation/error handling for
malformed catalogs.
In `@clients/web/apps/plugins/src/pages/index.astro`:
- Around line 27-34: Replace the hardcoded version string
"memory.surreal.graphs/0.1.0" used inside the <p class="endpoint"> code elements
and any other occurrences (e.g., the second occurrence at lines ~47-52) by
either 1) adding a visible note in the UI near those <p class="endpoint">
elements that these are immutable, versioned examples and directing users to the
canonical runtime catalog at "/catalog.json" for the latest version, or 2)
adding a short inline source comment next to the code strings (the literal
"memory.surreal.graphs/0.1.0") reminding maintainers to update these entries
when a new plugin tag is published; ensure you update both occurrences shown and
keep the displayed example path unchanged if you choose the UI note option.
Deploying corvus-plugins with
|
| Latest commit: |
0d526c3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://041d8db0.corvus-plugins.pages.dev |
| Branch Preview URL: | https://feature-plugins.corvus-plugins.pages.dev |
Deploying corvus with
|
| Latest commit: |
0d526c3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://431f37ac.corvus-42x.pages.dev |
| Branch Preview URL: | https://feature-plugins.corvus-42x.pages.dev |
Add tag-driven plugin release automation with immutable artifact paths, signing, and catalog updates so plugin releases deploy consistently without per-plugin workflow changes.
Summary by CodeRabbit
New Features
Documentation
Infrastructure