Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:
# This repo ships skills, hook scripts, and JSON manifests with no application
# package manager, so the only ecosystem to keep current is the pinned GitHub
# Actions in .github/workflows.
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
patterns: ["*"]
34 changes: 34 additions & 0 deletions .github/workflows/actions-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Actions Security

on:
push:
branches: [main]
paths: [".github/workflows/**"]
pull_request:
branches: [main]
paths: [".github/workflows/**"]

permissions:
contents: read

concurrency:
group: actions-lint-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
zizmor:
name: zizmor (workflow audit)
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Run zizmor
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pipx install zizmor
zizmor --min-severity=medium .github/workflows/
75 changes: 60 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ on:
permissions:
contents: read

# Cancel superseded runs on the same ref so rapid pushes don't pile up runners.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
validate:
name: Validate plugin structure
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Validate JSON files
run: |
Expand All @@ -28,6 +35,24 @@ jobs:
fi
done

# Belt-and-suspenders: parse every committed JSON file (manifests +
# fixtures), not just the three core manifests above. node is preinstalled
# on ubuntu-latest; node_modules/.git are excluded.
- name: Validate all JSON parses
run: |
set -euo pipefail
fail=0
while IFS= read -r -d '' f; do
if node -e "JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'))" "$f"; then
echo " [ok] $f"
else
echo " [FAIL] invalid JSON: $f"
fail=1
fi
done < <(find . -name '*.json' \
-not -path './.git/*' -not -path '*/node_modules/*' -not -path '*/dist/*' -print0)
exit $fail

- name: Validate plugin version consistency
run: |
echo "── Version consistency ──"
Expand Down Expand Up @@ -87,21 +112,41 @@ jobs:
exit $FAIL

shellcheck:
name: Shellcheck hooks
name: Shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Run shellcheck on hook scripts
# shellcheck is preinstalled on ubuntu-latest. Scope to error severity so
# the gate catches real bugs without failing on stylistic notes. Covers
# every committed *.sh (hooks, libs, installers, tests), not just hooks/.
- name: Run shellcheck on all shell scripts
run: |
echo "── Shellcheck ──"
FAIL=0
for f in hooks/*.sh test-local.sh; do
if shellcheck --severity=error "$f"; then
echo " [ok] $f"
else
echo " [FAIL] $f"
FAIL=1
fi
done
exit $FAIL
set -euo pipefail
shellcheck --version
mapfile -d '' files < <(find . -name '*.sh' \
-not -path './.git/*' -not -path '*/node_modules/*' -print0)
if [ ${#files[@]} -eq 0 ]; then
echo "no shell scripts found"; exit 0
fi
printf 'checking: %s\n' "${files[@]}"
shellcheck --severity=error "${files[@]}"

# ── Aggregate gate ───────────────────────────────────────────────────────
# One stable required-status-check context. Fails if any upstream job failed
# OR was skipped/cancelled, so the job graph can be reshaped without orphaning
# the required check.
ci-success:
name: CI Passed
if: always()
needs: [validate, shellcheck]
runs-on: ubuntu-latest
steps:
- name: Verify all required jobs succeeded
run: |
echo "validate=${{ needs.validate.result }}"
echo "shellcheck=${{ needs.shellcheck.result }}"
[ "${{ needs.validate.result }}" = "success" ] \
&& [ "${{ needs.shellcheck.result }}" = "success" ]
38 changes: 38 additions & 0 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Secret Scan

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

concurrency:
group: secrets-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
gitleaks:
name: gitleaks
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0 # scan full history
persist-credentials: false
# The gitleaks GitHub Action requires a paid license for org accounts, but
# the gitleaks binary itself is free (MIT). Run it directly.
- name: Install gitleaks
env:
GITLEAKS_VERSION: "8.30.1"
run: |
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xz -C /usr/local/bin gitleaks
gitleaks version
- name: Scan repository
run: gitleaks dir . --redact --verbose --exit-code 1
4 changes: 4 additions & 0 deletions .github/zizmor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# zizmor configuration. All findings are fixed in-place (least-privilege
# permissions + persist-credentials: false on every checkout), so there are
# currently no accepted exceptions to record here.
rules: {}