Feat/codescan (#27)

* feat: add Dependabot configuration for GitHub Actions, npm, and pip updates
feat: implement CodeQL analysis workflow for security scanning
fix: update permissions in community advisory workflow for better access control
fix: adjust permissions in poll NVD CVEs workflow for enhanced functionality
fix: update Scorecard workflow to use specific version of upload-sarif action
fix: refine permissions in skill release workflow for improved security and functionality

* feat: add guidance documentation for agents and development setup

* Update .github/workflows/codeql.yml

Co-authored-by: baz-reviewer[bot] <174234987+baz-reviewer[bot]@users.noreply.github.com>

---------

Co-authored-by: baz-reviewer[bot] <174234987+baz-reviewer[bot]@users.noreply.github.com>
This commit is contained in:
davida-ps
2026-02-16 15:00:43 +01:00
committed by GitHub
parent 398bd450ac
commit 65c40f67d9
9 changed files with 211 additions and 20 deletions
+19
View File
@@ -0,0 +1,19 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
- package-ecosystem: "pip"
directory: "/.github"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
+4 -6
View File
@@ -6,6 +6,8 @@ on:
push:
branches: [main]
permissions: read-all
jobs:
lint-typescript:
name: Lint TypeScript/React
@@ -32,14 +34,10 @@ jobs:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'
cache: 'pip'
cache-dependency-path: '.github/requirements-lint-python.txt'
- name: Install linters
run: python -m pip install -r .github/requirements-lint-python.txt
- name: Ruff (lint + format check)
run: ruff check utils/ --output-format=github
run: pipx run --spec "ruff==0.6.9" ruff check utils/ --output-format=github
- name: Bandit (security)
run: bandit -r utils/ -ll
run: pipx run --spec "bandit==1.7.9" bandit -r utils/ -ll
lint-shell:
name: Lint Shell Scripts
+41
View File
@@ -0,0 +1,41 @@
name: CodeQL
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "17 3 * * 1"
permissions: read-all
jobs:
analyze:
name: Analyze (CodeQL)
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ["javascript-typescript"]
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Initialize CodeQL
uses: github/codeql-action/init@9e907b5e64f6b83e7804b09294d44122997950d6 # v4
with:
languages: ${{ matrix.language }}
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@9e907b5e64f6b83e7804b09294d44122997950d6 # v4
+5 -4
View File
@@ -4,10 +4,7 @@ on:
issues:
types: [labeled]
permissions:
contents: write
issues: write
pull-requests: write
permissions: read-all
concurrency:
group: community-advisory
@@ -23,6 +20,10 @@ jobs:
process-advisory:
if: github.event.label.name == 'advisory-approved'
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+4 -3
View File
@@ -12,9 +12,7 @@ on:
default: 'false'
type: boolean
permissions:
contents: write
pull-requests: write
permissions: read-all
concurrency:
group: poll-nvd-cves
@@ -31,6 +29,9 @@ env:
jobs:
poll-and-update:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+1 -1
View File
@@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@a4e1a019f5e24960714ff6296aee04b736cbc3cf # v3.29.6
with:
sarif_file: results.sarif
+9 -6
View File
@@ -15,10 +15,7 @@ on:
required: true
type: string
permissions:
contents: write
pages: write
id-token: write
permissions: read-all
concurrency:
group: skill-release-${{ github.ref }}
@@ -505,6 +502,8 @@ jobs:
release-tag:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
skill_name: ${{ steps.parse.outputs.skill_name }}
version: ${{ steps.parse.outputs.version }}
@@ -947,6 +946,8 @@ jobs:
needs: release-tag
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: read
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
steps:
@@ -968,7 +969,7 @@ jobs:
- name: Install clawhub CLI
if: needs.release-tag.outputs.publishable == 'true' && env.CLAWHUB_TOKEN != ''
run: npm install -g clawhub
run: npm install -g clawhub@0.7.0
- name: Login to ClawHub
if: needs.release-tag.outputs.publishable == 'true' && env.CLAWHUB_TOKEN != ''
@@ -1022,6 +1023,8 @@ jobs:
# Usage: Go to Actions → Skill Release → Run workflow → Enter tag name
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
steps:
@@ -1077,7 +1080,7 @@ jobs:
node-version: 20
- name: Install clawhub CLI
run: npm install -g clawhub
run: npm install -g clawhub@0.7.0
- name: Login to ClawHub
run: |
+12
View File
@@ -0,0 +1,12 @@
- Delete unused or obsolete files when your changes make them irrelevant (refactors, feature removals, etc.), and revert files only when the change is yours or explicitly requested. If a git operation leaves you unsure about other agents' in-flight work, stop and coordinate instead of deleting.
- **Before attempting to delete a file to resolve a local type/lint failure, stop and ask the user.** Other agents are often editing adjacent files; deleting their work to silence an error is never acceptable without explicit approval.
- NEVER edit `.env` or any environment variable files—only the user may change them.
- Coordinate with other agents before removing their in-progress edits—don't revert or delete work you didn't author unless everyone agrees.
- Moving/renaming and restoring files is allowed.
- ABSOLUTELY NEVER run destructive git operations (e.g., `git reset --hard`, `rm`, `git checkout`/`git restore` to an older commit) unless the user gives an explicit, written instruction in this conversation. Treat these commands as catastrophic; if you are even slightly unsure, stop and ask before touching them. *(When working within Cursor or Codex Web, these git limitations do not apply; use the tooling's capabilities as needed.)*
- Never use `git restore` (or similar commands) to revert files you didn't author—coordinate with other agents instead so their in-progress work stays intact.
- Always double-check git status before any commit
- Keep commits atomic: commit only the files you touched and list each path explicitly. For tracked files run `git commit -m "<scoped message>" -- path/to/file1 path/to/file2`. For brand-new files, use the one-liner `git restore --staged :/ && git add "path/to/file1" "path/to/file2" && git commit -m "<scoped message>" -- path/to/file1 path/to/file2`.
- Quote any git paths containing brackets or parentheses (e.g., `src/app/[candidate]/**`) when staging or committing so the shell does not treat them as globs or subshells.
- When running `git rebase`, avoid opening editors—export `GIT_EDITOR=:` and `GIT_SEQUENCE_EDITOR=:` (or pass `--no-edit`) so the default messages are used automatically.
- Never amend commits unless you have explicit written approval in the task thread.
+116
View File
@@ -0,0 +1,116 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Development Setup
```bash
npm install # install JS dependencies
npm run dev # start Vite dev server on http://localhost:3000
npm run build # production build to dist/
```
Python environment (use `uv`, not raw `pip`):
```bash
uv venv # create .venv in repo root
source .venv/bin/activate
uv pip install ruff bandit # linters configured in pyproject.toml
```
Required tools: Node 20+, Python 3.10+, openssl, jq, shellcheck (`brew install shellcheck`).
## Common Commands
**Pre-push validation** (mirrors CI — run before pushing):
```bash
./scripts/prepare-to-push.sh # lint, typecheck, build, security scans
./scripts/prepare-to-push.sh --fix # auto-fix where possible
```
**Lint:**
```bash
npx eslint . --ext .ts,.tsx,.js,.jsx,.mjs --max-warnings 0 # JS/TS
ruff check utils/ # Python
bandit -r utils/ -ll # Python security
```
**Tests** (vanilla Node.js — no framework, no npm test script):
```bash
node skills/clawsec-suite/test/feed_verification.test.mjs
node skills/clawsec-suite/test/guarded_install.test.mjs
node skills/clawsec-suite/test/skill_catalog_discovery.test.mjs
```
**Validate a skill's structure:**
```bash
python utils/validate_skill.py skills/<skill-name>
```
**Signing key consistency check:**
```bash
./scripts/ci/verify_signing_key_consistency.sh
```
**Populate local dev data:**
```bash
./scripts/populate-local-skills.sh # build public/skills/index.json from local skills/
./scripts/populate-local-feed.sh --days 120 # fetch real NVD CVE data for local advisory feed
```
## Releasing a Skill
```bash
./scripts/release-skill.sh <skill-name> <version> [--force-tag]
# Example: ./scripts/release-skill.sh clawsec-feed 0.0.5
```
- **Feature branch:** bumps version in skill.json + SKILL.md frontmatter, commits. No tag.
- **Main branch:** same + creates annotated git tag + GitHub release with changelog.
- Tag format: `<skill-name>-v<semver>` (e.g., `clawsec-suite-v0.1.0`).
- Pushing the tag triggers the `skill-release.yml` workflow (sign, package, publish).
## Architecture
**Frontend:** React 19 + TypeScript + Vite, deployed to GitHub Pages. Hash-based routing. Tailwind via CDN.
**Skills:** Each skill lives in `skills/<name>/` with:
- `skill.json` — metadata, SBOM (file manifest), OpenClaw config (emoji, triggers, required bins)
- `SKILL.md` — YAML frontmatter (`name`, `version`, `description`) + agent-readable markdown
- Version in `skill.json` and `SKILL.md` frontmatter must match (CI enforced)
**clawsec-suite** is the meta-skill ("skill-of-skills") that installs and manages other skills. It embeds:
- Advisory feed with Ed25519 signature verification (`hooks/clawsec-advisory-guardian/`)
- Guarded skill installer with two-stage approval for advisory-flagged skills
- Dynamic catalog discovery from `https://clawsec.prompt.security/skills/index.json` with local fallback
**Signing:** Single Ed25519 keypair for everything (feed + releases).
- Private key lives only in GitHub secret `CLAWSEC_SIGNING_PRIVATE_KEY` — never committed.
- Public key committed in three canonical locations: `clawsec-signing-public.pem`, `advisories/feed-signing-public.pem`, `skills/clawsec-suite/advisories/feed-signing-public.pem`.
- `SKILL.md` embeds the same key inline for offline installation verification.
- Drift guard: `scripts/ci/verify_signing_key_consistency.sh` enforces all references resolve to the same fingerprint. Runs on every PR and tag push.
## CI Workflows
| Workflow | Trigger | What it does |
|---|---|---|
| `ci.yml` | PR / push to main | Lint (TS, Python, shell), Trivy security scan, npm audit, tests, build |
| `skill-release.yml` | Tag `*-v*.*.*` or PR touching skill files | Sign checksums, publish to GitHub Releases, supersede old versions |
| `deploy-pages.yml` | After CI or release succeeds | Build web frontend + skills catalog, deploy to GitHub Pages |
| `poll-nvd-cves.yml` | Daily 06:00 UTC | Poll NVD for CVEs, update `advisories/feed.json` + signature |
| `community-advisory.yml` | Issue labeled `advisory-approved` | Process community report into `CLAW-YYYY-NNNN` advisory |
## Key Conventions
- **ESLint:** flat config (`eslint.config.js`), zero warnings policy
- **Python:** ruff + bandit, configured in `pyproject.toml`, line-length 120
- **Shell:** shellcheck on `scripts/*.sh`
- **Tests:** each `.test.mjs` is a standalone Node.js script with its own pass/fail counters and `process.exit(1)` on failure. Tests generate ephemeral Ed25519 keys — they don't use the repo signing keys.
- **Advisory feed:** fail-closed signature verification by default. `CLAWSEC_ALLOW_UNSIGNED_FEED=1` is a temporary migration bypass only.
- **Hook event model:** hooks mutate `event.messages` array in-place (not return values). Rate-limited to 300s by default (`CLAWSEC_HOOK_INTERVAL_SECONDS`).