`check-plugin-content-sync` was the only local pre-push hook scoped with `files:` instead of `always_run`, and its regex missed both compiled `plugin.json` paths — exactly the manifests the script had been taught to diff. A commit tampering only with one of those passed the entire pre-push suite at exit 0. A regex fix alone could not close it: pre-commit drops deleted paths from the file list, so removing a mirror directory skipped the hook too. The `hooks\.json` alternative was also already dead, matching only the pre-move flat path. Dropping `files:` for `always_run: true` closes all three and makes the hook uniform with its three siblings; the check costs ~2-4s. Also excludes `.github/plugin/marketplace.json` from `pretty-format-json`. This was not hypothetical: `json.dumps(indent=2, sort_keys=True)` reproduces the manifests committed at HEAD byte-for-byte, so `--autofix` had already rewritten compiled apm output once. Without the exclusion it would do so again on the next commit, silently breaking the byte-identical mirror invariant. Landing first, ahead of the regenerated manifests, so that cannot happen. Refs: #90 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X7GvKuJfy2WrdBmUttV4DT
205 lines
7.9 KiB
YAML
205 lines
7.9 KiB
YAML
repos:
|
|
- repo: https://github.com/compilerla/conventional-pre-commit
|
|
rev: v2.4.0
|
|
hooks:
|
|
- id: conventional-pre-commit
|
|
stages: [commit-msg]
|
|
|
|
- repo: https://github.com/gitleaks/gitleaks
|
|
rev: v8.21.2
|
|
hooks:
|
|
- id: gitleaks
|
|
stages: ['pre-commit']
|
|
|
|
- repo: https://github.com/jumanjihouse/pre-commit-hooks
|
|
rev: 3.0.0
|
|
hooks:
|
|
- id: shellcheck
|
|
args: [--severity=warning]
|
|
stages: ['pre-commit']
|
|
|
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
rev: v4.5.0
|
|
hooks:
|
|
- id: end-of-file-fixer
|
|
stages: ['pre-commit']
|
|
- id: check-json
|
|
stages: ['pre-commit']
|
|
- id: pretty-format-json
|
|
stages: ['pre-commit']
|
|
args: [--autofix]
|
|
exclude: '(^|/)(\.claude-plugin/plugin\.json|\.github/plugin/plugin\.json|\.claude-plugin/marketplace\.json|\.github/plugin/marketplace\.json)$|^\.agents/plugins/marketplace\.json$'
|
|
- id: check-yaml
|
|
stages: ['pre-commit']
|
|
- id: trailing-whitespace
|
|
stages: ['pre-commit']
|
|
- id: check-merge-conflict
|
|
stages: ['pre-commit']
|
|
- id: detect-private-key
|
|
stages: ['pre-commit']
|
|
- id: check-toml
|
|
stages: ['pre-commit']
|
|
- id: check-ast
|
|
stages: ['pre-commit']
|
|
|
|
- repo: local
|
|
hooks:
|
|
- id: run-tests
|
|
name: Run test suite
|
|
description: Run all test-*.sh files and bats suite
|
|
entry: bash tests/run-tests.sh
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: check-manifests
|
|
name: Check plugin manifests
|
|
description: Validate marketplace.json and plugin.json paths
|
|
entry: bash scripts/check-manifests.sh
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: check-plugin-content-sync
|
|
name: Check plugin content sync
|
|
description: Verify each plugin's flat skills/agents/commands/hooks/hooks.json mirror is in sync with .apm/ -- Claude Code has no .apm/ awareness so this compiled mirror must stay current (see issue #90)
|
|
entry: bash scripts/sync-plugin-content.sh --check --all
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: check-marketplace-mirror-sync
|
|
name: Check marketplace mirror sync
|
|
description: Verify .github/plugin/marketplace.json (Copilot CLI's legacy manifest path) is byte-identical to .claude-plugin/marketplace.json -- apm has no output profile for this path, so it must be kept in sync explicitly (see issue #90)
|
|
entry: bash scripts/sync-marketplace-mirror.sh --check
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: apm-marketplace-check
|
|
name: apm marketplace check
|
|
description: Validate every marketplace.packages[] entry resolves, including network reachability of remote refs -- catches stale/unreachable remote package references that check-manifests.sh deliberately skips (local-source checks only)
|
|
entry: apm marketplace check
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: apm-audit-ci
|
|
name: apm audit --ci
|
|
description: apm's own producer-side lockfile/policy/hidden-content integrity gate, per apm's documented recommended CI block (see docs/research/docs/microsoft-apm/testing-and-validation.md)
|
|
entry: apm audit --ci
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: apm-pack-check-clean
|
|
name: apm pack --check-clean
|
|
description: Release gate -- verify .claude-plugin/marketplace.json still matches what apm.yml + .apm/ would currently generate, and that per-package versions agree with the per_package versioning strategy. Closes issue #90's deferred item 3 (a check-clean-equivalent gate) using apm's own flag instead of custom drift logic.
|
|
entry: apm pack --check-versions --check-clean --dry-run
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: check-vale-style-sync
|
|
name: Check Vale style copies are in sync
|
|
description: Diff skill-audit's Vale copy against agent-audit's canonical copy
|
|
entry: bash scripts/check-vale-style-sync.sh
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: check-scope-walkup-sync
|
|
name: Check scope walk-up implementations agree
|
|
description: Behaviorally cross-check validate.sh, validate-provenance.sh, new-agent.sh, and new-skill.sh's independent $HOME/.git/apm.yml walk-up ports against each other
|
|
entry: bash scripts/check-scope-walkup-sync.sh
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: check-release-needed
|
|
name: Check a release tag covers .pre-commit-hooks.yaml's paths
|
|
description: On push to main only, fail if files exposed via .pre-commit-hooks.yaml changed since the last tag
|
|
entry: bash scripts/check-release-needed.sh
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: validate-plugins
|
|
name: Validate plugins
|
|
description: Run claude plugin validate --strict on every plugin directory
|
|
entry: bash -c 'for d in plugins/*/; do claude plugin validate --strict "$d" || exit 1; done'
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: validate-marketplace
|
|
name: Validate marketplace manifest
|
|
description: Run claude plugin validate --strict on the root marketplace manifest
|
|
entry: claude plugin validate --strict .claude-plugin/marketplace.json
|
|
language: system
|
|
stages: [pre-push]
|
|
pass_filenames: false
|
|
always_run: true
|
|
|
|
- id: skill-frontmatter
|
|
stages: ['pre-commit']
|
|
name: SKILL.md frontmatter validation
|
|
description: Ensure SKILL.md files have required frontmatter fields
|
|
entry: bash
|
|
language: system
|
|
files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$'
|
|
args:
|
|
- -c
|
|
- |
|
|
for f in "$@"; do
|
|
if [[ -f "$f" ]]; then
|
|
if ! grep -q "^name:" "$f" || ! grep -q "^description:" "$f"; then
|
|
echo "ERROR: $f is missing required frontmatter fields (name: and description:)"
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|
|
|
|
- id: skill-size-check
|
|
stages: ['pre-commit']
|
|
name: SKILL.md size ceiling
|
|
description: Enforce agentskills.io's 500-line/5,000-token SKILL.md size ceiling
|
|
entry: scripts/skill-size-check.sh
|
|
language: script
|
|
files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$'
|
|
pass_filenames: true
|
|
|
|
- id: vale-audit-prefilter-skill
|
|
stages: ['pre-commit']
|
|
name: Vale audit prefilter (SKILL.md)
|
|
description: Run Vale against SKILL.md files as a deterministic prefilter for skill-audit, via skill-audit's own bundled copy
|
|
entry: plugins/kyberforge/.apm/skills/skill-audit/scripts/vale-wrap.sh
|
|
language: script
|
|
files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$'
|
|
pass_filenames: true
|
|
|
|
- id: vale-audit-prefilter-agent
|
|
stages: ['pre-commit']
|
|
name: Vale audit prefilter (agent files)
|
|
description: Run Vale against agent markdown files as a deterministic prefilter for agent-audit, via agent-audit's own bundled copy
|
|
entry: plugins/kyberforge/.apm/skills/agent-audit/scripts/vale-wrap.sh
|
|
language: script
|
|
files: '^plugins/[^/]+/\.apm/agents/[^/]+\.agent\.md$'
|
|
pass_filenames: true
|
|
|
|
- repo: meta
|
|
hooks:
|
|
- id: check-hooks-apply
|
|
- id: check-useless-excludes
|