mirror of
https://github.com/prompt-security/clawsec.git
synced 2026-06-13 05:28:02 +03:00
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:
@@ -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
|
||||||
@@ -6,6 +6,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint-typescript:
|
lint-typescript:
|
||||||
name: Lint TypeScript/React
|
name: Lint TypeScript/React
|
||||||
@@ -32,14 +34,10 @@ jobs:
|
|||||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.12'
|
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)
|
- 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)
|
- name: Bandit (security)
|
||||||
run: bandit -r utils/ -ll
|
run: pipx run --spec "bandit==1.7.9" bandit -r utils/ -ll
|
||||||
|
|
||||||
lint-shell:
|
lint-shell:
|
||||||
name: Lint Shell Scripts
|
name: Lint Shell Scripts
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -4,10 +4,7 @@ on:
|
|||||||
issues:
|
issues:
|
||||||
types: [labeled]
|
types: [labeled]
|
||||||
|
|
||||||
permissions:
|
permissions: read-all
|
||||||
contents: write
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: community-advisory
|
group: community-advisory
|
||||||
@@ -23,6 +20,10 @@ jobs:
|
|||||||
process-advisory:
|
process-advisory:
|
||||||
if: github.event.label.name == 'advisory-approved'
|
if: github.event.label.name == 'advisory-approved'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ on:
|
|||||||
default: 'false'
|
default: 'false'
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
permissions:
|
permissions: read-all
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: poll-nvd-cves
|
group: poll-nvd-cves
|
||||||
@@ -31,6 +29,9 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
poll-and-update:
|
poll-and-update:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||||
|
|||||||
@@ -73,6 +73,6 @@ jobs:
|
|||||||
# Upload the results to GitHub's code scanning dashboard (optional).
|
# Upload the results to GitHub's code scanning dashboard (optional).
|
||||||
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
uses: github/codeql-action/upload-sarif@a4e1a019f5e24960714ff6296aee04b736cbc3cf # v3.29.6
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
permissions:
|
permissions: read-all
|
||||||
contents: write
|
|
||||||
pages: write
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: skill-release-${{ github.ref }}
|
group: skill-release-${{ github.ref }}
|
||||||
@@ -505,6 +502,8 @@ jobs:
|
|||||||
release-tag:
|
release-tag:
|
||||||
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
outputs:
|
outputs:
|
||||||
skill_name: ${{ steps.parse.outputs.skill_name }}
|
skill_name: ${{ steps.parse.outputs.skill_name }}
|
||||||
version: ${{ steps.parse.outputs.version }}
|
version: ${{ steps.parse.outputs.version }}
|
||||||
@@ -947,6 +946,8 @@ jobs:
|
|||||||
needs: release-tag
|
needs: release-tag
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
env:
|
env:
|
||||||
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
|
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
@@ -968,7 +969,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install clawhub CLI
|
- name: Install clawhub CLI
|
||||||
if: needs.release-tag.outputs.publishable == 'true' && env.CLAWHUB_TOKEN != ''
|
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
|
- name: Login to ClawHub
|
||||||
if: needs.release-tag.outputs.publishable == 'true' && env.CLAWHUB_TOKEN != ''
|
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
|
# Usage: Go to Actions → Skill Release → Run workflow → Enter tag name
|
||||||
if: github.event_name == 'workflow_dispatch'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
env:
|
env:
|
||||||
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
|
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
@@ -1077,7 +1080,7 @@ jobs:
|
|||||||
node-version: 20
|
node-version: 20
|
||||||
|
|
||||||
- name: Install clawhub CLI
|
- name: Install clawhub CLI
|
||||||
run: npm install -g clawhub
|
run: npm install -g clawhub@0.7.0
|
||||||
|
|
||||||
- name: Login to ClawHub
|
- name: Login to ClawHub
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -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`).
|
||||||
Reference in New Issue
Block a user