fix(validate-plugin): kind-aware content check for code-class plugins #38

Merged
core-devops merged 3 commits from fix/validate-plugin-kind-aware-content into main 2026-06-22 05:58:22 +00:00
Member

Root cause

validate-plugin.py check #5 ("Has content") only accepted skill-class markers
(SKILL.md/hooks//skills//rules/) and was unaware of plugin.yaml kind.

molecule-ai/molecule-ai-plugin-gh-identity is a Go kind: env-mutator
plugin whose content is a Go module (go.mod) wired through an entrypoint
(pluginloader.BuildRegistry) plus an embedded wrapper.sh — none of the
skill markers. So its CI / validate job hard-failed on:

::error::Plugin must contain at least one of: SKILL.md, hooks/, skills/, rules/

This was a documented true-positive-of-the-wrong-contract (see that repo's
ci.yml header) blocked on the validator-semantics gap. It turned the plugin's
CI / validate (push) red on main HEAD.

Fix

Make check #5 kind-aware:

  • Skill-class plugins (kind unset / skill / agent-skill / claude-skill):
    unchanged — must ship at least one skill marker.
  • Code-class plugins (any other explicit kind, e.g. env-mutator):
    content = go.mod and a declared entrypoint. Both are required so
    setting kind: alone can't let an empty repo pass.

Verified: the new validator returns exit 0 against the real gh-identity
checkout and still fails an empty repo / a kind:-only repo with no go.mod.

Both copies of the script are updated (scripts/ and .molecule-ci/scripts/
the gh-identity CI fetches the latter; they are kept byte-identical).

Tests

New scripts/test_validate_plugin.py (runs in the existing pytest job):
11 subprocess-driven cases covering skill-class accept, code-class accept,
kind:-only / missing-go.mod / missing-entrypoint rejects, and the
required-field/version/runtimes shape checks. All green locally.

Follow-up (not in this PR)

Once merged, molecule-ai-plugin-gh-identity's CI / validate goes green on
its next run (it fetches this script fresh each run). The CI / validate
context can then be made BP-required there per RFC internal#476 P1.

🤖 Generated with Claude Code

## Root cause `validate-plugin.py` check #5 ("Has content") only accepted skill-class markers (`SKILL.md`/`hooks/`/`skills/`/`rules/`) and was unaware of `plugin.yaml` `kind`. `molecule-ai/molecule-ai-plugin-gh-identity` is a Go **`kind: env-mutator`** plugin whose content is a Go module (`go.mod`) wired through an `entrypoint` (`pluginloader.BuildRegistry`) plus an embedded `wrapper.sh` — none of the skill markers. So its `CI / validate` job hard-failed on: ``` ::error::Plugin must contain at least one of: SKILL.md, hooks/, skills/, rules/ ``` This was a documented true-positive-of-the-wrong-contract (see that repo's ci.yml header) blocked on the validator-semantics gap. It turned the plugin's `CI / validate (push)` red on main HEAD. ## Fix Make check #5 **kind-aware**: - **Skill-class** plugins (kind unset / `skill` / `agent-skill` / `claude-skill`): unchanged — must ship at least one skill marker. - **Code-class** plugins (any other explicit `kind`, e.g. `env-mutator`): content = `go.mod` **and** a declared `entrypoint`. Both are required so setting `kind:` alone can't let an empty repo pass. Verified: the new validator returns exit 0 against the real gh-identity checkout and still fails an empty repo / a `kind:`-only repo with no `go.mod`. Both copies of the script are updated (`scripts/` and `.molecule-ci/scripts/` — the gh-identity CI fetches the latter; they are kept byte-identical). ## Tests New `scripts/test_validate_plugin.py` (runs in the existing `pytest` job): 11 subprocess-driven cases covering skill-class accept, code-class accept, `kind:`-only / missing-`go.mod` / missing-`entrypoint` rejects, and the required-field/version/runtimes shape checks. All green locally. ## Follow-up (not in this PR) Once merged, `molecule-ai-plugin-gh-identity`'s `CI / validate` goes green on its next run (it fetches this script fresh each run). The `CI / validate` context can then be made BP-required there per RFC internal#476 P1. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
core-devops added 3 commits 2026-06-22 05:51:39 +00:00
Recognise code-class plugins (kind: env-mutator) whose content is a Go
module + entrypoint rather than SKILL.md/hooks/skills/rules. Fixes the
false positive that red-flagged molecule-gh-identity (RFC internal#476 P1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recognise code-class plugins (kind: env-mutator) whose content is a Go
module + entrypoint rather than SKILL.md/hooks/skills/rules. Fixes the
false positive that red-flagged molecule-gh-identity (RFC internal#476 P1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(validate-plugin): pin kind-aware content contract
CI / Workflow YAML lint (pull_request) Successful in 4s
CI / Python script lint (pull_request) Successful in 11s
CI / Validator pytest suites (pull_request) Successful in 16s
CI / Secrets scan (pull_request) Successful in 17s
3ca1a54a2f
Subprocess-driven suite covering skill-class (SKILL.md/skills) and
code-class (kind: env-mutator + go.mod + entrypoint) plugins, plus the
required-field/version/runtimes shape checks. Regression guard for the
gh-identity false positive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
molecule-code-reviewer approved these changes 2026-06-22 05:54:46 +00:00
molecule-code-reviewer left a comment
Member

Reviewed for correctness and contract integrity.

  • The content check is now kind-aware with correct precedence: skill markers accepted unconditionally → else non-skill kind requires go.mod AND entrypoint → else (skill kind, no markers) the original error. Backward compatible: unset/skill/agent-skill/claude-skill stay skill-class.
  • kind: alone cannot let an empty repo pass — go.mod + entrypoint are both required for the code-class path. Good fail-closed posture.
  • Both copies (scripts/ and .molecule-ci/scripts/) updated identically; gh-identity CI fetches the latter.
  • New test_validate_plugin.py is subprocess-driven (the validator isn't import-safe / calls sys.exit), exercising the exact CI entrypoint, and covers skill-accept, code-accept, the three reject branches, and the shape checks. CI Validator pytest suites is green.
  • Verified independently: the new validator returns exit 0 against the real gh-identity checkout.

Sound, minimal, no weakening of any existing check. Approve.

Reviewed for correctness and contract integrity. - The content check is now kind-aware with correct precedence: skill markers accepted unconditionally → else non-skill `kind` requires `go.mod` AND `entrypoint` → else (skill kind, no markers) the original error. Backward compatible: unset/`skill`/`agent-skill`/`claude-skill` stay skill-class. - `kind:` alone cannot let an empty repo pass — go.mod + entrypoint are both required for the code-class path. Good fail-closed posture. - Both copies (`scripts/` and `.molecule-ci/scripts/`) updated identically; gh-identity CI fetches the latter. - New `test_validate_plugin.py` is subprocess-driven (the validator isn't import-safe / calls sys.exit), exercising the exact CI entrypoint, and covers skill-accept, code-accept, the three reject branches, and the shape checks. CI `Validator pytest suites` is green. - Verified independently: the new validator returns exit 0 against the real gh-identity checkout. Sound, minimal, no weakening of any existing check. Approve.
core-security approved these changes 2026-06-22 05:54:46 +00:00
core-security left a comment
Member

Security review.

  • No reduction in gate strength: the secrets-scan check and required-field checks are untouched; the content check only ADDS an accept path for code-class plugins, and that path still requires real content (go.mod + entrypoint) so an empty repo cannot pass by setting kind:.
  • No new inputs trusted from the plugin under test beyond the already-parsed plugin.yaml; no shell/exec, no path traversal introduced (os.path.isfile("go.mod") is cwd-relative as before).
  • Test additions run in tmpdirs via subprocess, no network, no secrets.

No security concerns. Approve.

Security review. - No reduction in gate strength: the secrets-scan check and required-field checks are untouched; the content check only ADDS an accept path for code-class plugins, and that path still requires real content (go.mod + entrypoint) so an empty repo cannot pass by setting `kind:`. - No new inputs trusted from the plugin under test beyond the already-parsed plugin.yaml; no shell/exec, no path traversal introduced (`os.path.isfile("go.mod")` is cwd-relative as before). - Test additions run in tmpdirs via subprocess, no network, no secrets. No security concerns. Approve.
core-devops scheduled this pull request to auto merge when all checks succeed 2026-06-22 05:58:21 +00:00
core-devops merged commit 0a9b39ffc8 into main 2026-06-22 05:58:22 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-ci#38