Skip to content

ci: add reusable plugin-validate workflow for plugin repositories#19

Merged
byrongamatos merged 2 commits into
mainfrom
feat/reusable-plugin-validate
Jul 23, 2026
Merged

ci: add reusable plugin-validate workflow for plugin repositories#19
byrongamatos merged 2 commits into
mainfrom
feat/reusable-plugin-validate

Conversation

@gionnibgud

@gionnibgud gionnibgud commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What

Adds .github/workflows/plugin-validate.yml with on: workflow_call, plus a short README pointer. Any plugin repository can now run this spec's validator as its own CI gate in three lines:

jobs:
  validate:
    uses: got-feedback/feedBack-plugin-spec/.github/workflows/plugin-validate.yml@main

Why

tools/validate.py resolves schemas/plugin.schema.json relative to this repo, so plugin repos can't run it without either a second checkout or vendoring the schema — and a vendored copy of the compliance check itself is guaranteed drift. This workflow keeps the schema and validation logic single-sourced here.

Before validating, the plugin is staged under a directory named from its manifest id, so a repo named feedBack-plugin-foo with id foo still gets spec §5.2 (directory name == id) enforced — against the staged copy, matching how the plugin actually sits in a Host's plugins/ directory after installation.

Context

Groundwork for a proposed org-owned feedBack-plugin-template starter repo (being discussed in the dev channel): a GitHub template repository giving community plugin authors a compliant starting point — AGPL-3.0-only license, DCO notice, schema-valid manifest, tests, and this validation gate green from day one. That shifts compliance from review-time catch-up to a red X the author fixes before anyone looks. This PR is the prerequisite: the template's CI calls this workflow instead of duplicating it.

Notes

  • Tooling/CI only — no normative spec, schema, or example change, so no PSEP issue and no version bump (tools/check_versions.py passes unchanged).
  • Not wired into this repo's own CI: validate.yml already covers the examples via direct script invocation.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a reusable CI workflow for validating plugin repositories against the shared plugin specification.
    • Validation now checks plugin schemas and discovery requirements automatically.
  • Documentation

    • Added instructions and a configuration example for enabling validation in a plugin repository’s CI pipeline.

Lets any plugin repository run the spec's validator as its own CI gate in
three lines (uses: .../plugin-validate.yml@main) instead of vendoring the
schema or validator, which would drift. The plugin is staged under a
directory named from its manifest id before validation, so repository
naming conventions (feedBack-plugin-<id>) don't conflict with spec §5.2.

Groundwork for an org-owned feedBack-plugin-template starter repo, where
community plugins get this gate green from day one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: gionnibgud <gionnibgud@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@gionnibgud, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 92737411-599c-47b9-9cf2-941f8a94a3c7

📥 Commits

Reviewing files that changed from the base of the PR and between ba5382b and 98054ff.

📒 Files selected for processing (1)
  • .github/workflows/plugin-validate.yml
📝 Walkthrough

Walkthrough

Adds a reusable GitHub Actions workflow for checking out a plugin and specification ref, staging the plugin by manifest ID, and running shared validation. README documentation provides an example caller workflow.

Changes

Plugin validation workflow

Layer / File(s) Summary
Workflow contract and validation runtime
.github/workflows/plugin-validate.yml
Defines plugin-dir and spec-ref inputs, checks out both repositories, and installs Python 3.12 with jsonschema.
Plugin staging and documented invocation
.github/workflows/plugin-validate.yml, README.md
Stages plugin contents under the manifest ID, runs spec/tools/validate.py, and documents reusable workflow usage.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PluginRepository
  participant plugin_validate
  participant SpecRepository
  participant GitHubActionsRunner
  PluginRepository->>plugin_validate: Invoke reusable workflow
  plugin_validate->>GitHubActionsRunner: Start validation job
  GitHubActionsRunner->>PluginRepository: Check out plugin
  GitHubActionsRunner->>SpecRepository: Check out selected spec ref
  GitHubActionsRunner->>GitHubActionsRunner: Stage plugin by manifest id
  GitHubActionsRunner->>SpecRepository: Run validate.py on staged plugin
Loading

Suggested reviewers: byrongamatos

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main CI change: adding a reusable plugin-validate workflow for plugin repositories.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/reusable-plugin-validate

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/plugin-validate.yml:
- Around line 40-51: Update both actions/checkout steps in the plugin validation
workflow, including the “Check out plugin” and “Check out spec” steps, to set
persist-credentials to false while preserving their existing repository, ref,
and path settings.
- Around line 60-69: Harden the staging step around SRC and manifest ID
extraction: pass inputs.plugin-dir through an environment variable instead of
interpolating it in the shell, safely handle missing or invalid plugin.json and
absent id by using a deterministic fallback ID so validate.py can report schema
errors, and reject or sanitize IDs containing path separators or traversal
components before creating staged/$ID. Preserve the existing copy and STAGED
environment setup for valid manifests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8e74c2a3-6882-4bde-90ae-1e13bd7dcb95

📥 Commits

Reviewing files that changed from the base of the PR and between 53955b4 and ba5382b.

📒 Files selected for processing (2)
  • .github/workflows/plugin-validate.yml
  • README.md

Comment thread .github/workflows/plugin-validate.yml
Comment thread .github/workflows/plugin-validate.yml
Addresses review findings on the reusable workflow:

- persist-credentials: false on both checkouts; the workflow only reads
  files and never pushes, so the token has no reason to stay in the
  runner's git config.
- Pass plugin-dir via env instead of interpolating ${{ }} into the shell,
  removing the template-injection surface.
- Sanitise and default the manifest id before it reaches mkdir/cp. This
  step runs before validate.py, so the schema's id pattern is not yet
  enforced and the manifest is still untrusted: strip path components and
  fall back to a placeholder when plugin.json is missing, unparseable, or
  has no id.

The fallback also improves diagnostics — a bad manifest now produces
validate.py's own error (missing 'id', invalid JSON, no plugin.json)
instead of an opaque shell traceback from the staging step.

Verified against five fixtures (valid, id-less, traversal id, absent
manifest, malformed JSON): staging always succeeds, traversal stays
contained, and each invalid case fails in validate.py with its specific
message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: gionnibgud <gionnibgud@gmail.com>
@gionnibgud

Copy link
Copy Markdown
Contributor Author

Thanks — both findings were valid and are addressed in 98054ff.

1. persist-credentials: false on both checkouts — applied as suggested. The workflow only reads files and never pushes, so there's no reason for the token to stay in the runner's git config.

2. Staging step — all three sub-points applied:

  • Template injection: plugin-dir now arrives via env: instead of being interpolated into the shell.
  • Path traversal: the id is stripped to its basename before it reaches mkdir/cp. Worth noting why this is needed even though schemas/plugin.schema.json already constrains id to ^[a-z0-9][a-z0-9_-]*$: staging runs before validate.py, so at that moment the manifest is exactly the thing we haven't checked yet.
  • Missing/invalid manifest: falls back to a placeholder id rather than raising under set -eu. Agreed this is the better behaviour — the point of the step is to let validate.py produce the diagnostic, and a KeyError traceback from a bash step is a worse developer experience than 'id' is a required property.

Verified locally by extracting the step from the parsed YAML and running it against five fixtures:

Fixture Staging Result
valid (examples/full-plugin) staged/full-plugin ok
id removed staged/invalid-manifest schema: (root): 'id' is a required property
id: "../../pwned" staged/pwned (contained) schema pattern + §5.2 mismatch
no plugin.json staged/invalid-manifest no plugin.json in ...
malformed JSON staged/invalid-manifest plugin.json is not valid JSON: ...

Staging exits 0 in every case; each invalid one fails in validate.py with its specific message.

@byrongamatos
byrongamatos merged commit b2e32ba into main Jul 23, 2026
7 of 8 checks passed
@byrongamatos
byrongamatos deleted the feat/reusable-plugin-validate branch July 23, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants