1 Commits
Author SHA1 Message Date
evandro 2ef6f6be10 wip: snapshot das alterações não commitadas (2026-10-20)
Origem: D:/Documents/Github/dev-workflows
Arquivos omitidos (segredos, bancos de dados, logs, >50 MB): 0
2026-10-20 00:49:23 -03:00
64 changed files with 8277 additions and 296 deletions

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
{
"name": "dev-workflows",
"description": "Dev workflows como plugin do Claude Code: roteador por nível, agentes, gate de qualidade e revisão de segurança.",
"owner": {
"name": "Evandro Fonseca Junior",
"url": "https://github.com/evandrodevbr"
},
"plugins": [
{
"name": "dev-workflows",
"source": "./",
"description": "Roteador por nível, agentes, gate de qualidade e workflows de front, back, arquitetura, segurança e README."
}
]
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "dev-workflows",
"displayName": "Dev Workflows",
"version": "2.0.0",
"description": "Workflows de desenvolvimento que escalam com o tamanho do pedido: roteador por nível, agentes com permissão mínima, gate de qualidade determinístico e revisão de segurança com fontes ao vivo.",
"author": {
"name": "Evandro Fonseca Junior",
"url": "https://github.com/evandrodevbr"
},
"homepage": "https://github.com/evandrodevbr/dev-workflows",
"repository": "https://github.com/evandrodevbr/dev-workflows",
"license": "MIT",
"keywords": ["workflow", "code-review", "security", "frontend", "backend", "quality-gate"]
}
+22
View File
@@ -0,0 +1,22 @@
name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Lint das skills, agentes e hooks
run: python3 qa/lint_skills.py
- name: Testes do gate e dos hooks
run: python3 qa/test_gate.py
+17
View File
@@ -0,0 +1,17 @@
name: upstream
on:
schedule:
- cron: "0 9 1 * *"
workflow_dispatch:
permissions:
contents: read
jobs:
vendored-skills:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Skills vendorizadas atrás do upstream
run: python3 qa/check_upstream.py
+24
View File
@@ -0,0 +1,24 @@
# Changelog
## 2.0.0 (2026-09-24)
### Added
- Claude Code plugin packaging (`.claude-plugin/plugin.json`, `marketplace.json`); workflows moved to `skills/<name>/SKILL.md`.
- `dev-router`: tiers 0 to 3 with security triggers that raise the tier, so small requests skip heavy phases.
- `lean-code`: reuse ladder, dependency justification, diff budget per tier.
- `wf-bugfix` and `wf-refactor`.
- Agents: `explorer`, `planner`, `implementer`, `reviewer`, `security-auditor`, `ui-critic`, `verifier`, each with only the tools its role needs.
- `scripts/quality-gate`: deterministic checks per tier, scoped to the diff; missing tools reported as unverified; new dependencies listed.
- Hooks: `Stop` gate, shell command guard, formatter after edits.
- opencode adapter and `scripts/install.py` for Claude Code, opencode and Hermes Agent.
- taste-skill (`design-taste-frontend`, `redesign-existing-projects`) vendored for `wf-frontend`.
- `qa/lint_skills.py`, `qa/test_gate.py`, `qa/check_upstream.py` and CI.
### Changed
- The five workflows were cut to about 100 lines each; phases state their minimum tier; grep-count checks replaced by the gate and real tools.
- Security references moved to OWASP Top 10:2025, ASVS 5.0 and OWASP LLM Top 10 (2025).
- Machine-specific paths (`~/.hermes/...`, `vision_analyze`) and references to skills that do not exist publicly removed.
### Removed
- The keyword-count quality harness (`qa/wf_quality_harness.py`, `test_quality.py`, `test_tests.py`, snapshots). It scored occurrences of words like `VERIFICAR` and `NUNCA`, so its "+98.6%" measured wording, not quality; it also failed on a fresh clone because it looked for skills in `~/.hermes`.
- apisec-inc's `api-security-review` from `wf-backend` (name collision with the vendored OWASP skill).
+190 -120
View File
@@ -1,114 +1,143 @@
<div align="center">
<img src="assets/readme/hero.svg" width="100%" alt="dev-workflows: agent workflows where every phase ends in a verification step, shown as the wf-security-review SKILL.md checklist from SCOPE to REPORT + GATE">
# Dev Workflows
![Format SKILL.md](https://img.shields.io/badge/format-SKILL.md-informational?style=flat-square)
![Workflows 5, v1.0.0](https://img.shields.io/badge/workflows-5%20%C2%B7%20v1.0.0-informational?style=flat-square)
![QA harness Python 3](https://img.shields.io/badge/QA%20harness-Python%203-3776AB?style=flat-square&logo=python&logoColor=white)
![License MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)
**Agent workflows as SKILL.md files**: frontend, backend, architecture and security code review that never skip verification.
[Issues](https://git.evandro.dev.br/evandro/dev-workflows/issues) · [Skills inventory](docs/SKILLS.md) · [Vendored skills notice](skills/NOTICE.md) · [Contributing](CONTRIBUTING.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/Python-3.10+-3776AB?logo=python&logoColor=white)](qa/wf_quality_harness.py)
[![Agent Skills](https://img.shields.io/badge/Agent%20Skills-1.0-8A2BE2)](https://agentskills.io)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/evandrodevbr/dev-workflows/pulls)
**English** · [Português (BR)](README.pt-BR.md)
Turn your coding agent into a repeatable, verifiable process. Each workflow defines phases, concrete verification steps, real commands, and hard rules. The agent delivers work that can be *checked*, not just *claimed*.
**🇧🇷 [Ler em português](README.pt-BR.md)**
</div>
Harness output after installing the workflows and the vendored skills in the Hermes layout (real run; `impeccable` is a third-party skill that was not installed, so the harness exits 1):
---
```console
$ cd qa && python wf_quality_harness.py
wf-frontend score= 385.5 refs=18 sem_match=['impeccable'] fases_sem_verif=[]
wf-backend score= 424.0 refs=15 sem_match=[] fases_sem_verif=[]
wf-architecture score= 413.7 refs=11 sem_match=[] fases_sem_verif=[]
wf-security-review score= 390.0 refs=14 sem_match=[] fases_sem_verif=[]
## Why
TOTAL: 1613.2 / 400.0 (403.3%)
Agents are great at generating code and terrible at admitting they don't know. This project fixes the second part.
Every workflow here forces the agent to **prove** the work at each phase:
- **Verification steps**: run the build, run the tests, hit the API, consult the registry. Not "I think it works".
- **Acceptance criteria**: checkbox gates that must be marked before a phase closes.
- **Hard rules**: "never merge with a red build", "never claim 'no CVE' without querying OSV.dev".
- **A QA harness**: a scorecard that measures workflow quality objectively, plus meta-tests that corrupt the harness to prove it detects regressions.
## Table of contents
- [Workflows](#workflows)
- [Security: do not trust the training cutoff](#security-do-not-trust-the-training-cutoff)
- [Skills used, and their owners](#skills-used-and-their-owners)
- [Quick start](#quick-start)
- [The QA harness](#the-qa-harness)
- [Quality tests and measured gains](#quality-tests-and-measured-gains)
- [Repository layout](#repository-layout)
- [License](#license)
## Workflows
| Workflow | File | Covers |
|---|---|---|
| 🎨 **Frontend / UI** | [workflows/wf-frontend.md](workflows/wf-frontend.md) | Design direction before code, anti-AI-slop, React performance, visual QA for PDFs |
| ⚙️ **Backend / API** | [workflows/wf-backend.md](workflows/wf-backend.md) | Contract before handler, safe defaults, OWASP audit, tests + adversarial bug hunt |
| 🏗️ **Architecture** | [workflows/wf-architecture.md](workflows/wf-architecture.md) | Measurable requirements, C4 diagrams, ADRs, threat modeling, review |
| 🛡️ **Security review** | [workflows/wf-security-review.md](workflows/wf-security-review.md) | Code review (front + back), known CVEs **and** live lookup of new ones |
| 📄 **README** | [workflows/wf-readme.md](workflows/wf-readme.md) | Create/audit/rewrite READMEs grounded in real repo facts |
Each file is a standard `SKILL.md`. The `description` in the frontmatter is the trigger: when the agent's context matches it, the workflow loads automatically. Works in [Hermes Agent](https://hermes-agent.nousresearch.com), Claude Code, and anything that reads the Agent Skills format.
## Security: do not trust the training cutoff
A model's knowledge of CVEs stops at its training date. Anything disclosed after that, it has never seen, so "no vulnerabilities" from memory is a guess, not an answer.
The security workflow is built around that fact:
```
Code/diff → SCOPE → HUNT (known CVEs) → CONSULT (live sources) → CODE REVIEW → REPORT + GATE
│ │
│ └─ OSV.dev · GitHub Advisory DB · NVD
└──────────────┘
```
## What it is
Every security review **must** consult live sources and stamp the date. A review with no source and no date is expired on arrival.
Five agent workflows written as standard `SKILL.md` files. The `description` in each frontmatter is the trigger, so the workflow loads when the agent's context matches it. The workflow bodies are in Portuguese.
## Skills used, and their owners
| Workflow | File | Phases | Covers |
|---|---|---|---|
| Frontend / UI | [`wf-frontend.md`](workflows/wf-frontend.md) | DESIGN, BUILD, REVIEW | Design direction before code, anti-AI-slop, React performance, visual QA for PDFs |
| Backend / API | [`wf-backend.md`](workflows/wf-backend.md) | PLAN, BUILD, SECURITY, TEST + BUG HUNT | Contract before handler, safe defaults, OWASP audit, tests and adversarial bug hunt |
| Architecture | [`wf-architecture.md`](workflows/wf-architecture.md) | REQUIREMENTS, DESIGN, DOCS, REVIEW | Measurable requirements, C4 diagrams, ADRs, threat modeling |
| Security review | [`wf-security-review.md`](workflows/wf-security-review.md) | SCOPE, HUNT, CONSULT, CODE REVIEW, REPORT + GATE | Front and back code review, known CVEs and a live lookup of new ones |
| README | [`wf-readme.md`](workflows/wf-readme.md) | SCAN, CLASSIFY, AUDIT or DRAFT, GENERATE, VERIFY + VALIDATE | Create, audit or rewrite READMEs grounded in real repo facts |
Workflows load these skills by context. The three pillars of the security review come from primary security sources (OWASP, OSV.dev, UnitOne SecuritySkills), not from a model's memory.
The repository also vendors ten security skills under [`skills/`](skills/NOTICE.md) and ships a QA harness under [`qa/`](qa).
### 🛡️ Security review: the three pillars
## Why use it
_Vendored under `skills/` — see [`skills/NOTICE.md`](skills/NOTICE.md) for exact origin and license._
Agents generate code well and admit ignorance badly. Each workflow makes the agent prove the work at every phase:
- **Verification steps:** run the build, run the tests, hit the API, consult the registry.
- **Acceptance criteria:** checkbox gates that must be marked before a phase closes.
- **Hard rules:** "never merge with a red build", "never claim 'no CVE' without querying OSV.dev".
Do not use it if you want self-contained skills. The frontend, backend, architecture and README workflows load third-party skills that are not in this repository, the security workflow also expects two local skills that are not vendored, and the QA harness only reads the Hermes Agent layout.
## How it works
The security workflow is built on one fact: a model's knowledge of CVEs stops at its training date, so "no vulnerabilities" from memory is a guess.
1. **SCOPE** defines the target before auditing.
2. **HUNT** checks known CVEs in the dependencies (`safedeps` queries OSV.dev for a `package@version`).
3. **CONSULT** looks up new vulnerabilities in live sources: OSV.dev, GitHub Advisory DB and NVD.
4. **CODE REVIEW** reviews front and back code against OWASP Top 10 and ASVS.
5. **REPORT + GATE** delivers the report with sources and date stamped, then decides.
The QA harness scores `wf-frontend`, `wf-backend`, `wf-architecture` and `wf-security-review` (not `wf-readme`) on 30+ static criteria extracted from each `SKILL.md`: structure, numbered steps per phase, verification verbs, referenced skills and AI-isms density. `test_tests.py` holds meta-tests that break the harness on purpose and check that the score changes.
<details>
<summary>Skills the workflows load</summary>
Vendored in `skills/` (security review). Origin, commit and license of each copy are in [`skills/NOTICE.md`](skills/NOTICE.md); CC-BY-4.0 requires attribution, kept in that file.
| Skill | What it does | Origin | License |
|---|---|---|---|
| `safedeps` | Queries OSV.dev live: CVE, severity and fixed version for a `package@version` (script `check_deps.py`) | [Jeneidi/safedeps](https://github.com/Jeneidi/safedeps) | MIT |
| `sca-audit` | Dependency supply-chain audit with reachability analysis and CWE mapping | [OWASP/secure-agent-playbook](https://github.com/OWASP/secure-agent-playbook) | CC-BY-4.0 |
| `code-review-security` | Systematic security code review mapped to OWASP Top 10 + ASVS | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `secrets-scan` | Hardcoded credentials and API keys in code and git history | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `api-security-review` | API review against OWASP API Security Top 10 | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `web-security-review` | Web app review against OWASP Top 10 | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `cve-triage` | Prioritizes CVEs with CVSS 4.0, EPSS and CISA KEV | [UnitOneAI/SecuritySkills](https://github.com/UnitOneAI/SecuritySkills) | MIT |
| `patch-prioritization` | Decides remediation order | UnitOneAI/SecuritySkills | MIT |
| `dependency-scanning` | Dependency tree scanning | UnitOneAI/SecuritySkills | MIT |
| `hermaguard` | Adversarial review: static pre-scan plus 3 specialist agents (edge cases, attack, blast radius) | [Sahil-SS9/hermaguard](https://github.com/Sahil-SS9/hermaguard) | MIT |
Not vendored (install separately; full inventory in [`docs/SKILLS.md`](docs/SKILLS.md)):
| Workflow | Skill | Origin |
| Skill | What it does | Owner |
|---|---|---|
| Frontend | `frontend-design` | [anthropics/skills](https://github.com/anthropics/skills) |
| Frontend | `web-design` | [KAOPU-XiaoPu/web-design](https://github.com/KAOPU-XiaoPu/web-design) |
| Frontend | `vercel-react-best-practices`, `vercel-composition-patterns` | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) |
| Frontend | `animate` | [emilkowalski/skill](https://github.com/emilkowalski/skill) |
| Frontend | `impeccable` | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) |
| Frontend | `avoid-ai-writing` | [conorbronsdon/avoid-ai-writing](https://github.com/conorbronsdon/avoid-ai-writing) |
| Frontend | `anti-ai-slop` | local skill, not published here |
| Backend | `secure-coding` | [securityreviewai/secure-coding-skill](https://github.com/securityreviewai/secure-coding-skill) |
| Backend | `bola-detector`, `auth-rbac-scaffold`, `injection-checker`, `openapi-hardener`, `api-security-review`, `security-test-generator` | [apisec-inc/apisec-skills](https://github.com/apisec-inc/apisec-skills) |
| Architecture | `system-design`, `c4-architecture`, `isaqb-architecture-governance`, `secure-architecture-governance` | [Kotivskyi/architecture-governance-skills](https://github.com/Kotivskyi/architecture-governance-skills) |
| README | `readme-crafter` | [linhai0872/readme-crafter-skill](https://github.com/linhai0872/readme-crafter-skill) |
| README | `good-readme` | [adewale/good-readme](https://github.com/adewale/good-readme) |
| README | `curating-readme` | [liang-senbei/curating-readme](https://github.com/liang-senbei/curating-readme) |
| Security review | `dependency-cve-audit`, `security-threat-model` | local skills, not published here |
| [`safedeps`](https://github.com/Jeneidi/safedeps) | Queries OSV.dev in real time; returns CVE + severity + fixed version for a `package@version`. Covers the gap a frozen model can't. | [Jeneidi](https://github.com/Jeneidi) |
| [`sca-audit`](https://github.com/OWASP/secure-agent-playbook) | Supply-chain audit of dependencies with reachability analysis and CWE mapping. | [OWASP](https://github.com/OWASP) |
| [`code-review-security`](https://github.com/OWASP/secure-agent-playbook) | Systematic security code review mapped to OWASP Top 10 + ASVS. | [OWASP](https://github.com/OWASP) |
</details>
### 🛡️ Security review: supporting skills
## Quickstart
_Also vendored under `skills/`._
| Skill | What it does | Owner |
|---|---|---|
| [`secrets-scan`](https://github.com/OWASP/secure-agent-playbook) | Finds hardcoded credentials / API keys in code and git history. | [OWASP](https://github.com/OWASP) |
| [`api-security-review`](https://github.com/OWASP/secure-agent-playbook) | API review against OWASP API Security Top 10. | [OWASP](https://github.com/OWASP) |
| [`web-security-review`](https://github.com/OWASP/secure-agent-playbook) | Web app review against OWASP Top 10. | [OWASP](https://github.com/OWASP) |
| [`cve-triage`](https://github.com/UnitOneAI/SecuritySkills) | Prioritizes CVEs using CVSS 4.0 / EPSS / CISA KEV. | [UnitOneAI](https://github.com/UnitOneAI) |
| [`patch-prioritization`](https://github.com/UnitOneAI/SecuritySkills) | Decides remediation order. | [UnitOneAI](https://github.com/UnitOneAI) |
| [`dependency-scanning`](https://github.com/UnitOneAI/SecuritySkills) | Dependency tree scanning. | [UnitOneAI](https://github.com/UnitOneAI) |
| [`hermaguard`](https://github.com/Sahil-SS9/hermaguard) | Adversarial review: static pre-scan + 3 specialist agents (edge cases, attack, blast radius). | [Sahil-SS9](https://github.com/Sahil-SS9) |
### 🎨 Frontend / UI
| Skill | What it does | Owner |
|---|---|---|
| [`frontend-design`](https://github.com/anthropics/skills) | Intentional visual direction, typography, avoiding "generic AI" output. | [Anthropic](https://github.com/anthropics) |
| [`web-design`](https://github.com/KAOPU-XiaoPu/web-design) | Cohesive web aesthetics. | [KAOPU-XiaoPu](https://github.com/KAOPU-XiaoPu) |
| [`vercel-react-best-practices`](https://github.com/vercel-labs/agent-skills) | 40+ React/Next performance rules from Vercel engineering. | [Vercel Labs](https://github.com/vercel-labs) |
| [`vercel-composition-patterns`](https://github.com/vercel-labs/agent-skills) | Compound components, clean composition. | [Vercel Labs](https://github.com/vercel-labs) |
| [`animate`](https://github.com/emilkowalski/skill) | Purpose-driven motion. | [emilkowalski](https://github.com/emilkowalski) |
| [`impeccable`](https://github.com/pbakaus/impeccable) | The missing design vocabulary for agents: 23 commands (craft, shape, audit, polish, animate, live) and 59 deterministic anti-slop rules. The most-used frontend design skill (230k+ installs). | [pbakaus](https://github.com/pbakaus) |
| [`anti-ai-slop`](https://github.com/evandrodevbr/dev-workflows) | Detects "generated-by-AI" visual patterns (auto-loaded, local). | community skill |
| [`avoid-ai-writing`](https://github.com/conorbronsdon/avoid-ai-writing) | Removes AI-isms from microcopy, labels and docs. | [conorbronsdon](https://github.com/conorbronsdon) |
### ⚙️ Backend / API
| Skill | What it does | Owner |
|---|---|---|
| [`secure-coding`](https://github.com/securityreviewai/secure-coding-skill) | Secure coding patterns covering 15 stacks. | [securityreviewai](https://github.com/securityreviewai) |
| [`bola-detector`](https://github.com/apisec-inc/apisec-skills) | Broken object-level authorization (OWASP API1). | [apisec-inc](https://github.com/apisec-inc) |
| [`auth-rbac-scaffold`](https://github.com/apisec-inc/apisec-skills) | Authentication + RBAC (OWASP API2 / API5). | [apisec-inc](https://github.com/apisec-inc) |
| [`injection-checker`](https://github.com/apisec-inc/apisec-skills) | SQL / ORM / shell / template injection (OWASP API8). | [apisec-inc](https://github.com/apisec-inc) |
| [`openapi-hardener`](https://github.com/apisec-inc/apisec-skills) | Sanitizes OpenAPI / Zod / Pydantic schemas (OWASP API3). | [apisec-inc](https://github.com/apisec-inc) |
| [`api-security-review`](https://github.com/apisec-inc/apisec-skills) | Full OWASP API Top 10 review. | [apisec-inc](https://github.com/apisec-inc) |
| [`security-test-generator`](https://github.com/apisec-inc/apisec-skills) | Generates security test suites. | [apisec-inc](https://github.com/apisec-inc) |
### 🏗️ Architecture
| Skill | What it does | Owner |
|---|---|---|
| [`system-design`](https://github.com/Kotivskyi/architecture-governance-skills) | HelloInterview system-design framework. | [Kotivskyi](https://github.com/Kotivskyi) |
| [`c4-architecture`](https://github.com/Kotivskyi/architecture-governance-skills) | C4 diagrams (Mermaid / Structurizr). | [Kotivskyi](https://github.com/Kotivskyi) |
| [`isaqb-architecture-governance`](https://github.com/Kotivskyi/architecture-governance-skills) | arc42 + ADRs. | [Kotivskyi](https://github.com/Kotivskyi) |
| [`secure-architecture-governance`](https://github.com/Kotivskyi/architecture-governance-skills) | STRIDE+CIA threat models, security ADRs. | [Kotivskyi](https://github.com/Kotivskyi) |
> 📖 Full install instructions for every skill live in [docs/SKILLS.md](docs/SKILLS.md).
## Quick start
```bash
# 1. Copy the workflows into your agent's skills directory
# Hermes Agent
# 1. Copy workflows into your agent's skills directory
# Hermes Agent:
cp workflows/*.md ~/.hermes/skills/software-development/
# Claude Code: each skill needs its own directory (a loose .md is not loaded)
# Claude Code: each skill needs its own directory (won't load a loose .md)
mkdir -p ~/.claude/skills
for f in workflows/*.md; do
name=$(basename "$f" .md)
@@ -116,61 +145,102 @@ for f in workflows/*.md; do
cp "$f" "$HOME/.claude/skills/$name/SKILL.md"
done
# 2. Security review: the supporting skills are already vendored in skills/.
# Hermes:
# 2. (Optional, for security review) the supporting skills are already
# vendored in skills/ -- no external clone needed, just copy (Hermes; for
# Claude Code use the same loop as step 1, swapping "workflows" for "skills"):
cp -r skills/* ~/.hermes/skills/
# Claude Code: copy each skills/<name>/ directory to ~/.claude/skills/<name>/
# (the SKILL.md must sit inside its own directory, as in step 1).
# 3. Use it
# "review this PR for security" -> wf-security-review loads
# "build a new page" -> wf-frontend loads
# "build a new page" -> wf-frontend loads
```
The remaining skills install through `npx skills` (agentskills.io format), for example:
## The QA harness
```bash
npx skills add anthropics/skills --skill frontend-design
npx skills add vercel-labs/agent-skills --skill vercel-react-best-practices
npx skills add conorbronsdon/avoid-ai-writing
npx skills add https://github.com/pbakaus/impeccable --skill impeccable
```
> [!WARNING]
> Install layout matters. Claude Code ignores a loose `.md`; it needs `<skill>/SKILL.md`. The QA harness has the same requirement: it reads `~/.hermes/skills/software-development/<workflow>/SKILL.md`, so the flat `cp` used for Hermes above is not enough to run it.
## Usage
The `qa/` directory keeps the workflows themselves honest:
```bash
cd qa
python3 wf_quality_harness.py # score each workflow on 30+ criteria
python3 test_quality.py # gates: no regression, referenced skills exist, every phase verified
python3 test_tests.py # meta-tests: corrupt harness/workflows, confirm the score drops
python3 test_quality.py # gates: no regression, valid skills, phases verified
python3 test_tests.py # meta-tests: corrupt the harness, prove it detects the corruption
```
Final scores per workflow are versioned in [`qa/snapshots/baseline-final.json`](qa/snapshots/baseline-final.json): `wf-frontend` 385.5, `wf-backend` 424.0, `wf-architecture` 413.7, `wf-security-review` 390.0, total 1613.2. The run above reproduces them.
The meta-tests are the interesting part. They deliberately break the harness and the workflows, then confirm the score *drops*. If the score didn't move, the detector would be useless. These tests stay green as a contract.
## Project status
## Quality tests and measured gains
Six commits between 2026-08-19 and 2026-10-13; every workflow declares `version: 1.0.0`. No root CI: `skills/hermaguard/.github/workflows/ci.yml` belongs to the vendored hermaguard and does not run from this repository.
These are real numbers from the harness runs, stored in `qa/snapshots/`. The baseline column is the state before the refinement work; the final column is the result after it.
- The harness reads installed copies from `~/.hermes/skills/software-development/<name>/SKILL.md` (hardcoded `SKILLS_DIR`), not the files in `workflows/`. Without them it reports `SKILL.md não encontrado`.
- The harness exits 1 when a referenced skill is missing, and `test_quality.py` then stops with `HARNESS FALHOU`. Even with every skill installed, gate G3 asks each workflow to reach twice its own final baseline, so `test_quality.py` cannot pass against the current snapshot.
- `test_tests.py` mutates `wf-frontend/SKILL.md` at the repository root, which does not exist, so that meta-test does nothing; the anti-slop mutation still runs.
- The "referenced skills exist" check also accepts names from a hardcoded list without checking the disk.
- `wf-security-review` mentions `dependency-cve-audit` and `security-threat-model` as local skills that are not vendored, and calls `~/.hermes/skills/safedeps/check_deps.py`, so it assumes the Hermes layout.
- Two different skills share the name `api-security-review`: the vendored OWASP one and the apisec-inc one used by the backend workflow. Installing both into the same directory makes one overwrite the other.
- In `docs/SKILLS.md`, the Claude Code snippet quotes the tilde (`"~/.claude/skills/$nome"`), which creates a literal `~` directory; use `$HOME` as in the Quickstart above.
- `wf-readme` is not covered by the harness.
### Workflow quality score (same harness, before → after)
Contribution rules are in [`CONTRIBUTING.md`](CONTRIBUTING.md): claims trace back to repo facts, every phase has a verification step, and docs avoid AI-isms.
| Workflow | Baseline | Final | Gain |
|---|---|---|---|
| wf-frontend | 201.0 | 385.5 | +92% |
| wf-backend | 215.0 | 424.0 | +97% |
| wf-architecture | 199.9 | 413.7 | +107% |
| wf-security-review | 332.0 | 390.0 | +17% |
| **Total** | **615.9** | **1223.2** | **+98.6%** |
That is almost exactly double the quality of the workflows, measured with the same ruler.
The ruler itself also grew stricter over the project (13 → 30+ criteria: verification per phase, real commands, anti-patterns, acceptance criteria, artifacts, flow). That is why the early snapshots show lower totals: `base-364` (13 criteria) → `baseline-v2` (536.7) → `baseline-v3` (675.0) → `baseline-v4` (884.6) → `baseline-final` (1613.2 with four workflows). The fair before/after comparison above uses the final ruler for both sides.
### Gates (regression checks): all green
| Gate | What it checks | Status |
|---|---|---|
| G1 | Score did not drop below baseline | ✅ |
| G4 | Every referenced skill exists | ✅ 4/4 workflows |
| G5 | Every phase has ≥3 verification verbs | ✅ 4/4 workflows |
| Meta-tests | Corrupt harness/workflows → score drops (proves detector works) | ✅ |
### What the refinement added
Every workflow gained the same batch of real improvements:
- **Verification steps** with actual commands (`curl`, `grep`, `python3`, `git`, `npm`, `pytest`) instead of prose.
- **Per-phase acceptance checklists** (markable `[ ]` gates).
- **Anti-pattern blocks** per phase (what not to do, and why).
- **Executable-command sections** and **worked examples per phase**.
- **Checkpoints** that pause for user approval between phases.
The security workflow gained a hard rule: *never claim "no CVE" without querying OSV.dev / GitHub Advisory*. A model's knowledge stops at its training cutoff; the live sources don't.
### Context on the "double" target
The harness has a physical ceiling (sum of all criterion caps). The numeric "2× of baseline" target would need a ruler with more resolution to be expressible, so inflating the score to hit it would be gaming the metric. What shipped is the honest version: real quality ~doubled on the same ruler (+98.6%), with meta-tests proving the ruler detects regressions.
## Repository layout
```
dev-workflows/
├── README.md # this file
├── README.pt-BR.md # Portuguese version
├── workflows/ # the four SKILL.md workflows
│ ├── wf-frontend.md
│ ├── wf-backend.md
│ ├── wf-architecture.md
│ └── wf-security-review.md
├── docs/
│ └── SKILLS.md # full skill inventory + install steps
├── CONTRIBUTING.md # what to improve, local checks, PR process
└── qa/ # quality harness, gates, meta-tests
├── wf_quality_harness.py
├── test_quality.py
├── test_tests.py
└── snapshots/
```
## License
[MIT](LICENSE), (c) 2026 Evandro Fonseca Junior. Vendored skills keep their own licenses ([`skills/NOTICE.md`](skills/NOTICE.md)).
[MIT](LICENSE) © 2026 [Evandro Fonseca Junior](https://github.com/evandrodevbr)
---
<div align="center">
<sub>Made by <a href="https://evandro.dev.br">Evandro Fonseca Junior</a> · <a href="https://git.evandro.dev.br/evandro">git.evandro.dev.br</a></sub>
⭐ If this saves you from one "works on my machine" merge, star it.
</div>
+195 -125
View File
@@ -1,176 +1,246 @@
<div align="center">
<img src="assets/readme/hero.svg" width="100%" alt="dev-workflows: workflows de agente em que toda fase termina num passo de verificação, mostrados como o checklist do SKILL.md wf-security-review de SCOPE a REPORT + GATE">
# Dev Workflows
![Formato SKILL.md](https://img.shields.io/badge/formato-SKILL.md-informational?style=flat-square)
![Workflows 5, v1.0.0](https://img.shields.io/badge/workflows-5%20%C2%B7%20v1.0.0-informational?style=flat-square)
![Harness de QA Python 3](https://img.shields.io/badge/harness%20de%20QA-Python%203-3776AB?style=flat-square&logo=python&logoColor=white)
![Licença MIT](https://img.shields.io/badge/licen%C3%A7a-MIT-blue?style=flat-square)
**Workflows de agente como arquivos SKILL.md**: frontend, backend, arquitetura e code review de segurança que nunca pulam a verificação.
[Issues](https://git.evandro.dev.br/evandro/dev-workflows/issues) · [Inventário de skills](docs/SKILLS.md) · [Aviso das skills vendorizadas](skills/NOTICE.md) · [Como contribuir](CONTRIBUTING.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/Python-3.10+-3776AB?logo=python&logoColor=white)](qa/wf_quality_harness.py)
[![Agent Skills](https://img.shields.io/badge/Agent%20Skills-1.0-8A2BE2)](https://agentskills.io)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/evandrodevbr/dev-workflows/pulls)
[English](README.md) · **Português (BR)**
Transforme seu agente de código num processo repetível e verificável. Cada workflow define fases, passos de verificação concretos, comandos reais e regras duras. O agente entrega trabalho que dá pra *checar*, não só *afirmar*.
**🇺🇸 [Read this in English](README.md)**
</div>
Saída do harness depois de instalar os workflows e as skills vendorizadas no layout do Hermes (execução real; `impeccable` é uma skill de terceiros que não foi instalada, por isso o harness sai com código 1):
---
```console
$ cd qa && python wf_quality_harness.py
wf-frontend score= 385.5 refs=18 sem_match=['impeccable'] fases_sem_verif=[]
wf-backend score= 424.0 refs=15 sem_match=[] fases_sem_verif=[]
wf-architecture score= 413.7 refs=11 sem_match=[] fases_sem_verif=[]
wf-security-review score= 390.0 refs=14 sem_match=[] fases_sem_verif=[]
## Por quê
TOTAL: 1613.2 / 400.0 (403.3%)
Agente é ótimo pra gerar código e péssimo pra admitir que não sabe. Este projeto resolve a segunda parte.
Cada workflow força o agente a **provar** o trabalho em cada fase:
- **Passos de verificação**: rodar build, rodar testes, chamar a API, consultar o registry. Não "acho que funciona".
- **Critérios de aceite**: portões com checkbox que precisam estar marcados pra fase fechar.
- **Regras duras**: "nunca faça merge com build vermelho", "nunca afirme 'sem CVE' sem consultar o OSV.dev".
- **Harness de QA**: um placar que mede a qualidade dos workflows de forma objetiva, mais meta-testes que corrompem o harness pra provar que ele detecta regressão.
## Sumário
- [Workflows](#workflows)
- [Segurança: não confie no cutoff de treino](#segurança-não-confie-no-cutoff-de-treino)
- [Skills usadas e seus donos](#skills-usadas-e-seus-donos)
- [Começo rápido](#começo-rápido)
- [O harness de QA](#o-harness-de-qa)
- [Testes de qualidade e ganhos medidos](#testes-de-qualidade-e-ganhos-medidos)
- [Estrutura do repositório](#estrutura-do-repositório)
- [Licença](#licença)
## Workflows
| Workflow | Arquivo | Cobre |
|---|---|---|
| 🎨 **Frontend / UI** | [workflows/wf-frontend.md](workflows/wf-frontend.md) | Direção de design antes do código, anti-AI-slop, performance React, QA visual de PDFs |
| ⚙️ **Backend / API** | [workflows/wf-backend.md](workflows/wf-backend.md) | Contrato antes do handler, defaults seguros, auditoria OWASP, testes + caça de bugs adversarial |
| 🏗️ **Arquitetura** | [workflows/wf-architecture.md](workflows/wf-architecture.md) | Requisitos mensuráveis, diagramas C4, ADRs, threat modeling, revisão |
| 🛡️ **Security review** | [workflows/wf-security-review.md](workflows/wf-security-review.md) | Code review (front + back), CVEs conhecidas **e** consulta ao vivo de novas |
| 📄 **README** | [workflows/wf-readme.md](workflows/wf-readme.md) | Criar/auditar/reescrever READMEs grounded nos fatos reais do repo |
Cada arquivo é um `SKILL.md` padrão. A `description` no frontmatter é o gatilho: quando o contexto do agente bate, o workflow carrega sozinho. Funciona no [Hermes Agent](https://hermes-agent.nousresearch.com), Claude Code e qualquer coisa que leia o formato Agent Skills.
## Segurança: não confie no cutoff de treino
O conhecimento de CVEs de um modelo para na data do treinamento. Qualquer coisa divulgada depois disso, ele nunca viu, então "não tem vulnerabilidade" vindo de memória é um chute, não resposta.
O workflow de segurança nasceu desse fato:
```
Código/diff → SCOPE → HUNT (CVEs conhecidas) → CONSULT (fontes vivas) → CODE REVIEW → REPORT + GATE
│ │
│ └─ OSV.dev · GitHub Advisory DB · NVD
└──────────────┘
```
## O que é
Todo security review **precisa** consultar fontes vivas e carimbar a data. Review sem fonte e sem data vence na hora.
Cinco workflows de agente escritos como arquivos `SKILL.md` padrão. A `description` no frontmatter de cada um é o gatilho: o workflow carrega quando o contexto do agente bate com ela. O corpo dos workflows está em português.
## Skills usadas e seus donos
| Workflow | Arquivo | Fases | Cobre |
|---|---|---|---|
| Frontend / UI | [`wf-frontend.md`](workflows/wf-frontend.md) | DESIGN, BUILD, REVIEW | Direção de design antes do código, anti-AI-slop, performance React, QA visual de PDFs |
| Backend / API | [`wf-backend.md`](workflows/wf-backend.md) | PLAN, BUILD, SECURITY, TEST + BUG HUNT | Contrato antes do handler, defaults seguros, auditoria OWASP, testes e caça de bugs adversarial |
| Arquitetura | [`wf-architecture.md`](workflows/wf-architecture.md) | REQUIREMENTS, DESIGN, DOCS, REVIEW | Requisitos mensuráveis, diagramas C4, ADRs, threat modeling |
| Security review | [`wf-security-review.md`](workflows/wf-security-review.md) | SCOPE, HUNT, CONSULT, CODE REVIEW, REPORT + GATE | Code review de front e back, CVEs conhecidas e consulta ao vivo das novas |
| README | [`wf-readme.md`](workflows/wf-readme.md) | SCAN, CLASSIFY, AUDIT ou DRAFT, GENERATE, VERIFY + VALIDATE | Criar, auditar ou reescrever READMEs com base em fatos reais do repositório |
Os workflows carregam essas skills por contexto. Os três pilares do security review vêm de fontes primárias de segurança (OWASP, OSV.dev, UnitOne SecuritySkills), não da memória de um modelo.
O repositório também vendoriza dez skills de segurança em [`skills/`](skills/NOTICE.md) e traz um harness de QA em [`qa/`](qa).
### 🛡️ Security review: os três pilares
## Por que usar
_Vendorizadas em `skills/` — ver [`skills/NOTICE.md`](skills/NOTICE.md) pra origem exata e licença._
Agente gera código bem e admite que não sabe muito mal. Cada workflow obriga o agente a provar o trabalho em cada fase:
- **Passos de verificação:** rodar o build, rodar os testes, chamar a API, consultar o registry.
- **Critérios de aceite:** checkboxes que precisam estar marcados para a fase fechar.
- **Regras duras:** "nunca faça merge com build vermelho", "nunca afirme 'sem CVE' sem consultar o OSV.dev".
Não use se você quer skills autossuficientes. Os workflows de frontend, backend, arquitetura e README carregam skills de terceiros que não estão neste repositório, o de segurança também espera duas skills locais que não foram vendorizadas, e o harness de QA só lê o layout do Hermes Agent.
## Como funciona
O workflow de segurança parte de um fato: o conhecimento de CVEs de um modelo para na data do treinamento, então "sem vulnerabilidades" vindo da memória é chute.
1. **SCOPE** define o alvo antes da auditoria.
2. **HUNT** checa CVEs conhecidas nas dependências (`safedeps` consulta o OSV.dev para um `pacote@versão`).
3. **CONSULT** busca vulnerabilidades novas em fontes vivas: OSV.dev, GitHub Advisory DB e NVD.
4. **CODE REVIEW** revisa o código de front e back contra OWASP Top 10 e ASVS.
5. **REPORT + GATE** entrega o relatório com fontes e data carimbadas e decide.
O harness de QA pontua `wf-frontend`, `wf-backend`, `wf-architecture` e `wf-security-review` (não o `wf-readme`) em mais de 30 critérios estáticos extraídos de cada `SKILL.md`: estrutura, passos numerados por fase, verbos de verificação, skills referenciadas e densidade de AI-isms. O `test_tests.py` tem meta-testes que quebram o harness de propósito e conferem se a nota muda.
<details>
<summary>Skills que os workflows carregam</summary>
Vendorizadas em `skills/` (security review). Origem, commit e licença de cada cópia estão em [`skills/NOTICE.md`](skills/NOTICE.md); a CC-BY-4.0 exige atribuição, mantida nesse arquivo.
| Skill | O que faz | Origem | Licença |
|---|---|---|---|
| `safedeps` | Consulta o OSV.dev ao vivo: CVE, severidade e versão corrigida de um `pacote@versão` (script `check_deps.py`) | [Jeneidi/safedeps](https://github.com/Jeneidi/safedeps) | MIT |
| `sca-audit` | Auditoria da cadeia de dependências com análise de alcançabilidade e mapeamento CWE | [OWASP/secure-agent-playbook](https://github.com/OWASP/secure-agent-playbook) | CC-BY-4.0 |
| `code-review-security` | Code review de segurança sistemático mapeado para OWASP Top 10 + ASVS | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `secrets-scan` | Credenciais e chaves de API hardcoded no código e no histórico do git | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `api-security-review` | Revisão de API contra o OWASP API Security Top 10 | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `web-security-review` | Revisão de app web contra o OWASP Top 10 | OWASP/secure-agent-playbook | CC-BY-4.0 |
| `cve-triage` | Prioriza CVEs com CVSS 4.0, EPSS e CISA KEV | [UnitOneAI/SecuritySkills](https://github.com/UnitOneAI/SecuritySkills) | MIT |
| `patch-prioritization` | Decide a ordem de correção | UnitOneAI/SecuritySkills | MIT |
| `dependency-scanning` | Varredura da árvore de dependências | UnitOneAI/SecuritySkills | MIT |
| `hermaguard` | Revisão adversarial: pré-varredura estática mais 3 agentes especialistas (casos de borda, ataque, raio de impacto) | [Sahil-SS9/hermaguard](https://github.com/Sahil-SS9/hermaguard) | MIT |
Não vendorizadas (instale à parte; inventário completo em [`docs/SKILLS.md`](docs/SKILLS.md)):
| Workflow | Skill | Origem |
| Skill | O que faz | Dono |
|---|---|---|
| Frontend | `frontend-design` | [anthropics/skills](https://github.com/anthropics/skills) |
| Frontend | `web-design` | [KAOPU-XiaoPu/web-design](https://github.com/KAOPU-XiaoPu/web-design) |
| Frontend | `vercel-react-best-practices`, `vercel-composition-patterns` | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) |
| Frontend | `animate` | [emilkowalski/skill](https://github.com/emilkowalski/skill) |
| Frontend | `impeccable` | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) |
| Frontend | `avoid-ai-writing` | [conorbronsdon/avoid-ai-writing](https://github.com/conorbronsdon/avoid-ai-writing) |
| Frontend | `anti-ai-slop` | skill local, não publicada aqui |
| Backend | `secure-coding` | [securityreviewai/secure-coding-skill](https://github.com/securityreviewai/secure-coding-skill) |
| Backend | `bola-detector`, `auth-rbac-scaffold`, `injection-checker`, `openapi-hardener`, `api-security-review`, `security-test-generator` | [apisec-inc/apisec-skills](https://github.com/apisec-inc/apisec-skills) |
| Arquitetura | `system-design`, `c4-architecture`, `isaqb-architecture-governance`, `secure-architecture-governance` | [Kotivskyi/architecture-governance-skills](https://github.com/Kotivskyi/architecture-governance-skills) |
| README | `readme-crafter` | [linhai0872/readme-crafter-skill](https://github.com/linhai0872/readme-crafter-skill) |
| README | `good-readme` | [adewale/good-readme](https://github.com/adewale/good-readme) |
| README | `curating-readme` | [liang-senbei/curating-readme](https://github.com/liang-senbei/curating-readme) |
| Security review | `dependency-cve-audit`, `security-threat-model` | skills locais, não publicadas aqui |
| [`safedeps`](https://github.com/Jeneidi/safedeps) | Consulta o OSV.dev em tempo real; devolve CVE + severidade + versão corrigida pra um `package@version`. Cobre o buraco que um modelo congelado não cobre. | [Jeneidi](https://github.com/Jeneidi) |
| [`sca-audit`](https://github.com/OWASP/secure-agent-playbook) | Auditoria de supply chain de dependências com análise de alcance e mapeamento CWE. | [OWASP](https://github.com/OWASP) |
| [`code-review-security`](https://github.com/OWASP/secure-agent-playbook) | Code review de segurança sistemático mapeado a OWASP Top 10 + ASVS. | [OWASP](https://github.com/OWASP) |
</details>
### 🛡️ Security review: skills de apoio
## Início rápido
_Também vendorizadas em `skills/`._
| Skill | O que faz | Dono |
|---|---|---|
| [`secrets-scan`](https://github.com/OWASP/secure-agent-playbook) | Encontra credenciais / API keys no código e no git history. | [OWASP](https://github.com/OWASP) |
| [`api-security-review`](https://github.com/OWASP/secure-agent-playbook) | Revisão de API contra OWASP API Security Top 10. | [OWASP](https://github.com/OWASP) |
| [`web-security-review`](https://github.com/OWASP/secure-agent-playbook) | Revisão de web app contra OWASP Top 10. | [OWASP](https://github.com/OWASP) |
| [`cve-triage`](https://github.com/UnitOneAI/SecuritySkills) | Prioriza CVEs com CVSS 4.0 / EPSS / CISA KEV. | [UnitOneAI](https://github.com/UnitOneAI) |
| [`patch-prioritization`](https://github.com/UnitOneAI/SecuritySkills) | Decide a ordem da correção. | [UnitOneAI](https://github.com/UnitOneAI) |
| [`dependency-scanning`](https://github.com/UnitOneAI/SecuritySkills) | Varredura da árvore de dependências. | [UnitOneAI](https://github.com/UnitOneAI) |
| [`hermaguard`](https://github.com/Sahil-SS9/hermaguard) | Review adversarial: pré-scan estático + 3 agentes especialistas (edge cases, ataque, blast radius). | [Sahil-SS9](https://github.com/Sahil-SS9) |
### 🎨 Frontend / UI
| Skill | O que faz | Dono |
|---|---|---|
| [`frontend-design`](https://github.com/anthropics/skills) | Direção visual intencional, tipografia, fugindo do padrão "IA genérica". | [Anthropic](https://github.com/anthropics) |
| [`web-design`](https://github.com/KAOPU-XiaoPu/web-design) | Estética web coesa. | [KAOPU-XiaoPu](https://github.com/KAOPU-XiaoPu) |
| [`vercel-react-best-practices`](https://github.com/vercel-labs/agent-skills) | 40+ regras de performance React/Next da engenharia da Vercel. | [Vercel Labs](https://github.com/vercel-labs) |
| [`vercel-composition-patterns`](https://github.com/vercel-labs/agent-skills) | Compound components, composição limpa. | [Vercel Labs](https://github.com/vercel-labs) |
| [`animate`](https://github.com/emilkowalski/skill) | Motion com propósito. | [emilkowalski](https://github.com/emilkowalski) |
| [`impeccable`](https://github.com/pbakaus/impeccable) | O vocabulário de design que faltava pros agentes: 23 comandos (craft, shape, audit, polish, animate, live) e 59 regras determinísticas anti-slop. A skill de design frontend mais usada (230k+ instalações). | [pbakaus](https://github.com/pbakaus) |
| [`anti-ai-slop`](https://github.com/evandrodevbr/dev-workflows) | Detecta padrão visual "gerado por IA" (auto-carregada, local). | skill da comunidade |
| [`avoid-ai-writing`](https://github.com/conorbronsdon/avoid-ai-writing) | Remove AI-isms de microcopy, labels e docs. | [conorbronsdon](https://github.com/conorbronsdon) |
### ⚙️ Backend / API
| Skill | O que faz | Dono |
|---|---|---|
| [`secure-coding`](https://github.com/securityreviewai/secure-coding-skill) | Padrões de codificação segura em 15 stacks. | [securityreviewai](https://github.com/securityreviewai) |
| [`bola-detector`](https://github.com/apisec-inc/apisec-skills) | Object-level authorization quebrada (OWASP API1). | [apisec-inc](https://github.com/apisec-inc) |
| [`auth-rbac-scaffold`](https://github.com/apisec-inc/apisec-skills) | Autenticação + RBAC (OWASP API2 / API5). | [apisec-inc](https://github.com/apisec-inc) |
| [`injection-checker`](https://github.com/apisec-inc/apisec-skills) | Injeção SQL / ORM / shell / template (OWASP API8). | [apisec-inc](https://github.com/apisec-inc) |
| [`openapi-hardener`](https://github.com/apisec-inc/apisec-skills) | Sanear schemas OpenAPI / Zod / Pydantic (OWASP API3). | [apisec-inc](https://github.com/apisec-inc) |
| [`api-security-review`](https://github.com/apisec-inc/apisec-skills) | Review completo OWASP API Top 10. | [apisec-inc](https://github.com/apisec-inc) |
| [`security-test-generator`](https://github.com/apisec-inc/apisec-skills) | Gera suítes de testes de segurança. | [apisec-inc](https://github.com/apisec-inc) |
### 🏗️ Arquitetura
| Skill | O que faz | Dono |
|---|---|---|
| [`system-design`](https://github.com/Kotivskyi/architecture-governance-skills) | Framework HelloInterview de system design. | [Kotivskyi](https://github.com/Kotivskyi) |
| [`c4-architecture`](https://github.com/Kotivskyi/architecture-governance-skills) | Diagramas C4 (Mermaid / Structurizr). | [Kotivskyi](https://github.com/Kotivskyi) |
| [`isaqb-architecture-governance`](https://github.com/Kotivskyi/architecture-governance-skills) | arc42 + ADRs. | [Kotivskyi](https://github.com/Kotivskyi) |
| [`secure-architecture-governance`](https://github.com/Kotivskyi/architecture-governance-skills) | Threat models STRIDE+CIA, ADRs de segurança. | [Kotivskyi](https://github.com/Kotivskyi) |
> 📖 Instruções completas de instalação de cada skill estão em [docs/SKILLS.md](docs/SKILLS.md).
## Começo rápido
```bash
# 1. Copie os workflows para o diretório de skills do seu agente
# Hermes Agent
# 1. Copie os workflows pro diretório de skills do seu agente
# Hermes Agent:
cp workflows/*.md ~/.hermes/skills/software-development/
# Claude Code: cada skill precisa do próprio diretório (um .md solto não carrega)
# Claude Code: cada skill no seu proprio diretorio (nao aceita .md solto)
mkdir -p ~/.claude/skills
for f in workflows/*.md; do
name=$(basename "$f" .md)
mkdir -p "$HOME/.claude/skills/$name"
cp "$f" "$HOME/.claude/skills/$name/SKILL.md"
nome=$(basename "$f" .md)
mkdir -p "$HOME/.claude/skills/$nome"
cp "$f" "$HOME/.claude/skills/$nome/SKILL.md"
done
# 2. Security review: as skills de apoio já estão vendorizadas em skills/.
# Hermes:
# 2. (Opcional, pro security review) as skills de apoio ja vem vendorizadas
# em skills/ -- sem clone externo, so copiar (Hermes; pra Claude Code use o
# mesmo loop do passo 1 trocando "workflows" por "skills"):
cp -r skills/* ~/.hermes/skills/
# Claude Code: copie cada diretório skills/<nome>/ para ~/.claude/skills/<nome>/
# (o SKILL.md precisa ficar dentro do próprio diretório, como no passo 1).
# 3. Use
# "revise este PR para segurança" -> carrega o wf-security-review
# "crie uma página nova" -> carrega o wf-frontend
# "review this PR for security" -> wf-security-review carrega
# "build a new page" -> wf-frontend carrega
```
As demais skills se instalam com `npx skills` (formato agentskills.io), por exemplo:
## O harness de QA
```bash
npx skills add anthropics/skills --skill frontend-design
npx skills add vercel-labs/agent-skills --skill vercel-react-best-practices
npx skills add conorbronsdon/avoid-ai-writing
npx skills add https://github.com/pbakaus/impeccable --skill impeccable
```
> [!WARNING]
> O layout da instalação importa. O Claude Code ignora um `.md` solto; ele precisa de `<skill>/SKILL.md`. O harness de QA tem a mesma exigência: ele lê `~/.hermes/skills/software-development/<workflow>/SKILL.md`, então o `cp` plano usado acima para o Hermes não basta para rodá-lo.
## Uso
O diretório `qa/` mantém os próprios workflows honestos:
```bash
cd qa
python3 wf_quality_harness.py # pontua cada workflow em mais de 30 critérios
python3 test_quality.py # gates: sem regressão, skills referenciadas existem, toda fase verificada
python3 test_tests.py # meta-testes: corrompem harness/workflows e conferem que a nota cai
python3 wf_quality_harness.py # pontua cada workflow em 30+ critérios
python3 test_quality.py # gates: sem regressão, skills válidas, fases verificadas
python3 test_tests.py # meta-testes: corrompe o harness, prova que ele detecta a corrupção
```
As notas finais de cada workflow estão versionadas em [`qa/snapshots/baseline-final.json`](qa/snapshots/baseline-final.json): `wf-frontend` 385.5, `wf-backend` 424.0, `wf-architecture` 413.7, `wf-security-review` 390.0, total 1613.2. A execução acima reproduz esses valores.
Os meta-testes são a parte legal. Eles quebram o harness e os workflows de propósito e confirmam que o placar *cai*. Se o placar não mudasse, o detetor seria inútil. Esses testes ficam verdes como contrato.
## Estado do projeto
## Testes de qualidade e ganhos medidos
Seis commits entre 2026-08-19 e 2026-10-13; todo workflow declara `version: 1.0.0`. Não há CI na raiz: `skills/hermaguard/.github/workflows/ci.yml` pertence ao hermaguard vendorizado e não roda a partir deste repositório.
Números reais das execuções do harness, guardados em `qa/snapshots/`. A coluna "Antes" é o estado anterior ao refinamento; "Depois" é o resultado após ele.
- O harness lê as cópias instaladas em `~/.hermes/skills/software-development/<nome>/SKILL.md` (`SKILLS_DIR` fixo no código), não os arquivos de `workflows/`. Sem elas, ele informa `SKILL.md não encontrado`.
- O harness sai com código 1 quando falta uma skill referenciada, e aí o `test_quality.py` para com `HARNESS FALHOU`. Mesmo com todas as skills instaladas, o gate G3 exige que cada workflow chegue ao dobro da própria nota final, então o `test_quality.py` não passa contra o snapshot atual.
- O `test_tests.py` altera `wf-frontend/SKILL.md` na raiz do repositório, arquivo que não existe, então esse meta-teste não faz nada; a mutação do anti-slop continua rodando.
- A checagem de "skills referenciadas existem" também aceita nomes de uma lista fixa no código, sem olhar o disco.
- O `wf-security-review` cita `dependency-cve-audit` e `security-threat-model` como skills locais que não foram vendorizadas e chama `~/.hermes/skills/safedeps/check_deps.py`, então pressupõe o layout do Hermes.
- Duas skills diferentes têm o nome `api-security-review`: a da OWASP, vendorizada, e a da apisec-inc, usada pelo workflow de backend. Instalar as duas no mesmo diretório faz uma sobrescrever a outra.
- Em `docs/SKILLS.md`, o trecho para o Claude Code coloca o til entre aspas (`"~/.claude/skills/$nome"`), o que cria um diretório `~` literal; use `$HOME` como no Início rápido acima.
- O `wf-readme` não é coberto pelo harness.
### Score de qualidade dos workflows (mesma régua, antes → depois)
As regras de contribuição estão em [`CONTRIBUTING.md`](CONTRIBUTING.md): toda afirmação remete a fatos do repositório, toda fase tem um passo de verificação e a documentação evita AI-isms.
| Workflow | Antes | Depois | Ganho |
|---|---|---|---|
| wf-frontend | 201.0 | 385.5 | +92% |
| wf-backend | 215.0 | 424.0 | +97% |
| wf-architecture | 199.9 | 413.7 | +107% |
| wf-security-review | 332.0 | 390.0 | +17% |
| **Total** | **615.9** | **1223.2** | **+98.6%** |
Isso é quase exatamente o dobro da qualidade dos workflows, medido com a mesma régua.
A própria régua também ficou mais exigente ao longo do projeto (13 → 30+ critérios: verificação por fase, comandos reais, anti-padrões, critérios de aceite, artefatos, fluxo). Por isso os snapshots antigos mostram totais menores: `base-364` (13 critérios) → `baseline-v2` (536.7) → `baseline-v3` (675.0) → `baseline-v4` (884.6) → `baseline-final` (1613.2 com quatro workflows). A comparação justa acima usa a régua final dos dois lados.
### Gates (checagens de regressão): todos verdes
| Gate | O que verifica | Status |
|---|---|---|
| G1 | Score não caiu abaixo do baseline | ✅ |
| G4 | Toda skill referenciada existe | ✅ 4/4 workflows |
| G5 | Toda fase tem ≥3 verbos de verificação | ✅ 4/4 workflows |
| Meta-testes | Corrompe harness/workflows → score cai (prova que o detetor funciona) | ✅ |
### O que o refinamento adicionou
Cada workflow ganhou o mesmo lote de melhorias reais:
- **Passos de verificação** com comandos de verdade (`curl`, `grep`, `python3`, `git`, `npm`, `pytest`) em vez de prosa.
- **Checklists de aceite por fase** (portões `[ ]` marcáveis).
- **Blocos de anti-padrões** por fase (o que não fazer, e por quê).
- **Seções de comandos executáveis** e **exemplos trabalhados por fase**.
- **Checkpoints** que pausam pra aprovação do usuário entre fases.
O workflow de segurança ganhou uma regra dura: *nunca afirmar "sem CVE" sem consultar OSV.dev / GitHub Advisory*. O conhecimento do modelo para no cutoff do treino; as fontes vivas não.
### Contexto sobre a meta do "dobro"
O harness tem um teto físico (soma dos caps dos critérios). A meta numérica de "2× do baseline" precisaria de uma régua com mais resolução pra ser expressável, então inflar o score pra bater seria maquiar a métrica. O que foi publicado é a versão honesta: qualidade real ~dobrou na mesma régua (+98.6%), com meta-testes provando que a régua detecta regressão.
## Estrutura do repositório
```
dev-workflows/
├── README.md # versão em inglês
├── README.pt-BR.md # este arquivo
├── workflows/ # os quatro workflows em SKILL.md
│ ├── wf-frontend.md
│ ├── wf-backend.md
│ ├── wf-architecture.md
│ └── wf-security-review.md
├── docs/
│ └── SKILLS.md # inventário completo de skills + instalação
├── CONTRIBUTING.md # o que melhorar, checks locais, processo de PR
└── qa/ # harness de qualidade, gates, meta-testes
├── wf_quality_harness.py
├── test_quality.py
├── test_tests.py
└── snapshots/
```
## Licença
[MIT](LICENSE), (c) 2026 Evandro Fonseca Junior. As skills vendorizadas mantêm as próprias licenças ([`skills/NOTICE.md`](skills/NOTICE.md)).
[MIT](LICENSE) © 2026 [Evandro Fonseca Junior](https://github.com/evandrodevbr)
---
<div align="center">
<sub>Feito por <a href="https://evandro.dev.br">Evandro Fonseca Junior</a> · <a href="https://git.evandro.dev.br/evandro">git.evandro.dev.br</a></sub>
⭐ Se isso te salvar de um "na minha máquina funciona" no merge, dá uma estrela.
</div>
+34
View File
@@ -0,0 +1,34 @@
// dev-workflows for opencode: the same guard, formatter and gate scripts the Claude Code hooks run.
// Installed by `python3 scripts/install.py opencode`, which replaces __DW_ROOT__ with the checkout path.
// opencode cannot block the end of a turn, so a missing or failing gate is logged instead of blocking.
const ROOT = "__DW_ROOT__"
const DevWorkflows = async (ctx: any) => {
const $ = ctx.$ ?? (globalThis as any).Bun?.$
const directory = ctx.directory ?? ctx.location?.directory ?? process.cwd()
return {
"tool.execute.before": async (input: any, output: any) => {
if (!["bash", "shell"].includes(String(input?.tool ?? "").toLowerCase())) return
const command = output?.args?.command
if (typeof command !== "string" || !command) return
const r = await $`python3 ${ROOT}/scripts/hooks/bash_guard.py --check ${command}`.quiet().nothrow()
if (r.exitCode === 2) throw new Error(String(r.stdout).trim())
},
"tool.execute.after": async (input: any, output: any) => {
if (!["edit", "write", "patch", "multiedit"].includes(String(input?.tool ?? "").toLowerCase())) return
const file = input?.args?.filePath ?? output?.args?.filePath
if (typeof file === "string" && file) {
await $`python3 ${ROOT}/scripts/hooks/post_edit.py --file ${file}`.quiet().nothrow()
}
},
event: async ({ event }: any) => {
if (event?.type !== "session.idle") return
const r = await $`python3 ${ROOT}/scripts/hooks/stop_gate.py --check ${directory}`.quiet().nothrow()
if (r.exitCode === 2) {
await ctx.client?.app?.log?.({ body: { service: "dev-workflows", level: "warn", message: String(r.stdout).trim() } })
}
},
}
}
export default { id: "dev-workflows", setup: DevWorkflows }
+19
View File
@@ -0,0 +1,19 @@
---
name: explorer
description: Mapeia o código antes de uma mudança - onde fica o que importa, o que já existe para reaproveitar e como o projeto roda lint e testes. Só leitura. Use no nível 2 ou 3, ou no nível 1 quando não se sabe onde está o código.
tools: Read, Grep, Glob, Bash
model: haiku
---
Você mapeia o código para quem vai mudá-lo. Não edita nada. No Bash, só comandos de leitura
(`git log`, `git grep`, `ls`, `cat` de configs).
Entregue, em até 300 palavras:
1. **Onde mexer**: arquivos e funções relevantes, como `caminho:linha`, com uma linha sobre o papel de cada um.
2. **O que já existe**: helpers, componentes, tipos, validações ou padrões que resolvem parte do pedido e devem ser reaproveitados. Esta é a parte mais importante.
3. **Como verificar**: os comandos reais de teste, lint, typecheck e build (do `package.json`, `pyproject.toml`, `Makefile` ou CI).
4. **Convenções** que a mudança deve seguir (nomes, estrutura de pastas, tratamento de erro).
5. **Riscos**: chamadores que também dependem do que vai mudar.
Se não achou algo, diga que não achou. Não invente caminhos.
+17
View File
@@ -0,0 +1,17 @@
---
name: implementer
description: Implementa uma tarefa já planejada, com TDD e o menor diff que resolve, e roda o gate de qualidade no nível indicado.
tools: Read, Edit, Write, Bash, Grep, Glob
model: sonnet
skills: [lean-code]
---
Você implementa uma tarefa de cada vez, com o nível que o `dev-router` definiu.
1. Leia os arquivos antes de editar. Siga as convenções do projeto.
2. **Comportamento novo ou corrigido começa por um teste que falha.** Rode e veja vermelho; depois implemente até ficar verde.
3. Aplique `lean-code`: reaproveite o que existe, sem abstração sem uso, sem dependência sem justificativa.
4. Rode o gate: `"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier N`. Corrija o que falhar.
5. Devolva: o que mudou (arquivos, linhas líquidas), o teste que prova, o veredito do gate e o que ficou "não verificado".
Não declare pronto com teste vermelho ou gate falho. Se uma falha não é sua de corrigir, diga qual e por quê.
+28
View File
@@ -0,0 +1,28 @@
---
name: planner
description: Escreve o plano (nível 2) ou a spec com requisitos EARS, ADR e tarefas (nível 3) antes da implementação. Só leitura.
tools: Read, Grep, Glob
model: opus
---
Você planeja; não implementa. Use o mapa do `explorer` se houver, e prefira reaproveitar o que existe.
## Nível 2: plano curto
- Até 15 linhas. Tarefas de 2 a 5 minutos cada, com o arquivo exato e como verificar.
- O que **não** será feito (escopo cortado de propósito).
- Decisões que são do usuário, se houver.
## Nível 3: spec
1. **Requisitos EARS com ID**, um por linha:
- `REQ-001: WHEN <evento> THE SYSTEM SHALL <resposta>`
- `REQ-002: IF <condição indesejada> THEN THE SYSTEM SHALL <resposta>`
- `REQ-003: WHILE <estado> THE SYSTEM SHALL <resposta>`
2. **Não funcionais** com número: orçamento de performance (ex.: p95, LCP), nível ASVS (L2), limites.
3. **ADR** para cada decisão difícil de desfazer: contexto, opções, decisão, consequências.
4. **Tarefas** pequenas, cada uma com os `REQ-` que cobre e o teste que prova.
5. **Rollback**: como desfazer se der errado (migração reversível, feature flag).
Salve a spec num arquivo (ex.: `docs/specs/<nome>.md`) e sugira `[spec]` no `.dev-workflows.toml`
para o gate conferir que todo `REQ-` tem teste. A spec passa pelo usuário antes da implementação.
+25
View File
@@ -0,0 +1,25 @@
---
name: reviewer
description: Revisão independente de correção e simplicidade de um diff. Julga só o código e o plano, não o que a conversa afirma. Só leitura. Use no nível 2 ou 3 depois da implementação.
tools: Read, Grep, Glob, Bash
model: opus
---
Você revisa um diff sem ter participado da implementação. Não edite arquivos. No Bash, só leitura
(`git diff <base>`, `git log`, rodar testes).
Obtenha o diff com `git diff $(git merge-base HEAD origin/HEAD 2>/dev/null || echo HEAD)` mais os
arquivos não rastreados. Leia o código ao redor de cada trecho alterado.
Procure:
1. **Correção**: casos de borda, erro não tratado, concorrência, estado inconsistente, contrato quebrado com chamadores.
2. **Testes que provam**: o teste falharia se o bug voltasse? Testa o comportamento ou só a implementação?
3. **Simplicidade**: algo que poderia não existir, reaproveitar código do projeto ou ser apagado.
4. **Consistência** com as convenções do código ao redor.
Para cada achado: severidade (`bloqueante`, `importante`, `sugestão`), `arquivo:linha`, o problema,
um cenário concreto de falha (entrada e resultado errado) e a correção sugerida. No máximo 10 achados,
os mais graves primeiro, sem questões de estilo que o lint já cobre.
Sem achados: diga "sem achados" e liste o que você verificou.
+20
View File
@@ -0,0 +1,20 @@
---
name: security-auditor
description: Auditoria de segurança do diff e da superfície que ele toca - OWASP Top 10 2025, API Top 10, ASVS 5.0 e LLM Top 10, com CVEs consultados ao vivo. Só leitura. Use quando o dev-router disparar um gatilho de segurança ou no nível 3.
tools: Read, Grep, Glob, Bash, WebFetch
model: opus
skills: [wf-security-review]
---
Você audita; não corrige. Siga o `wf-security-review` com escopo no diff e no que ele alcança
(rotas, handlers, queries e componentes que usam o código alterado).
- **Referências**: OWASP Top 10:2025, OWASP API Security Top 10 (2023), ASVS 5.0 no nível que o
router definiu (L1 no nível 2, L2 no nível 3), OWASP LLM Top 10 (2025) se a feature chama um LLM.
- **Dependências novas ou alteradas**: consulte OSV.dev ao vivo (`safedeps`) e registre data e fonte.
Nunca diga "sem CVE" sem ter consultado.
- **Scanners do gate** (semgrep, gitleaks, osv-scanner, trivy) são ponto de partida, não substituto da leitura.
Para cada achado: severidade, CWE, `arquivo:linha`, como explorar (passo a passo curto), impacto e
correção. Diferencie vulnerabilidade confirmada de suspeita. Sem achados: liste o que verificou e as
fontes consultadas, com data.
+22
View File
@@ -0,0 +1,22 @@
---
name: ui-critic
description: Crítica visual e de UX de uma tela implementada - estados, acessibilidade, responsividade, contraste e padrões genéricos de "UI feita por IA". Só leitura. Use no nível 2 ou 3 quando houver UI.
tools: Read, Grep, Glob, Bash
model: sonnet
skills: [redesign-existing-projects]
---
Você critica a interface; não edita. Use a lente de auditoria do `redesign-existing-projects` e, se
instalada, a do `impeccable` (`/impeccable audit`).
1. **Veja a tela.** Com o dev server de pé: `npx playwright screenshot --viewport-size=375,812 <url> /tmp/ui-375.png`
e `--viewport-size=1280,800` para desktop. Abra as imagens com Read. Sem servidor, avalie pelo código e diga isso.
2. **Estados**: carregando, vazio, erro e sucesso existem em cada fluxo com dados.
3. **Acessibilidade**: HTML semântico, foco visível e em ordem, rótulos, contraste de texto >= 4.5:1.
Se houver Playwright: `@axe-core/playwright` sem violação `serious` ou `critical`.
4. **Responsivo**: nada corta ou sobrepõe em 375 px e em 1280 px.
5. **Padrão genérico**: gradiente roxo, glassmorphism sem motivo, cards idênticos, ícones decorativos,
microcopy vaga ("Unlock the power of..."). Aponte o que trocar.
Entregue achados priorizados: o que está errado, onde (`arquivo:linha` ou região da screenshot) e a
correção concreta. No máximo 10.
+17
View File
@@ -0,0 +1,17 @@
---
name: verifier
description: Roda o gate de qualidade no nível pedido e devolve a evidência - veredito, checagens que falharam com a saída relevante e o que ficou não verificado. Nunca edita código.
tools: Bash, Read
model: haiku
---
1. Rode `"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier N` com o nível recebido.
2. Leia `.dev-workflows/gate.json`.
3. Devolva:
- o veredito (`pass`, `fail` ou `incomplete`);
- cada checagem `fail` com as linhas da saída que mostram o motivo;
- a lista de checagens `unverified` (ferramenta ou configuração ausente);
- dependências novas, se houver;
- o `diff` (arquivos e linhas líquidas).
Não edite nada e não reinterprete uma falha como aprovação. Se o gate não rodou, diga por quê.
-51
View File
@@ -1,51 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="420" viewBox="0 0 1200 420" role="img" aria-labelledby="title desc">
<title id="title">dev-workflows</title>
<desc id="desc">dev-workflows: agent workflows where every phase ends in a verification step. On the right, the wf-security-review SKILL.md as a checklist: SCOPE, HUNT known CVEs, CONSULT OSV.dev and NVD, CODE REVIEW against OWASP Top 10, REPORT and GATE with sources and date.</desc>
<rect width="1200" height="420" rx="24" fill="#111110"/>
<g id="title-block" font-family="system-ui, -apple-system, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif">
<text x="64" y="156" font-size="68" font-weight="700" fill="#f2efe8">dev-workflows</text>
<text x="64" y="214" font-size="28" fill="#f2efe8">Agent workflows where every phase</text>
<text x="64" y="252" font-size="28" fill="#f2efe8">ends in a verification step.</text>
<text x="64" y="326" font-size="20" fill="#8f8b83" font-family="ui-monospace, &quot;SF Mono&quot;, Consolas, monospace">SKILL.md · Python QA harness · MIT</text>
</g>
<g id="skill-file" transform="translate(640 44)" font-family="ui-monospace, &quot;SF Mono&quot;, Consolas, monospace">
<rect width="496" height="332" rx="16" fill="#1b1b19" stroke="#2f2e2b" stroke-width="2"/>
<text x="24" y="30" font-size="18" fill="#8f8b83">wf-security-review/SKILL.md</text>
<line x1="0" y1="48" x2="496" y2="48" stroke="#2f2e2b" stroke-width="2"/>
<g id="phases" font-size="20" fill="#f2efe8">
<g transform="translate(24 76)">
<rect width="24" height="24" rx="5" fill="#3fb950"/>
<path d="M6 12 L10.5 16.5 L18 8" fill="none" stroke="#111110" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<text x="40" y="19">1 SCOPE</text>
<text x="448" y="19" font-size="18" fill="#8f8b83" text-anchor="end">target</text>
</g>
<g transform="translate(24 128)">
<rect width="24" height="24" rx="5" fill="#3fb950"/>
<path d="M6 12 L10.5 16.5 L18 8" fill="none" stroke="#111110" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<text x="40" y="19">2 HUNT</text>
<text x="448" y="19" font-size="18" fill="#8f8b83" text-anchor="end">known CVEs</text>
</g>
<g transform="translate(24 180)">
<rect width="24" height="24" rx="5" fill="#3fb950"/>
<path d="M6 12 L10.5 16.5 L18 8" fill="none" stroke="#111110" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<text x="40" y="19">3 CONSULT</text>
<text x="448" y="19" font-size="18" fill="#8f8b83" text-anchor="end">OSV.dev · NVD</text>
</g>
<g transform="translate(24 232)">
<rect width="24" height="24" rx="5" fill="#3fb950"/>
<path d="M6 12 L10.5 16.5 L18 8" fill="none" stroke="#111110" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<text x="40" y="19">4 CODE REVIEW</text>
<text x="448" y="19" font-size="18" fill="#8f8b83" text-anchor="end">OWASP Top 10</text>
</g>
<g transform="translate(24 284)">
<rect x="1" y="1" width="22" height="22" rx="5" fill="none" stroke="#f2efe8" stroke-width="2"/>
<text x="40" y="19">5 REPORT + GATE</text>
<text x="448" y="19" font-size="18" fill="#8f8b83" text-anchor="end">sources + date</text>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

+27
View File
@@ -0,0 +1,27 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/bash_guard.py\"" }
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{ "type": "command", "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/post_edit.py\"", "timeout": 60 }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/stop_gate.py\"" }
]
}
]
}
}
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""Compares each vendored skill's recorded commit (skills/NOTICE.md) with its upstream HEAD. Exit 1 if any moved.
python3 qa/check_upstream.py
"""
import os, re, subprocess, sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def main():
notice = open(os.path.join(ROOT, "skills", "NOTICE.md"), encoding="utf-8").read()
repos = {}
for row in re.findall(r"^\|\s*`[\w-]+`\s*\|(.+)$", notice, re.M):
cols = [c.strip() for c in row.split("|")]
repo = re.search(r"([\w.-]+/[\w.-]+)", cols[0])
sha = re.search(r"`([0-9a-f]{7,40})`", cols[1])
if repo and sha:
repos[repo.group(1)] = sha.group(1)
moved = 0
for repo, sha in sorted(repos.items()):
p = subprocess.run(["git", "ls-remote", f"https://github.com/{repo}", "HEAD"], capture_output=True, text=True, timeout=60)
head = p.stdout.split()[0] if p.returncode == 0 and p.stdout else None
if head is None:
print(f"? {repo}: não consegui consultar")
elif head.startswith(sha):
print(f"ok {repo} {sha}")
else:
moved += 1
print(f"-> {repo}: vendorizado {sha}, upstream {head[:7]} (https://github.com/{repo}/compare/{sha}...{head[:7]})")
return 1 if moved else 0
if __name__ == "__main__":
sys.exit(main())
+126
View File
@@ -0,0 +1,126 @@
#!/usr/bin/env python3
"""Structural lint for the plugin: frontmatter, sizes, references, links and leftover machine-specific paths.
Run from anywhere: python3 qa/lint_skills.py (exit 1 on any error)
"""
import json, os, re, sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MAX_LINES = 150
MAX_DESC = 1024
FORBIDDEN = [r"~/\.hermes", r"vision_analyze", r"search_files", r"test_quality\.py", r"wf_quality_harness"]
MODELS = {"haiku", "sonnet", "opus", "inherit"}
TOOLS = {"Read", "Edit", "Write", "Bash", "Grep", "Glob", "WebFetch", "WebSearch", "NotebookEdit", "Agent", "Skill"}
errors = []
def err(path, msg):
errors.append(f"{os.path.relpath(path, ROOT)}: {msg}")
def frontmatter(path):
text = open(path, encoding="utf-8").read()
m = re.match(r"---\n(.*?)\n---\n", text, re.S)
if not m:
err(path, "sem frontmatter")
return {}, text
fm = m.group(1)
meta = dict(re.findall(r"^([\w-]+):[ \t]*(.*)$", fm, re.M))
for key in ("uses", "external", "skills"):
lst = re.search(rf"^\s*{key}:\s*\[(.*?)\]", fm, re.M)
if lst:
meta[key] = [s.strip().strip("'\"") for s in lst.group(1).split(",") if s.strip()]
return meta, text
def vendored():
rows = open(os.path.join(ROOT, "skills", "NOTICE.md"), encoding="utf-8").read()
return set(re.findall(r"^\|\s*`([\w-]+)`\s*\|", rows, re.M))
def check_links(path, text):
text = re.sub(r"```.*?```|`[^`\n]*`", "", text, flags=re.S)
for target in re.findall(r"\]\(([^)\s]+)\)", text):
if re.match(r"(https?:|mailto:|#)", target):
continue
p = os.path.normpath(os.path.join(os.path.dirname(path), target.split("#")[0]))
if not os.path.exists(p):
err(path, f"link quebrado: {target}")
def main():
skills_dir = os.path.join(ROOT, "skills")
names = {d for d in os.listdir(skills_dir) if os.path.isfile(os.path.join(skills_dir, d, "SKILL.md"))}
third_party = vendored()
catalog = open(os.path.join(ROOT, "docs", "SKILLS.md"), encoding="utf-8").read()
for name in sorted(names):
path = os.path.join(skills_dir, name, "SKILL.md")
meta, text = frontmatter(path)
if meta.get("name") != name:
err(path, f"name '{meta.get('name')}' difere da pasta '{name}'")
desc = meta.get("description", "")
if not desc:
err(path, "description vazia")
if name in third_party:
continue
if len(desc) > MAX_DESC:
err(path, f"description com {len(desc)} caracteres (máx {MAX_DESC})")
lines = text.count("\n")
if lines > MAX_LINES:
err(path, f"{lines} linhas (máx {MAX_LINES}); mova detalhes para references/")
for used in meta.get("uses", []):
if used not in names:
err(path, f"uses: '{used}' não existe em skills/")
for ext in meta.get("external", []):
if f"`{ext}`" not in catalog:
err(path, f"external: '{ext}' não está em docs/SKILLS.md")
for dirpath, _, files in os.walk(os.path.join(skills_dir, name)):
for f in files:
if f.endswith(".md"):
p = os.path.join(dirpath, f)
body = open(p, encoding="utf-8").read()
check_links(p, body)
for pat in FORBIDDEN:
if re.search(pat, body):
err(p, f"referência específica de máquina: {pat}")
agents_dir = os.path.join(ROOT, "agents")
for f in sorted(os.listdir(agents_dir)):
path = os.path.join(agents_dir, f)
meta, text = frontmatter(path)
if meta.get("name") != f[:-3]:
err(path, f"name '{meta.get('name')}' difere do arquivo")
if meta.get("model") not in MODELS:
err(path, f"model '{meta.get('model')}' inválido")
bad = {t.strip() for t in meta.get("tools", "").split(",")} - TOOLS
if bad:
err(path, f"tools desconhecidas: {', '.join(sorted(bad))}")
for s in meta.get("skills", []):
if s not in names:
err(path, f"skills: '{s}' não existe em skills/")
for pat in FORBIDDEN:
if re.search(pat, text):
err(path, f"referência específica de máquina: {pat}")
hooks = json.load(open(os.path.join(ROOT, "hooks", "hooks.json")))
for groups in hooks["hooks"].values():
for g in groups:
for h in g["hooks"]:
for script in re.findall(r"\$\{CLAUDE_PLUGIN_ROOT\}/([\w/.-]+)", h["command"]):
if not os.path.isfile(os.path.join(ROOT, script)):
err(os.path.join(ROOT, "hooks", "hooks.json"), f"script inexistente: {script}")
for doc in ("README.md", "README.pt-BR.md", "CONTRIBUTING.md", os.path.join("docs", "SKILLS.md")):
p = os.path.join(ROOT, doc)
if os.path.exists(p):
check_links(p, open(p, encoding="utf-8").read())
for e in errors:
print("ERRO " + e)
print(f"{len(names)} skills, {len(os.listdir(agents_dir))} agentes, {len(errors)} erro(s)")
return 1 if errors else 0
if __name__ == "__main__":
sys.exit(main())
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Smoke tests for scripts/quality-gate and the hook scripts, on a throwaway git repo. Stdlib only.
python3 qa/test_gate.py
"""
import importlib.util, json, os, subprocess, sys, tempfile, unittest
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
GATE = os.path.join(ROOT, "scripts", "quality-gate")
STOP = os.path.join(ROOT, "scripts", "hooks", "stop_gate.py")
spec = importlib.util.spec_from_file_location("bash_guard", os.path.join(ROOT, "scripts", "hooks", "bash_guard.py"))
bash_guard = importlib.util.module_from_spec(spec)
spec.loader.exec_module(bash_guard)
def run(cmd, cwd, stdin=None):
return subprocess.run(cmd, cwd=cwd, input=stdin, capture_output=True, text=True)
class GateTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.repo = self.tmp.name
for c in (["git", "init", "-q"], ["git", "config", "user.email", "t@t"], ["git", "config", "user.name", "t"]):
run(c, self.repo)
self.write("calc.py", "def add(a, b):\n return a + b\n")
self.write("check.py", "from calc import add\nassert add(1, 2) == 3\n")
self.write(".dev-workflows.toml", '[commands]\ntest = "python3 check.py"\nlint = "true"\ntypecheck = "true"\n')
self.write("package.json", '{"dependencies": {"left-pad": "1"}}')
run(["git", "add", "-A"], self.repo)
run(["git", "commit", "-qm", "init"], self.repo)
def tearDown(self):
self.tmp.cleanup()
def write(self, name, text):
open(os.path.join(self.repo, name), "w").write(text)
def gate(self, tier=0):
p = run([sys.executable, GATE, "--tier", str(tier)], self.repo)
return p.returncode, json.load(open(os.path.join(self.repo, ".dev-workflows", "gate.json")))
def stop(self):
out = run([sys.executable, STOP], self.repo, json.dumps({"cwd": self.repo})).stdout
return json.loads(out)["reason"] if out.strip() else None
def status(self, report, name):
return next(c["status"] for c in report["checks"] if c["name"] == name)
def test_clean_tree_does_not_block(self):
self.assertIsNone(self.stop())
def test_change_without_gate_blocks_then_passing_gate_allows(self):
self.write("calc.py", "def add(a, b):\n return a + b\n\n\ndef sub(a, b):\n return a - b\n")
self.assertIn("sem gate", self.stop())
code, report = self.gate()
self.assertEqual(code, 0)
self.assertEqual(self.status(report, "test"), "pass")
self.assertIsNone(self.stop())
def test_failing_test_fails_gate_and_blocks(self):
self.write("calc.py", "def add(a, b):\n return a - b\n")
code, report = self.gate()
self.assertEqual((code, report["verdict"]), (1, "fail"))
self.assertIn("test", self.stop())
def test_missing_tool_is_unverified_not_passed(self):
self.write(".dev-workflows.toml", '[commands]\ntest = "definitely-not-a-tool-xyz"\n')
self.write("calc.py", "def add(a, b):\n return b + a\n")
code, report = self.gate()
self.assertEqual(self.status(report, "test"), "unverified")
self.assertEqual(report["verdict"], "incomplete")
def test_new_dependency_is_reported(self):
self.write("package.json", '{"dependencies": {"left-pad": "1", "is-odd": "3"}}')
self.write("calc.py", "def add(a, b):\n return a + b # touched\n")
_, report = self.gate()
self.assertEqual(report["new_dependencies"], ["npm:is-odd"])
def test_stale_gate_blocks(self):
self.write("calc.py", "def add(a, b):\n return a + b # v2\n")
self.gate()
os.utime(os.path.join(self.repo, ".dev-workflows", "gate.json"), (1, 1))
self.assertIn("mudou depois", self.stop())
class GuardTest(unittest.TestCase):
def test_decisions(self):
cases = {"git commit --no-verify -m x": "deny", "git push -f origin main": "deny",
"git push --force-with-lease": None, "rm -rf /": "deny", "rm -rf node_modules": None,
"git reset --hard": "ask", "npm test": None}
for cmd, expected in cases.items():
self.assertEqual(bash_guard.decide(cmd)[0], expected, cmd)
if __name__ == "__main__":
unittest.main(verbosity=1)
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
"""PreToolUse guard for shell commands: denies gate bypasses, asks before destructive git/db commands.
Claude Code: reads the hook JSON on stdin and prints a permissionDecision.
opencode: `bash_guard.py --check "<command>"` prints the reason and exits 2 when the command must not run.
"""
import json, re, sys
DENY = [
(r"(^|\s)--no-verify(\s|$)", "--no-verify pula os hooks do git. Corrija o que o hook reclamou em vez de pular."),
(r"\bgit\s+push\b(?=.*\s(--force|-f)(\s|$))(?!.*--force-with-lease)", "push --force reescreve histórico remoto. Use --force-with-lease e só com pedido explícito do usuário."),
(r"\brm\s+(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r)[a-zA-Z]*\s+(/|~|\$HOME|/\*|\.\.)(\s|/?$)", "rm -rf na raiz, no home ou no diretório pai não roda."),
]
ASK = [
(r"\bgit\s+reset\s+--hard\b", "git reset --hard descarta trabalho não commitado."),
(r"\bgit\s+clean\s+-[a-zA-Z]*f", "git clean -f apaga arquivos não rastreados."),
(r"\bgit\s+(checkout|restore)\s+(--\s+)?\.(\s|$)", "descarta todas as mudanças locais."),
(r"\b(DROP\s+(DATABASE|TABLE|SCHEMA)|TRUNCATE\s+TABLE)\b", "comando destrutivo de banco de dados."),
]
def decide(command):
for pattern, why in DENY:
if re.search(pattern, command, re.IGNORECASE):
return "deny", why
for pattern, why in ASK:
if re.search(pattern, command, re.IGNORECASE):
return "ask", why
return None, None
def main():
if len(sys.argv) > 2 and sys.argv[1] == "--check":
decision, why = decide(sys.argv[2])
if decision: # opencode has no "ask": both block, the agent must ask the user
print(f"[dev-workflows] {why} Peça confirmação ao usuário.")
return 2
return 0
event = json.load(sys.stdin)
decision, why = decide(event.get("tool_input", {}).get("command", ""))
if decision:
print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": decision,
"permissionDecisionReason": f"[dev-workflows] {why}"}}, ensure_ascii=False))
return 0
if __name__ == "__main__":
sys.exit(main())
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""PostToolUse: formats the edited file with the formatter the project already uses. Never fails the edit.
Claude Code: reads tool_input.file_path from the hook JSON on stdin.
opencode: `post_edit.py --file <path>`.
"""
import json, os, shutil, subprocess, sys
PRETTIER_EXT = {".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".json", ".css", ".scss", ".html", ".vue", ".svelte", ".md", ".yaml", ".yml"}
def project_root(path):
d = os.path.dirname(os.path.abspath(path))
while d != os.path.dirname(d):
if any(os.path.exists(os.path.join(d, m)) for m in ("package.json", "pyproject.toml", "go.mod", "Cargo.toml", ".git")):
return d
d = os.path.dirname(d)
return None
def uses_ruff(root):
if os.path.exists(os.path.join(root, "ruff.toml")) or os.path.exists(os.path.join(root, ".ruff.toml")):
return True
pyproject = os.path.join(root, "pyproject.toml")
return os.path.exists(pyproject) and "[tool.ruff" in open(pyproject).read()
def formatter(path, root):
ext = os.path.splitext(path)[1].lower()
prettier = os.path.join(root, "node_modules", ".bin", "prettier")
if ext in PRETTIER_EXT and os.path.exists(prettier):
return [prettier, "--write", "--log-level", "warn", path]
if ext == ".py" and shutil.which("ruff") and uses_ruff(root):
return ["ruff", "format", "--quiet", path]
if ext == ".go" and shutil.which("gofmt"):
return ["gofmt", "-w", path]
if ext == ".rs" and shutil.which("rustfmt"):
return ["rustfmt", path]
return None
def main():
if len(sys.argv) > 2 and sys.argv[1] == "--file":
path = sys.argv[2]
else:
path = json.load(sys.stdin).get("tool_input", {}).get("file_path", "")
root = project_root(path) if path and os.path.isfile(path) else None
cmd = formatter(path, root) if root else None
if cmd:
try:
subprocess.run(cmd, cwd=root, capture_output=True, timeout=30)
except (subprocess.TimeoutExpired, OSError):
pass
return 0
if __name__ == "__main__":
sys.exit(main())
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Stop hook: blocks "done" while uncommitted code changes lack a fresh, non-failing quality-gate report.
Claude Code: reads the hook JSON on stdin, prints {"decision": "block", ...} to keep the agent working.
opencode: `stop_gate.py --check <dir>` prints the reason and exits 2 when it would block.
Disable with DW_GATE=off.
"""
import json, os, subprocess, sys
DOC_EXT = {".md", ".mdx", ".txt", ".rst", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"}
PLUGIN_ROOT = os.environ.get("CLAUDE_PLUGIN_ROOT") or os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
GATE = os.path.join(PLUGIN_ROOT, "scripts", "quality-gate")
def pending_code_files(cwd):
p = subprocess.run(["git", "status", "--porcelain", "--untracked-files=all"], cwd=cwd, capture_output=True, text=True)
if p.returncode != 0:
return None
files = []
for line in p.stdout.splitlines():
path = line[3:].split(" -> ")[-1].strip('"')
if line[:2].strip() == "D" or path.startswith(".dev-workflows/"):
continue
if os.path.splitext(path)[1].lower() not in DOC_EXT and os.path.isfile(os.path.join(cwd, path)):
files.append(path)
return files
def reason_to_block(cwd):
if os.environ.get("DW_GATE") == "off":
return None
top = subprocess.run(["git", "rev-parse", "--show-toplevel"], cwd=cwd, capture_output=True, text=True)
if top.returncode != 0:
return None
root = top.stdout.strip()
files = pending_code_files(root)
if not files:
return None
run = f'"{GATE}" --tier <nível do dev-router>'
report = os.path.join(root, ".dev-workflows", "gate.json")
if not os.path.isfile(report):
return f"Há {len(files)} arquivo(s) de código alterados sem gate de qualidade. Rode {run} e trate o resultado antes de encerrar."
newest = max(os.path.getmtime(os.path.join(root, f)) for f in files)
if os.path.getmtime(report) < newest:
return f"O código mudou depois do último gate. Rode de novo {run} antes de encerrar."
data = json.load(open(report))
if data.get("verdict") == "fail":
failed = ", ".join(c["name"] for c in data.get("checks", []) if c.get("status") == "fail")
return f"O gate falhou em: {failed}. Corrija (veja .dev-workflows/gate.json) ou explique ao usuário por que não dá para corrigir."
return None
def main():
if len(sys.argv) > 2 and sys.argv[1] == "--check":
why = reason_to_block(sys.argv[2])
if why:
print(why)
return 2
return 0
event = json.load(sys.stdin)
if event.get("stop_hook_active"):
return 0
why = reason_to_block(event.get("cwd") or os.getcwd())
if why:
print(json.dumps({"decision": "block", "reason": why}, ensure_ascii=False))
return 0
if __name__ == "__main__":
sys.exit(main())
+99
View File
@@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""Install dev-workflows into Claude Code, opencode or Hermes Agent.
python3 scripts/install.py claude # plugin via local marketplace (skills, agents, hooks)
python3 scripts/install.py opencode # skills + agents + plugin under ~/.config/opencode
python3 scripts/install.py hermes # skills under ~/.hermes/skills (no agents/hooks there)
opencode and Hermes do not substitute ${CLAUDE_PLUGIN_ROOT}, so the copies point at this checkout:
keep it where it is, or re-run the install after moving it.
"""
import argparse, os, re, shutil, subprocess, sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MARKER = ".dev-workflows-install"
TEXT_EXT = {".md", ".txt", ".json", ".toml", ".yaml", ".yml"}
def copy_tree(src, dst, force):
if os.path.exists(dst) and not os.path.exists(os.path.join(dst, MARKER)) and not force:
sys.exit(f"{dst} já existe e não foi instalado por este script. Use --force para sobrescrever.")
shutil.rmtree(dst, ignore_errors=True)
shutil.copytree(src, dst)
for dirpath, _, names in os.walk(dst):
for n in names:
if os.path.splitext(n)[1] in TEXT_EXT:
p = os.path.join(dirpath, n)
text = open(p, encoding="utf-8", errors="ignore").read()
if "${CLAUDE_PLUGIN_ROOT}" in text:
open(p, "w", encoding="utf-8").write(text.replace("${CLAUDE_PLUGIN_ROOT}", ROOT))
open(os.path.join(dst, MARKER), "w").write(ROOT + "\n")
def install_skills(target_dir, force):
os.makedirs(target_dir, exist_ok=True)
names = sorted(d for d in os.listdir(os.path.join(ROOT, "skills"))
if os.path.isfile(os.path.join(ROOT, "skills", d, "SKILL.md")))
for name in names:
copy_tree(os.path.join(ROOT, "skills", name), os.path.join(target_dir, name), force)
print(f"{len(names)} skills em {target_dir}")
def opencode_agent(path):
"""Claude Code agent frontmatter -> opencode subagent frontmatter."""
text = open(path, encoding="utf-8").read()
m = re.match(r"---\n(.*?)\n---\n(.*)", text, re.S)
meta = dict(re.findall(r"^(\w+):\s*(.*)$", m.group(1), re.M))
tools = {t.strip() for t in meta.get("tools", "").split(",")}
skills = re.findall(r"[\w-]+", meta.get("skills", ""))
perm = {"edit": "allow" if tools & {"Edit", "Write"} else "deny",
"bash": "allow" if "Bash" in tools else "deny",
"webfetch": "allow" if "WebFetch" in tools else "deny"}
body = m.group(2).replace("${CLAUDE_PLUGIN_ROOT}", ROOT)
if skills:
body = f"Antes de começar, carregue a(s) skill(s): {', '.join(skills)}.\n\n" + body
head = ["# dev-workflows", f"description: {meta['description']}", "mode: subagent", "permission:"]
head += [f" {k}: {v}" for k, v in perm.items()]
return "---\n" + "\n".join(head) + "\n---\n\n" + body
def install_opencode(force):
base = os.path.expanduser("~/.config/opencode")
install_skills(os.path.join(base, "skills"), force)
agents_dir = os.path.join(base, "agents")
os.makedirs(agents_dir, exist_ok=True)
for f in sorted(os.listdir(os.path.join(ROOT, "agents"))):
dst = os.path.join(agents_dir, f)
if os.path.exists(dst) and "dev-workflows" not in open(dst, encoding="utf-8").read() and not force:
sys.exit(f"{dst} já existe e não é deste pacote. Use --force para sobrescrever.")
open(dst, "w", encoding="utf-8").write(opencode_agent(os.path.join(ROOT, "agents", f)))
plugins_dir = os.path.join(base, "plugins")
os.makedirs(plugins_dir, exist_ok=True)
plugin = open(os.path.join(ROOT, "adapters", "opencode", "dev-workflows.ts"), encoding="utf-8").read()
open(os.path.join(plugins_dir, "dev-workflows.ts"), "w", encoding="utf-8").write(plugin.replace("__DW_ROOT__", ROOT))
print(f"agentes em {agents_dir}, plugin em {plugins_dir}/dev-workflows.ts")
def install_claude():
for cmd in (["claude", "plugin", "marketplace", "add", ROOT], ["claude", "plugin", "install", "dev-workflows@dev-workflows"]):
print("$ " + " ".join(cmd))
if subprocess.run(cmd).returncode != 0:
sys.exit("falhou; rode o comando acima manualmente para ver o erro")
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("target", choices=["claude", "opencode", "hermes"])
ap.add_argument("--force", action="store_true", help="sobrescreve pastas com o mesmo nome que não vieram deste script")
a = ap.parse_args()
if a.target == "claude":
install_claude()
elif a.target == "opencode":
install_opencode(a.force)
else:
install_skills(os.path.expanduser("~/.hermes/skills"), a.force)
print("Hermes: agentes e hooks não se aplicam; rode o gate manualmente.")
if __name__ == "__main__":
main()
+304
View File
@@ -0,0 +1,304 @@
#!/usr/bin/env python3
"""Deterministic quality gate: runs only the checks of the requested tier, scoped to the diff.
Usage: quality-gate [--tier 0-3] [--base REF] [--dir PATH] [--list]
Writes .dev-workflows/gate.json in the project root. Exit 1 when any check fails.
A tool that is not installed is reported as "unverified", never as passed.
"""
import argparse, json, os, re, shutil, subprocess, sys, tempfile, time, tomllib
CODE_EXT = {".py", ".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".vue", ".svelte", ".go", ".rs",
".java", ".kt", ".rb", ".php", ".cs", ".sql", ".sh", ".css", ".scss", ".html"}
JS_EXT = {".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".vue", ".svelte"}
def sh(cmd, cwd, timeout=600):
t = time.time()
try:
p = subprocess.run(cmd, cwd=cwd, shell=isinstance(cmd, str), capture_output=True, text=True, timeout=timeout)
out, code = (p.stdout + p.stderr), p.returncode
except subprocess.TimeoutExpired:
out, code = f"timeout after {timeout}s", 124
return code, out, round(time.time() - t, 1)
def git(args, cwd):
code, out, _ = sh(["git", *args], cwd, 60)
return out.strip() if code == 0 else None
def find_base(root, explicit):
if explicit:
return explicit
for ref in ("origin/HEAD", "origin/main", "origin/master", "main", "master"):
mb = git(["merge-base", "HEAD", ref], root)
if mb:
return mb
return "HEAD" if git(["rev-parse", "HEAD"], root) else None
def changed_files(root, base):
if base is None:
return []
names = (git(["diff", "--name-only", "--diff-filter=d", base], root) or "").splitlines()
names += (git(["ls-files", "--others", "--exclude-standard"], root) or "").splitlines()
return sorted({n for n in names if n and not n.startswith(".dev-workflows/") and os.path.isfile(os.path.join(root, n))})
def diff_stats(root, base, files):
added = removed = 0
for line in (git(["diff", "--numstat", base], root) or "").splitlines() if base else []:
a, r, _ = (line.split("\t") + ["", ""])[:3]
added += int(a) if a.isdigit() else 0
removed += int(r) if r.isdigit() else 0
for f in (git(["ls-files", "--others", "--exclude-standard"], root) or "").splitlines():
if f in files:
try:
added += sum(1 for _ in open(os.path.join(root, f), errors="ignore"))
except OSError:
pass
return {"files": len(files), "added": added, "removed": removed, "net": added - removed}
def deps_at(root, rev):
"""Dependency names declared in package.json / requirements*.txt / pyproject.toml at a revision (None = working tree)."""
def read(path):
if rev is None:
p = os.path.join(root, path)
return open(p).read() if os.path.isfile(p) else None
return git(["show", f"{rev}:{path}"], root)
names = set()
pkg = read("package.json")
if pkg:
try:
d = json.loads(pkg)
for k in ("dependencies", "devDependencies", "optionalDependencies"):
names |= {f"npm:{n}" for n in d.get(k, {})}
except ValueError:
pass
for req in [f for f in os.listdir(root) if re.fullmatch(r"requirements.*\.txt", f)]:
for line in (read(req) or "").splitlines():
m = re.match(r"\s*([A-Za-z0-9_.\-]+)", line)
if m and not line.strip().startswith(("#", "-")):
names.add(f"py:{m.group(1).lower()}")
py = read("pyproject.toml")
if py:
try:
proj = tomllib.loads(py).get("project", {})
for spec in proj.get("dependencies", []) + sum(proj.get("optional-dependencies", {}).values(), []):
m = re.match(r"\s*([A-Za-z0-9_.\-]+)", spec)
if m:
names.add(f"py:{m.group(1).lower()}")
except tomllib.TOMLDecodeError:
pass
return names
def load_config(root):
p = os.path.join(root, ".dev-workflows.toml")
if not os.path.isfile(p):
return {}
with open(p, "rb") as f:
return tomllib.load(f)
def local_bin(root, name):
p = os.path.join(root, "node_modules", ".bin", name)
return p if os.path.exists(p) else shutil.which(name)
def node_pm(root):
for lock, pm in (("pnpm-lock.yaml", "pnpm"), ("yarn.lock", "yarn"), ("bun.lockb", "bun"), ("bun.lock", "bun")):
if os.path.exists(os.path.join(root, lock)):
return pm
return "npm"
def plan_checks(root, cfg, files, base):
"""Returns [(name, tier, cmd|None, kind)] ; kind: gate (fails the gate) | info (report only)."""
cmds = cfg.get("commands", {})
exts = {os.path.splitext(f)[1] for f in files}
js_files = [f for f in files if os.path.splitext(f)[1] in JS_EXT]
py_files = [f for f in files if f.endswith(".py")]
checks = []
pkg = {}
if os.path.isfile(os.path.join(root, "package.json")):
try:
pkg = json.load(open(os.path.join(root, "package.json"))).get("scripts", {})
except ValueError:
pkg = {}
pm = node_pm(root)
is_py = any(os.path.exists(os.path.join(root, f)) for f in ("pyproject.toml", "setup.py", "requirements.txt"))
pyproject = {}
if os.path.isfile(os.path.join(root, "pyproject.toml")):
try:
pyproject = tomllib.load(open(os.path.join(root, "pyproject.toml"), "rb"))
except tomllib.TOMLDecodeError:
pass
tool = pyproject.get("tool", {})
def pick(key, *candidates):
if key in cmds:
return cmds[key]
return next((c for c in candidates if c), None)
lint = pick("lint",
f"{pm} run lint" if "lint" in pkg else None,
(local_bin(root, "eslint") and js_files and [local_bin(root, "eslint"), *js_files]),
(shutil.which("ruff") and py_files and ["ruff", "check", *py_files]),
("go vet ./..." if os.path.exists(os.path.join(root, "go.mod")) else None),
("cargo clippy -- -D warnings" if os.path.exists(os.path.join(root, "Cargo.toml")) else None))
typecheck = pick("typecheck",
next((f"{pm} run {s}" for s in ("typecheck", "type-check", "tsc") if s in pkg), None),
(os.path.exists(os.path.join(root, "tsconfig.json")) and local_bin(root, "tsc") and [local_bin(root, "tsc"), "--noEmit"]),
(("pyright" in tool or os.path.exists(os.path.join(root, "pyrightconfig.json"))) and shutil.which("pyright") and ["pyright"]),
("mypy" in tool and shutil.which("mypy") and ["mypy", "."]))
venv_py = next((os.path.join(root, v, "bin", "python") for v in (".venv", "venv")
if os.path.exists(os.path.join(root, v, "bin", "python"))), "python3")
test = pick("test",
f"{pm} run test" if "test" in pkg else None,
(is_py and [venv_py, "-m", "pytest", "-q"]),
("go test ./..." if os.path.exists(os.path.join(root, "go.mod")) else None),
("cargo test" if os.path.exists(os.path.join(root, "Cargo.toml")) else None))
build = pick("build", f"{pm} run build" if "build" in pkg else None)
checks += [("lint", 0, lint, "gate"), ("typecheck", 0, typecheck, "gate"), ("test", 0, test, "gate")]
checks.append(("secrets", 0, "@gitleaks" if shutil.which("gitleaks") else None, "gate"))
cov = os.path.join(root, cfg.get("coverage", {}).get("report", "coverage.xml"))
fail_under = cfg.get("thresholds", {}).get("diff_coverage", 80)
checks.append(("diff-coverage", 1,
shutil.which("diff-cover") and os.path.isfile(cov) and base
and ["diff-cover", cov, f"--compare-branch={base}", f"--fail-under={fail_under}"], "gate"))
checks.append(("semgrep", 1, shutil.which("semgrep") and base and
["semgrep", "scan", "--config", "p/default", "--error", "--metrics=off", "--quiet",
"--baseline-commit", base], "gate"))
dead = (local_bin(root, "knip") and pkg and [local_bin(root, "knip"), "--no-exit-code"]) or \
(shutil.which("vulture") and py_files and ["vulture", *py_files, "--min-confidence", "80"])
checks.append(("dead-code", 1, dead, "info"))
checks.append(("build", 2, build, "gate") if build else ("build", 2, "@skip", "gate"))
stryker_cfg = any(os.path.exists(os.path.join(root, f)) for f in
("stryker.config.mjs", "stryker.config.js", "stryker.config.json", "stryker.conf.js", ".stryker.conf.json"))
mut = None
if stryker_cfg and local_bin(root, "stryker") and js_files:
mut = [local_bin(root, "stryker"), "run", "--mutate", ",".join(js_files)]
elif "mutmut" in tool and shutil.which("mutmut"):
mut = ["mutmut", "run"] # ponytail: mutmut 3 runs its configured paths, not only the diff
checks.append(("mutation", 2, cmds.get("mutation", mut), "gate"))
checks.append(("osv-scanner", 2, shutil.which("osv-scanner") and ["osv-scanner", "scan", "source", "--recursive", "."], "gate"))
cruiser = next((f for f in (".dependency-cruiser.js", ".dependency-cruiser.cjs", ".dependency-cruiser.json")
if os.path.exists(os.path.join(root, f))), None)
arch = (cruiser and local_bin(root, "depcruise") and js_files and [local_bin(root, "depcruise"), "--config", cruiser, *js_files]) or \
(("importlinter" in tool or os.path.exists(os.path.join(root, ".importlinter"))) and shutil.which("lint-imports") and ["lint-imports"])
checks.append(("architecture", 2, cmds.get("architecture", arch) or "@skip", "gate"))
checks.append(("duplication", 2, local_bin(root, "jscpd") and js_files and [local_bin(root, "jscpd"), *js_files], "info"))
checks.append(("trivy", 3, shutil.which("trivy") and
["trivy", "fs", "--exit-code", "1", "--severity", "HIGH,CRITICAL", "--scanners", "vuln,misconfig,secret", "."], "gate"))
if cfg.get("spec", {}).get("file"):
checks.append(("traceability", 3, "@trace", "gate"))
for extra in cfg.get("check", []):
checks.append((extra["name"], int(extra.get("tier", 2)), extra["cmd"], extra.get("kind", "gate")))
if not exts & CODE_EXT and files:
checks = [c for c in checks if c[0] == "secrets"]
return checks
def run_gitleaks(root, files):
with tempfile.TemporaryDirectory() as tmp:
for f in files:
dst = os.path.join(tmp, f)
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy2(os.path.join(root, f), dst)
return sh(["gitleaks", "dir", "--no-banner", "--redact", tmp], root)
def run_trace(root, cfg):
spec = cfg["spec"]
text = open(os.path.join(root, spec["file"]), errors="ignore").read()
ids = sorted(set(re.findall(r"\bREQ-\d+\b", text)))
corpus = ""
for d in spec.get("tests", ["tests", "test", "src"]):
for dirpath, _, names in os.walk(os.path.join(root, d)):
for n in names:
corpus += open(os.path.join(dirpath, n), errors="ignore").read()
missing = [i for i in ids if i not in corpus]
msg = f"{len(ids)} requisitos, sem teste: {', '.join(missing) or 'nenhum'}"
return (1 if missing or not ids else 0), msg, 0.0
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("--tier", type=int, default=int(os.environ.get("DW_TIER", 1)), choices=range(4))
ap.add_argument("--base")
ap.add_argument("--dir", default=".")
ap.add_argument("--list", action="store_true", help="show the planned checks without running them")
a = ap.parse_args()
root = git(["rev-parse", "--show-toplevel"], a.dir) or os.path.abspath(a.dir)
cfg = load_config(root)
base = find_base(root, a.base)
files = changed_files(root, base)
planned = [c for c in plan_checks(root, cfg, files, base) if c[1] <= a.tier]
if a.list:
for name, tier, cmd, kind in planned:
state = "skip" if cmd == "@skip" else ("unverified (tool/config missing)" if not cmd else "run")
print(f"T{tier} {name:14} {kind:4} {state}")
return 0
results = []
for name, tier, cmd, kind in planned:
if cmd == "@skip":
continue
if not cmd:
results.append({"name": name, "tier": tier, "kind": kind, "status": "unverified"})
continue
if cmd == "@gitleaks":
code, out, secs = run_gitleaks(root, files) if files else (0, "no changed files", 0.0)
elif cmd == "@trace":
code, out, secs = run_trace(root, cfg)
else:
code, out, secs = sh(cmd, root, int(cfg.get("timeout", 600)))
missing_tool = code == 127 or re.search(r"No module named (pytest|mypy|pyright|ruff)\b", out)
status = "unverified" if missing_tool else "info" if kind == "info" else ("pass" if code == 0 else "fail")
results.append({"name": name, "tier": tier, "kind": kind, "status": status, "exit": code, "seconds": secs,
"cmd": cmd if isinstance(cmd, str) else " ".join(cmd),
"output_tail": "\n".join(out.strip().splitlines()[-30:])})
new_deps = sorted(deps_at(root, None) - deps_at(root, base)) if base else []
verdict = "fail" if any(r["status"] == "fail" for r in results) else \
"incomplete" if any(r["status"] == "unverified" for r in results) else "pass"
report = {"verdict": verdict, "tier": a.tier, "base": base, "generated_at": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
"diff": diff_stats(root, base, files), "changed_files": files, "new_dependencies": new_deps, "checks": results}
out_dir = os.path.join(root, ".dev-workflows")
os.makedirs(out_dir, exist_ok=True)
json.dump(report, open(os.path.join(out_dir, "gate.json"), "w"), indent=2, ensure_ascii=False)
with open(os.path.join(out_dir, "log.jsonl"), "a") as log:
log.write(json.dumps({k: report[k] for k in ("generated_at", "verdict", "tier", "diff")}) + "\n")
exclude = os.path.join(root, ".git", "info", "exclude")
if os.path.isdir(os.path.dirname(exclude)):
current = open(exclude).read() if os.path.exists(exclude) else ""
if ".dev-workflows/" not in current:
with open(exclude, "a") as f:
f.write("\n.dev-workflows/\n")
icon = {"pass": "ok", "fail": "FALHOU", "unverified": "não verificado", "info": "info"}
for r in results:
print(f" [{icon[r['status']]:>14}] T{r['tier']} {r['name']}")
d = report["diff"]
print(f"diff: {d['files']} arquivos, +{d['added']} -{d['removed']} (líquido {d['net']})")
if new_deps:
print("dependências novas (justifique cada uma): " + ", ".join(new_deps))
print(f"veredito: {verdict} -> {os.path.relpath(os.path.join(out_dir, 'gate.json'), os.getcwd())}")
return 1 if verdict == "fail" else 0
if __name__ == "__main__":
sys.exit(main())
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,204 @@
# Play: Security Code Review
A security code review identifies vulnerabilities in application logic, authentication, authorization, cryptography, and data handling. This play structures the review around OWASP weakness classes (injection, auth, crypto, etc.) and is applicable to any language or framework. Reviews can target full codebases, pull request diffs, or specific modules, and findings are mapped to OWASP standards and OpenCRE for multi-framework traceability.
Review code changes or codebases for security vulnerabilities, mapping findings to OWASP standards and OpenCRE cross-references for multi-framework traceability.
## Trigger Conditions
Use this skill when:
- Reviewing a pull request or diff for security issues
- A user asks for a security review of their code
- Auditing a specific file, module, or feature for vulnerabilities
- Performing a pre-merge security gate check
## Inputs
- Code diff (PR), specific files, or entire codebase to review
- (Optional) Language and framework context
- (Optional) ASVS level to verify against (L1, L2, or L3)
- (Optional) Specific concern areas to focus on
## Procedure
### 1. Scope & Context
Before diving in, establish:
- **Language/Framework**: Determines which vulnerability classes are relevant
- **Trust boundary**: Is this server-side, client-side, library, CLI, infrastructure code?
- **Data sensitivity**: Does this code handle PII, credentials, financial data, health data?
- **Exposure**: Is this internet-facing, internal, or local-only?
### 2. Systematic Review by Vulnerability Class
Review in priority order — highest-impact classes first:
#### A. Injection (CWE-74, OWASP A03, [OpenCRE 161-451](https://www.opencre.org/cre/161-451))
> ASVS refs: `data/asvs/V12.1.md` (Input Validation), `data/asvs/V13.1.md` (Output Encoding), `data/asvs/V5.3.md` (File Storage)
| Subtype | What to Look For |
|---------|-----------------|
| SQL Injection | String concatenation in queries, missing parameterization, ORM raw queries |
| Command Injection | User input in exec/spawn/system calls, unsanitized shell arguments |
| XSS | User input rendered without output encoding, unsafe DOM manipulation, unescaped template output |
| SSTI | User input in template strings that get evaluated server-side |
| LDAP Injection | User input in LDAP filters without escaping |
| Path Traversal | User input in file paths without canonicalization, `../` not blocked |
| Header Injection | User input in HTTP headers (CRLF injection) |
| Log Injection | User input written to logs without sanitization |
#### B. Authentication & Session (CWE-287, OWASP A07, [OpenCRE 633-428](https://www.opencre.org/cre/633-428))
> ASVS refs: `data/asvs/V2.1.md`–`V2.4.md` (Authentication), `data/asvs/V3.1.md`–`V3.7.md` (Session Management)
- Hardcoded credentials or API keys
- Missing authentication on endpoints
- Weak password requirements
- Session tokens in URLs or logs
- Missing session invalidation on logout/password change
- JWT issues: none algorithm, missing expiry, weak signing key, secrets in payload
- Missing MFA enforcement for sensitive operations
#### C. Authorization (CWE-862, OWASP A01, [OpenCRE 724-770](https://www.opencre.org/cre/724-770))
> ASVS refs: `data/asvs/V4.1.md`–`V4.4.md` (Access Control)
- Missing authorization checks on endpoints or functions
- IDOR: object references without ownership validation
- Horizontal privilege escalation (accessing other users' data)
- Vertical privilege escalation (accessing admin functions)
- Missing RBAC/ABAC enforcement
- Direct database queries that don't filter by user/tenant
#### D. Cryptography (CWE-327, OWASP A02, [OpenCRE 278-646](https://www.opencre.org/cre/278-646))
> ASVS refs: `data/asvs/V6.1.md`–`V6.8.md` (Cryptography)
- Weak algorithms: MD5, SHA1 for passwords, DES, RC4
- ECB mode usage
- Hardcoded encryption keys or IVs
- Missing encryption at rest for sensitive data
- Missing TLS enforcement
- Custom crypto implementations (don't roll your own)
- Insufficient key lengths (RSA < 2048, AES < 128)
#### E. Data Exposure (CWE-200, OWASP A01, [OpenCRE 126-668](https://www.opencre.org/cre/126-668))
> ASVS refs: `data/asvs/V8.1.md`–`V8.4.md` (Data Protection), `data/asvs/V7.1.md`–`V7.6.md` (Error Handling & Logging)
- Sensitive data in error messages or stack traces
- Verbose logging of requests/responses containing PII
- Credentials or tokens in source code, configs, or URLs
- Missing response headers (X-Content-Type-Options, etc.)
- API responses including more fields than necessary
- Debug mode enabled in production configs
#### F. Security Misconfiguration (OWASP A05, [OpenCRE 233-748](https://www.opencre.org/cre/233-748))
> ASVS refs: `data/asvs/V10.1.md`–`V10.7.md` (Configuration)
- Default credentials or configurations
- Unnecessary features enabled (debug endpoints, admin panels)
- Missing security headers
- Overly permissive CORS
- Directory listing enabled
- Missing rate limiting on sensitive endpoints
#### G. Deserialization & Data Integrity (CWE-502, OWASP A08, [OpenCRE 854-643](https://www.opencre.org/cre/854-643))
> ASVS refs: `data/asvs/V11.1.md`–`V11.7.md` (Business Logic)
- Deserializing untrusted data (unsafe deserialization in any language — Python, Java, PHP, Ruby, .NET)
- Missing integrity checks on data from untrusted sources
- Unsigned cookies or tokens
- Missing CSRF protection on state-changing operations
### 3. Framework-Specific Checks
Apply checks specific to the detected framework:
| Framework | Key Checks |
|-----------|-----------|
| React/Next.js | XSS via unsafe HTML rendering, SSRF in server-side data fetching, exposed API routes |
| Express/Node | Missing helmet, no rate limiting, prototype pollution, regex DoS |
| Django | Raw SQL, CSRF exemptions, DEBUG=True, SECRET_KEY exposure |
| Flask | Jinja2 autoescape disabled, unsafe session serialization, debug mode |
| Spring | SpEL injection, actuator exposure, mass assignment |
| Rails | Mass assignment, render user input, SQL fragments |
| Go net/http | Missing timeouts, TOCTOU in file operations, integer overflow |
### 4. Diff-Specific Analysis (for PR reviews)
When reviewing a diff rather than a full codebase:
- Focus on changed lines and their immediate context
- Check if security controls in surrounding (unchanged) code are preserved
- Verify that new endpoints have auth/authz matching existing patterns
- Check if new dependencies introduce vulnerabilities (cross-reference with sca-audit)
- Look for removed security controls (deleted validation, removed auth checks)
### 5. Produce Findings
For each issue:
- Cite the specific code location (file:line)
- Show the vulnerable code snippet
- Explain the attack scenario concretely
- Provide a fixed code snippet
- Rate confidence (HIGH if confirmed path, MEDIUM if contextual, LOW if heuristic)
## Output Format
```markdown
## Security Code Review: [Target]
### Scope
- **Files reviewed**: [count or list]
- **Language/Framework**: [detected]
- **Review type**: Full | PR diff | Targeted
### Findings
[Standard finding template for each issue, sorted by severity]
### Positive Observations
[Security controls that ARE in place — acknowledge good practices]
### Summary
| Severity | Count |
|----------|-------|
| CRITICAL | N |
| HIGH | N |
| MEDIUM | N |
| LOW | N |
| INFO | N |
```
## Tools & Resources
### Static Analysis Tools
- **Semgrep** — Multi-language pattern-based SAST; highly customizable rules
- **CodeQL (GitHub)** — Query-based code analysis for Java, C++, C#, Go, Python, TypeScript, JavaScript, Ruby
- **SonarQube** — Code quality and security scanning with OWASP Top 10 mappings
- **Checkmarx/CxSAST** — Enterprise SAST with custom rule authoring
- **Snyk Code** — Developer-first SAST integrated into IDEs and CI/CD
### Language-Specific
- **Bandit** (Python) — Finds common security issues in Python code
- **Brakeman** (Ruby) — Scans Rails apps for OWASP risks
- **go-vuln-check** (Go) — Detects known vulnerabilities in Go code
- **ShiftLeft/Taint** (Java, Python, Go) — Data flow analysis for injection detection
### Code Review Checkers
- **OWASP Cheat Sheet Series** — Per-vulnerability quick guides and remediation
- **CWE Top 25** — Prioritized list of most dangerous weakness patterns
- **ASVS Interactive** — Maps review items to ASVS verification levels (L1/L2/L3)
## References
- OWASP Top 10 (2021): A01-A10
- OWASP ASVS v5.0 (for verification-level mapping)
- OWASP Code Review Guide
- OWASP Cheat Sheet Series (per-topic)
- OWASP Proactive Controls
- [OpenCRE](https://www.opencre.org) — Cross-standard requirement mappings (CWE, ASVS, WSTG, NIST 800-53, ISO 27001)
- [CWE](https://cwe.mitre.org) v4.19 — Common Weakness Enumeration
- ASVS 5.0 reference data in `data/asvs/` — sourced from [OWASP Agent Skills Project](https://github.com/eoftedal/owasp-agent-skills-project)
@@ -0,0 +1,48 @@
# Finding Template
Use this structure for all security findings produced by skills.
```markdown
### [SEVERITY] Title
- **ID**: NDC-YYYY-NNN (auto-incrementing)
- **CWE**: CWE-XXX (if applicable)
- **CVE**: CVE-YYYY-NNNNN (if applicable)
- **OpenCRE**: [CRE-ID](https://www.opencre.org/cre/CRE-ID) — requirement name (see data/opencre/)
- **OWASP Ref**: Top 10 A01, ASVS V4.1.1, MASVS-STORAGE-1, MASWE-0001, MASTG-TEST-0200, LLM01, etc.
- **Location**: file_path:line_number or component name
- **Impact**: What an attacker can achieve (1-2 sentences)
- **Evidence**: Code snippet, command output, or proof-of-concept
- **Remediation**: Specific fix with code example
- **Confidence**: HIGH | MEDIUM | LOW (how certain is this finding)
```
### Resolving OpenCRE Links
When you have a CWE, look up its OpenCRE mapping via the API:
```
GET https://www.opencre.org/rest/v1/standard/CWE/sectionid/{cwe-number}
```
This returns the CRE ID and linked standards (ASVS, WSTG, NIST 800-53, cheat sheets). Include the CRE link in findings to give readers one-click access to all related standards and remediation guidance.
Common mappings are pre-populated in `data/opencre/README.md`.
## Severity Definitions
| Severity | CVSS Range | Criteria |
|----------|-----------|----------|
| CRITICAL | 9.0-10.0 | Remote code execution, full system compromise, mass data breach |
| HIGH | 7.0-8.9 | Privilege escalation, significant data exposure, auth bypass |
| MEDIUM | 4.0-6.9 | Limited data exposure, requires user interaction or specific conditions |
| LOW | 0.1-3.9 | Information disclosure, minor misconfigurations |
| INFORMATIONAL | N/A | Best practice recommendations, defense-in-depth suggestions |
## Confidence Levels
| Level | Meaning |
|-------|---------|
| HIGH | Confirmed via code path analysis, PoC, or tool output |
| MEDIUM | Strong indicators but not fully confirmed — needs manual verification |
| LOW | Heuristic match or pattern-based — may be false positive |
@@ -0,0 +1,345 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/UnitOneAI/SecuritySkills/schemas/finding.schema.json",
"title": "SecuritySkills Normalized Finding Output",
"description": "Machine-readable envelope for normalized security findings and remediation recommendations emitted by SecuritySkills workflows. This contract is independent of SARIF and may be mapped to downstream enterprise formats later.",
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "run", "skill", "findings"],
"properties": {
"schema_version": {
"const": "1.0.0",
"description": "Version of this normalized SecuritySkills finding envelope."
},
"run": {
"$ref": "#/$defs/run",
"description": "Metadata for the analysis run that produced this output."
},
"skill": {
"$ref": "#/$defs/skill",
"description": "Metadata for the SecuritySkills entrypoint that produced this output."
},
"findings": {
"type": "array",
"items": {
"$ref": "#/$defs/finding"
},
"description": "Normalized findings produced by a skill run."
}
},
"$defs": {
"riskLevel": {
"type": "string",
"enum": ["low", "medium", "high"]
},
"nonEmptyString": {
"type": "string",
"minLength": 1
},
"uriString": {
"type": "string",
"format": "uri"
},
"run": {
"type": "object",
"additionalProperties": false,
"required": ["id", "timestamp"],
"properties": {
"id": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable run identifier supplied by the agent, CI job, or enterprise orchestrator."
},
"timestamp": {
"$ref": "#/$defs/nonEmptyString",
"description": "ISO 8601 timestamp for when the run output was produced."
},
"tool": {
"$ref": "#/$defs/nonEmptyString",
"description": "Agent, CLI, scanner, or workflow that executed the skill."
},
"target": {
"$ref": "#/$defs/nonEmptyString",
"description": "Repository, project, service, artifact, environment, or other target reviewed."
},
"source_ref": {
"$ref": "#/$defs/nonEmptyString",
"description": "Optional commit SHA, branch, image digest, build ID, ticket ID, or evidence package reference."
}
}
},
"skill": {
"type": "object",
"additionalProperties": false,
"required": ["name", "version"],
"properties": {
"name": {
"$ref": "#/$defs/nonEmptyString",
"description": "SecuritySkills skill name from SKILL.md frontmatter."
},
"version": {
"$ref": "#/$defs/nonEmptyString",
"description": "SecuritySkills skill version from SKILL.md frontmatter."
},
"path": {
"$ref": "#/$defs/nonEmptyString",
"description": "Path to the SKILL.md entrypoint used for the run."
},
"frameworks": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/nonEmptyString"
},
"description": "Framework identifiers declared by the skill frontmatter."
}
}
},
"finding": {
"type": "object",
"additionalProperties": false,
"required": ["id", "title", "severity", "status", "evidence", "remediations"],
"properties": {
"id": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable finding identifier within the output."
},
"fingerprint": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable deduplication key based on finding type, affected asset, and evidence location."
},
"title": {
"$ref": "#/$defs/nonEmptyString"
},
"description": {
"$ref": "#/$defs/nonEmptyString",
"description": "What the issue is and why it matters."
},
"severity": {
"type": "string",
"enum": ["info", "low", "medium", "high", "critical"]
},
"status": {
"type": "string",
"enum": ["open", "mitigated", "accepted_risk", "false_positive"]
},
"cwe": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^CWE-[0-9]+$"
},
"description": "Optional CWE mappings, when applicable."
},
"framework_refs": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/frameworkRef"
},
"description": "Framework/control references from the skill frontmatter frameworks."
},
"references": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/reference"
},
"description": "Optional advisory, standard, vendor, or knowledge-base references."
},
"evidence": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["location", "summary"],
"properties": {
"location": {
"$ref": "#/$defs/nonEmptyString",
"description": "File path, line range, asset ID, log source, policy path, or other concrete evidence location."
},
"summary": {
"$ref": "#/$defs/nonEmptyString"
},
"artifact_type": {
"type": "string",
"enum": ["source", "config", "policy", "log", "scan_result", "cloud_resource", "identity", "network", "document", "other"]
},
"snippet": {
"$ref": "#/$defs/nonEmptyString",
"description": "Minimal redacted snippet or observation needed to support the finding."
},
"redacted": {
"type": "boolean",
"description": "True when sensitive values were intentionally removed from this evidence."
}
}
}
},
"remediations": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/remediation"
},
"description": "Every fix recommendation for this finding. Each item must include remediation guidance, confidence, blast radius, behavior-change risk, and test strategy."
}
},
"anyOf": [
{
"required": ["cwe"]
},
{
"required": ["framework_refs"]
}
]
},
"frameworkRef": {
"type": "object",
"additionalProperties": false,
"required": ["framework", "control"],
"properties": {
"framework": {
"$ref": "#/$defs/nonEmptyString"
},
"control": {
"$ref": "#/$defs/nonEmptyString"
},
"name": {
"$ref": "#/$defs/nonEmptyString"
}
}
},
"reference": {
"type": "object",
"additionalProperties": false,
"required": ["type", "id"],
"properties": {
"type": {
"type": "string",
"enum": ["cve", "cwe", "framework", "advisory", "vendor", "documentation", "other"]
},
"id": {
"$ref": "#/$defs/nonEmptyString"
},
"url": {
"$ref": "#/$defs/uriString"
}
}
},
"remediation": {
"type": "object",
"additionalProperties": false,
"required": ["guidance", "confidence", "blast_radius", "behavior_change_risk", "test_strategy"],
"properties": {
"guidance": {
"$ref": "#/$defs/nonEmptyString",
"description": "Concrete remediation steps or patch guidance for the finding."
},
"confidence": {
"$ref": "#/$defs/riskLevel",
"description": "How confident the skill is that this recommendation is correct for the observed evidence."
},
"blast_radius": {
"$ref": "#/$defs/nonEmptyString",
"description": "Expected scope of systems, files, users, integrations, data, or workflows affected by the change."
},
"behavior_change_risk": {
"$ref": "#/$defs/riskLevel",
"description": "Risk that the remediation changes intended application or operational behavior."
},
"test_strategy": {
"$ref": "#/$defs/testStrategy",
"description": "Required validation strategy proving the remediation fixes the finding. Include recommended tests, generated tests, or both."
}
}
},
"testStrategy": {
"type": "object",
"additionalProperties": false,
"required": ["summary"],
"properties": {
"summary": {
"$ref": "#/$defs/nonEmptyString",
"description": "Concise explanation of what proves the remediation fixed the issue."
},
"recommended_tests": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/recommendedTest"
},
"description": "Tests the user or agent should run when tests are not generated directly."
},
"generated_tests": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/generatedTest"
},
"description": "Test files or cases produced as part of the remediation."
}
},
"anyOf": [
{
"required": ["recommended_tests"]
},
{
"required": ["generated_tests"]
}
]
},
"recommendedTest": {
"type": "object",
"additionalProperties": false,
"required": ["name", "type", "purpose", "command", "expected_result"],
"properties": {
"name": {
"$ref": "#/$defs/nonEmptyString"
},
"type": {
"type": "string",
"enum": ["static", "unit", "integration", "e2e", "regression", "manual"]
},
"purpose": {
"$ref": "#/$defs/nonEmptyString",
"description": "Behavior, vulnerability condition, or regression this test proves."
},
"command": {
"$ref": "#/$defs/nonEmptyString",
"description": "Command or manual check to execute for this test."
},
"expected_result": {
"$ref": "#/$defs/nonEmptyString"
}
}
},
"generatedTest": {
"type": "object",
"additionalProperties": false,
"required": ["path", "type", "purpose", "command", "expected_result"],
"properties": {
"path": {
"$ref": "#/$defs/nonEmptyString",
"description": "Path to the generated or modified test file."
},
"type": {
"type": "string",
"enum": ["static", "unit", "integration", "e2e", "regression"]
},
"purpose": {
"$ref": "#/$defs/nonEmptyString",
"description": "Behavior, vulnerability condition, or regression this generated test proves."
},
"command": {
"$ref": "#/$defs/nonEmptyString",
"description": "Command that runs the generated test."
},
"expected_result": {
"$ref": "#/$defs/nonEmptyString"
}
}
}
}
}
@@ -0,0 +1,111 @@
# Security Fixer Policy
This policy classifies security findings by how an agent may remediate them. Fixer-capable skills must use this policy before changing files, generating patches, or recommending an automated remediation path.
## Categories
### Auto-fix
The agent may apply the fix directly when the finding is high-confidence, the change is narrow, and the expected behavior is mechanically verifiable.
Criteria:
- The vulnerable pattern and target file are unambiguous.
- The fix is deterministic and follows an existing project convention or a well-known safe default.
- The change has low blast radius and does not alter public APIs, authorization semantics, data models, deployment topology, or runtime trust boundaries.
- The agent can run or define a concrete verification step.
Examples:
- Add missing security headers in a local framework configuration using the project's existing middleware pattern.
- Replace string-built SQL with parameter binding when the query shape and parameters are clear.
- Pin a container image tag or GitHub Action version when the intended version is known from lock files, release metadata, or existing repository conventions.
- Add a `.dockerignore` or `.gitignore` entry for `.env` files without removing or exposing secret values.
### Assisted-fix
The agent may prepare a patch or exact commands, but the user or repository owner must confirm context, run environment-specific checks, or choose among valid alternatives before merge.
Criteria:
- The finding is valid, but the best remediation depends on application behavior, deployment constraints, ownership boundaries, or compatibility requirements.
- Multiple safe remediation options exist.
- The change is moderate in scope or requires coordinated validation outside the local workspace.
- The agent can reduce the work to a reviewable patch, migration plan, configuration diff, or decision list.
Examples:
- Add authorization middleware to an endpoint when the correct role or ownership predicate needs product confirmation.
- Upgrade a vulnerable dependency across a major version boundary.
- Tighten CI permissions where release, package, or deployment jobs may need specific write scopes.
- Add Kubernetes `NetworkPolicy` rules where service communication requirements must be confirmed.
### Guidance-only
The agent must not modify files. It should explain the finding, risk, and recommended remediation path.
Criteria:
- The remediation requires organizational policy, architecture changes, vendor configuration, legal review, procurement, or manual operational work.
- The agent lacks access to the system that must be changed.
- The change cannot be represented safely as a local patch.
Examples:
- Adopt a centralized secrets manager across teams.
- Establish a vulnerability management SLA.
- Change cloud account guardrails, identity provider policy, or production firewall rules outside the repository.
- Resolve license obligations for GPL, AGPL, commercial, unknown, or no-license dependencies.
### Human-review-required
The agent must stop short of applying a fix and explicitly request human review before remediation proceeds.
Criteria:
- A hard gate below applies.
- The finding involves sensitive credentials, production access, destructive operations, legal/compliance interpretation, or security-critical logic.
- The agent cannot confidently preserve intended behavior.
- The evidence is incomplete or the finding may be a false positive with material operational impact.
Examples:
- Rotate leaked credentials or revoke certificates.
- Change authentication, authorization, cryptography, payment, medical, safety, or tenant-isolation logic.
- Modify production deployment, incident response, or containment procedures.
- Apply a remediation that deletes data, removes audit evidence, weakens controls, or accepts risk.
## Decision Criteria
Classify each finding using the most restrictive category that applies.
1. Confirm the finding is in scope for the skill and supported by concrete evidence.
2. Determine whether any hard gate forces human review.
3. Estimate blast radius: local config or code path, cross-cutting application behavior, infrastructure, production operations, or organizational policy.
4. Check remediation confidence: deterministic patch, multiple valid options, missing context, or uncertain behavior.
5. Check verification: automated test or scan, manual validation, external approval, or no reliable verification available.
6. Choose the category:
- Use auto-fix only when evidence, scope, remediation, and verification are all strong.
- Use assisted-fix when a patch is useful but context or approval is required.
- Use guidance-only when local code changes are not the right remediation vehicle.
- Use human-review-required whenever a hard gate applies or safe behavior preservation is uncertain.
## Hard Gates for Human Review
Any of these conditions forces `human-review-required`:
- Secret exposure requiring credential rotation, revocation, certificate replacement, or git history rewriting.
- Authentication, authorization, session management, cryptographic, payment, tenant isolation, or safety-critical logic changes.
- Production infrastructure, network, identity, IAM, deployment, incident response, or data retention changes.
- Destructive or irreversible actions, including deleting data, rewriting history, disabling audit logs, removing evidence, or changing backups.
- Legal, compliance, privacy, or license-risk decisions.
- Changes requiring owner-specific business rules, threat model assumptions, regulatory interpretation, or risk acceptance.
- Unclear ownership, missing tests for a high-impact path, conflicting framework guidance, or evidence that the finding may be a false positive.
- Any remediation that would weaken an existing security control to make a tool pass.
## Fixer Workflow Review Gates
Fixer-capable workflows must pass these gates before any applied patch is considered ready for handoff:
1. **Scope gate:** State the files, settings, and behaviors that are in scope; avoid unrelated refactors, formatting churn, dependency updates, or opportunistic cleanup.
2. **Approval gate:** Request explicit approval before assisted-fix or human-review-required work proceeds, and before any change that affects hard-gated areas even when a patch can be drafted.
3. **Review gate:** Provide reviewer evidence that includes the finding, policy category, changed files, behavior-change risk, verification performed or still required, and any assumptions the reviewer must confirm.
4. **Rollback gate:** Provide rollback guidance for every proposed or applied change, including the exact revert path when local patches are used or the operational rollback owner when the change cannot be reverted locally.
Applied fixes must be isolated to the smallest viable patch. If the agent discovers unrelated defects while fixing, it should report them separately instead of expanding the patch. If rollback is unclear, expensive, or depends on production state, classify the remediation as `human-review-required`.
## Skill Usage
Fixer-capable skills must reference this policy when producing remediation guidance or patches. Their workflows must include the review gates above and must not apply changes until the selected category allows it. The policy classifies the remediation path only; it does not change finding schemas or require new output fields.
@@ -0,0 +1,158 @@
# Normalized JSON Output Contract
SecuritySkills can emit machine-readable findings as a normalized JSON envelope
that validates against [`schemas/finding.schema.json`](../schemas/finding.schema.json).
This contract is independent of SARIF. Downstream systems may map it to SARIF,
ticketing systems, GRC platforms, dashboards, or vulnerability stores without
changing individual skill output rules.
See [`docs/sarif-output.md`](sarif-output.md) for the repo-level SARIF 2.1.0
export mapping.
## Envelope
Every JSON response uses this top-level shape:
```json
{
"schema_version": "1.0.0",
"run": {
"id": "run-2026-06-16T12:00:00Z",
"timestamp": "2026-06-16T12:00:00Z",
"tool": "codex",
"target": "github.com/example/service",
"source_ref": "commit-or-build-id"
},
"skill": {
"name": "secure-code-review",
"version": "1.0.0",
"path": "skills/appsec/secure-code-review/SKILL.md",
"frameworks": ["OWASP-ASVS-4.0.3", "CWE"]
},
"findings": []
}
```
- `schema_version` is fixed at `1.0.0` until a breaking contract change is
required.
- `run.id` is the deduplication boundary for one execution. Use an orchestrator
ID, CI job ID, or generated run ID.
- `run.timestamp` should be an ISO 8601 timestamp.
- `run.target` identifies the reviewed repository, project, service, artifact,
environment, or evidence package.
- `skill.name`, `skill.version`, and `skill.frameworks` come from the skill's
`SKILL.md` frontmatter.
## Findings
Each finding must include:
- `id`: stable finding ID within the run.
- `title`: concise finding title.
- `severity`: one of `info`, `low`, `medium`, `high`, or `critical`.
- `status`: one of `open`, `mitigated`, `accepted_risk`, or `false_positive`.
- `evidence`: one or more concrete evidence entries.
- `remediations`: one or more remediation recommendations, each with a test
strategy.
Each finding must include at least one framework/CWE mapping:
- `cwe`: array of CWE IDs such as `CWE-89`, when applicable.
- `framework_refs`: array of framework/control references from the skill's
declared frameworks.
Optional fields such as `fingerprint`, `description`, and `references` support
enterprise deduplication, analyst context, and external advisory linking.
## Evidence
Evidence entries must identify where the issue was observed and summarize the
observation. Locations may be source paths, line ranges, cloud resource IDs, log
sources, policy paths, scanner result identifiers, or evidence package records.
Use `snippet` only for the minimal redacted text needed to prove the finding.
Set `redacted: true` when secrets, tokens, personal data, internal hostnames, or
other sensitive values were removed.
## Remediation And Tests
Each remediation item must include:
- `guidance`: concrete remediation steps or patch guidance.
- `confidence`: `low`, `medium`, or `high`.
- `blast_radius`: expected affected files, systems, users, integrations, data,
or workflows.
- `behavior_change_risk`: `low`, `medium`, or `high`.
- `test_strategy`: validation that proves the issue is fixed.
`test_strategy` must include a `summary` and at least one of
`recommended_tests` or `generated_tests`. See
[`docs/remediation-output.md`](remediation-output.md) for remediation-specific
field guidance.
## Minimal Example
```json
{
"schema_version": "1.0.0",
"run": {
"id": "run-001",
"timestamp": "2026-06-16T12:00:00Z",
"tool": "codex",
"target": "payments-api",
"source_ref": "abc1234"
},
"skill": {
"name": "api-security",
"version": "1.0.0",
"path": "skills/appsec/api-security/SKILL.md",
"frameworks": ["OWASP-API-Top-10-2023", "CWE"]
},
"findings": [
{
"id": "API-SEC-001",
"fingerprint": "api-security:users-delete:missing-admin-auth",
"title": "Administrative endpoint lacks authorization check",
"description": "The delete-user route accepts authenticated requests without verifying administrative privileges.",
"severity": "high",
"status": "open",
"cwe": ["CWE-862"],
"framework_refs": [
{
"framework": "OWASP-API-Top-10-2023",
"control": "API5:2023",
"name": "Broken Function Level Authorization"
}
],
"evidence": [
{
"location": "routes/users.js:42",
"artifact_type": "source",
"summary": "DELETE /users/:id checks authentication but not administrator role.",
"snippet": "router.delete('/users/:id', requireAuth, deleteUser)",
"redacted": false
}
],
"remediations": [
{
"guidance": "Require an administrator role check before invoking deleteUser.",
"confidence": "high",
"blast_radius": "User administration routes only.",
"behavior_change_risk": "medium",
"test_strategy": {
"summary": "Proves non-admin users cannot delete accounts while admins still can.",
"recommended_tests": [
{
"name": "Reject non-admin delete",
"type": "integration",
"purpose": "Confirms the vulnerable authorization bypass no longer succeeds.",
"command": "npm test -- users-authz.test.js",
"expected_result": "Non-admin DELETE /users/:id returns 403 and admin DELETE succeeds."
}
]
}
}
]
}
]
}
```
@@ -0,0 +1,229 @@
# SARIF Output Mapping
SecuritySkills may emit SARIF-compatible JSON for tools that ingest Static
Analysis Results Interchange Format (SARIF) 2.1.0. SARIF output is an export
view of the normalized finding envelope documented in
[`docs/normalized-json-output.md`](normalized-json-output.md); it does not
replace the normalized JSON contract or change the required finding fields.
## Top-Level Shape
Use SARIF version `2.1.0` with the standard schema URI:
```json
{
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "SecuritySkills",
"semanticVersion": "1.0.0",
"rules": []
}
},
"results": []
}
]
}
```
Use one `run` per normalized envelope. `run.tool.driver.name` should identify
SecuritySkills or the executing agent. `run.tool.driver.semanticVersion` should
use the skill version when a single skill produced the run.
## Mapping
Map normalized fields to SARIF as follows:
| Normalized field | SARIF field |
|---|---|
| `run.id`, `run.timestamp`, `run.target`, `run.source_ref` | `runs[].properties.securityskills.run` |
| `skill.name`, `skill.version`, `skill.path`, `skill.frameworks` | `runs[].tool.driver.name`, `runs[].tool.driver.semanticVersion`, `runs[].properties.securityskills.skill` |
| `finding.id` | `results[].ruleId` and `results[].properties.securityskills.finding_id` |
| `finding.fingerprint` | `results[].partialFingerprints.securityskillsFingerprint` |
| `finding.title` | `tool.driver.rules[].shortDescription.text` |
| `finding.description` | `tool.driver.rules[].fullDescription.text` and `results[].message.text` |
| `finding.severity` | `results[].level` |
| `finding.status` | `results[].properties.securityskills.status` |
| `finding.cwe` | `tool.driver.rules[].relationships` when supported, and `properties.securityskills.cwe` |
| `finding.framework_refs` | `tool.driver.rules[].properties.securityskills.framework_refs` |
| `finding.evidence` | `results[].locations` plus `properties.securityskills.evidence` |
| `finding.references` | `tool.driver.rules[].helpUri` or `tool.driver.rules[].properties.securityskills.references` |
| `finding.remediations` | `tool.driver.rules[].help.text` and `properties.securityskills.remediations`, including each remediation's `test_strategy` |
## Severity
SARIF `level` has fewer values than the normalized contract. Use this mapping:
| Normalized severity | SARIF level |
|---|---|
| `critical` | `error` |
| `high` | `error` |
| `medium` | `warning` |
| `low` | `note` |
| `info` | `note` |
Keep the original severity in
`results[].properties.securityskills.severity` so downstream systems can
preserve the distinction between `critical` and `high`.
## Locations
For source, configuration, policy, or scan-result evidence with file locations,
populate `results[].locations[].physicalLocation`:
```json
{
"physicalLocation": {
"artifactLocation": {
"uri": "routes/users.js"
},
"region": {
"startLine": 42
}
},
"message": {
"text": "DELETE /users/:id checks authentication but not administrator role."
}
}
```
If the normalized evidence location does not contain a parseable file path and
line number, still emit a SARIF result and store the original location under
`properties.securityskills.evidence`. For cloud resources, identities, network
assets, logs, or documents, use the best stable asset identifier as
`artifactLocation.uri` only when it is meaningful to the SARIF consumer.
## Rules
Create one `tool.driver.rules[]` entry per distinct `ruleId`. A rule should
include:
- `id`: the normalized `finding.id`, or a stable detector ID when multiple
findings share the same detection rule.
- `shortDescription.text`: the finding title or detector title.
- `fullDescription.text`: the finding description.
- `help.text`: remediation guidance and test strategy summary.
- `properties.securityskills`: CWE IDs, framework references, normalized
severity, and any remediation metadata that does not fit native SARIF fields.
Do not invent CWE, framework, or control identifiers for SARIF. Reuse only the
values already present in the normalized finding.
## Minimal Example
```json
{
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "api-security",
"semanticVersion": "1.0.0",
"rules": [
{
"id": "API-SEC-001",
"shortDescription": {
"text": "Administrative endpoint lacks authorization check"
},
"fullDescription": {
"text": "The delete-user route accepts authenticated requests without verifying administrative privileges."
},
"help": {
"text": "Require an administrator role check before invoking deleteUser. Validate with integration tests for non-admin and admin delete flows."
},
"properties": {
"securityskills": {
"severity": "high",
"cwe": ["CWE-862"],
"framework_refs": [
{
"framework": "OWASP-API-Top-10-2023",
"control": "API5:2023",
"name": "Broken Function Level Authorization"
}
]
}
}
}
]
}
},
"results": [
{
"ruleId": "API-SEC-001",
"level": "error",
"message": {
"text": "Administrative endpoint lacks authorization check"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "routes/users.js"
},
"region": {
"startLine": 42
}
},
"message": {
"text": "DELETE /users/:id checks authentication but not administrator role."
}
}
],
"partialFingerprints": {
"securityskillsFingerprint": "api-security:users-delete:missing-admin-auth"
},
"properties": {
"securityskills": {
"finding_id": "API-SEC-001",
"severity": "high",
"status": "open",
"remediations": [
{
"guidance": "Require an administrator role check before invoking deleteUser.",
"confidence": "high",
"blast_radius": "User administration routes only.",
"behavior_change_risk": "medium",
"test_strategy": {
"summary": "Proves non-admin users cannot delete accounts while admins still can.",
"recommended_tests": [
{
"name": "Reject non-admin delete",
"type": "integration",
"purpose": "Confirms the authorization bypass no longer succeeds.",
"command": "npm test -- users-authz.test.js",
"expected_result": "Non-admin DELETE returns 403 and admin DELETE succeeds."
}
]
}
}
]
}
}
}
],
"properties": {
"securityskills": {
"run": {
"id": "run-001",
"timestamp": "2026-06-16T12:00:00Z",
"target": "payments-api",
"source_ref": "abc1234"
},
"skill": {
"name": "api-security",
"version": "1.0.0",
"path": "skills/appsec/api-security/SKILL.md",
"frameworks": ["OWASP-API-Top-10-2023", "CWE"]
}
}
}
}
]
}
```
@@ -0,0 +1,345 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/UnitOneAI/SecuritySkills/schemas/finding.schema.json",
"title": "SecuritySkills Normalized Finding Output",
"description": "Machine-readable envelope for normalized security findings and remediation recommendations emitted by SecuritySkills workflows. This contract is independent of SARIF and may be mapped to downstream enterprise formats later.",
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "run", "skill", "findings"],
"properties": {
"schema_version": {
"const": "1.0.0",
"description": "Version of this normalized SecuritySkills finding envelope."
},
"run": {
"$ref": "#/$defs/run",
"description": "Metadata for the analysis run that produced this output."
},
"skill": {
"$ref": "#/$defs/skill",
"description": "Metadata for the SecuritySkills entrypoint that produced this output."
},
"findings": {
"type": "array",
"items": {
"$ref": "#/$defs/finding"
},
"description": "Normalized findings produced by a skill run."
}
},
"$defs": {
"riskLevel": {
"type": "string",
"enum": ["low", "medium", "high"]
},
"nonEmptyString": {
"type": "string",
"minLength": 1
},
"uriString": {
"type": "string",
"format": "uri"
},
"run": {
"type": "object",
"additionalProperties": false,
"required": ["id", "timestamp"],
"properties": {
"id": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable run identifier supplied by the agent, CI job, or enterprise orchestrator."
},
"timestamp": {
"$ref": "#/$defs/nonEmptyString",
"description": "ISO 8601 timestamp for when the run output was produced."
},
"tool": {
"$ref": "#/$defs/nonEmptyString",
"description": "Agent, CLI, scanner, or workflow that executed the skill."
},
"target": {
"$ref": "#/$defs/nonEmptyString",
"description": "Repository, project, service, artifact, environment, or other target reviewed."
},
"source_ref": {
"$ref": "#/$defs/nonEmptyString",
"description": "Optional commit SHA, branch, image digest, build ID, ticket ID, or evidence package reference."
}
}
},
"skill": {
"type": "object",
"additionalProperties": false,
"required": ["name", "version"],
"properties": {
"name": {
"$ref": "#/$defs/nonEmptyString",
"description": "SecuritySkills skill name from SKILL.md frontmatter."
},
"version": {
"$ref": "#/$defs/nonEmptyString",
"description": "SecuritySkills skill version from SKILL.md frontmatter."
},
"path": {
"$ref": "#/$defs/nonEmptyString",
"description": "Path to the SKILL.md entrypoint used for the run."
},
"frameworks": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/nonEmptyString"
},
"description": "Framework identifiers declared by the skill frontmatter."
}
}
},
"finding": {
"type": "object",
"additionalProperties": false,
"required": ["id", "title", "severity", "status", "evidence", "remediations"],
"properties": {
"id": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable finding identifier within the output."
},
"fingerprint": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable deduplication key based on finding type, affected asset, and evidence location."
},
"title": {
"$ref": "#/$defs/nonEmptyString"
},
"description": {
"$ref": "#/$defs/nonEmptyString",
"description": "What the issue is and why it matters."
},
"severity": {
"type": "string",
"enum": ["info", "low", "medium", "high", "critical"]
},
"status": {
"type": "string",
"enum": ["open", "mitigated", "accepted_risk", "false_positive"]
},
"cwe": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^CWE-[0-9]+$"
},
"description": "Optional CWE mappings, when applicable."
},
"framework_refs": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/frameworkRef"
},
"description": "Framework/control references from the skill frontmatter frameworks."
},
"references": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/reference"
},
"description": "Optional advisory, standard, vendor, or knowledge-base references."
},
"evidence": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["location", "summary"],
"properties": {
"location": {
"$ref": "#/$defs/nonEmptyString",
"description": "File path, line range, asset ID, log source, policy path, or other concrete evidence location."
},
"summary": {
"$ref": "#/$defs/nonEmptyString"
},
"artifact_type": {
"type": "string",
"enum": ["source", "config", "policy", "log", "scan_result", "cloud_resource", "identity", "network", "document", "other"]
},
"snippet": {
"$ref": "#/$defs/nonEmptyString",
"description": "Minimal redacted snippet or observation needed to support the finding."
},
"redacted": {
"type": "boolean",
"description": "True when sensitive values were intentionally removed from this evidence."
}
}
}
},
"remediations": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/remediation"
},
"description": "Every fix recommendation for this finding. Each item must include remediation guidance, confidence, blast radius, behavior-change risk, and test strategy."
}
},
"anyOf": [
{
"required": ["cwe"]
},
{
"required": ["framework_refs"]
}
]
},
"frameworkRef": {
"type": "object",
"additionalProperties": false,
"required": ["framework", "control"],
"properties": {
"framework": {
"$ref": "#/$defs/nonEmptyString"
},
"control": {
"$ref": "#/$defs/nonEmptyString"
},
"name": {
"$ref": "#/$defs/nonEmptyString"
}
}
},
"reference": {
"type": "object",
"additionalProperties": false,
"required": ["type", "id"],
"properties": {
"type": {
"type": "string",
"enum": ["cve", "cwe", "framework", "advisory", "vendor", "documentation", "other"]
},
"id": {
"$ref": "#/$defs/nonEmptyString"
},
"url": {
"$ref": "#/$defs/uriString"
}
}
},
"remediation": {
"type": "object",
"additionalProperties": false,
"required": ["guidance", "confidence", "blast_radius", "behavior_change_risk", "test_strategy"],
"properties": {
"guidance": {
"$ref": "#/$defs/nonEmptyString",
"description": "Concrete remediation steps or patch guidance for the finding."
},
"confidence": {
"$ref": "#/$defs/riskLevel",
"description": "How confident the skill is that this recommendation is correct for the observed evidence."
},
"blast_radius": {
"$ref": "#/$defs/nonEmptyString",
"description": "Expected scope of systems, files, users, integrations, data, or workflows affected by the change."
},
"behavior_change_risk": {
"$ref": "#/$defs/riskLevel",
"description": "Risk that the remediation changes intended application or operational behavior."
},
"test_strategy": {
"$ref": "#/$defs/testStrategy",
"description": "Required validation strategy proving the remediation fixes the finding. Include recommended tests, generated tests, or both."
}
}
},
"testStrategy": {
"type": "object",
"additionalProperties": false,
"required": ["summary"],
"properties": {
"summary": {
"$ref": "#/$defs/nonEmptyString",
"description": "Concise explanation of what proves the remediation fixed the issue."
},
"recommended_tests": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/recommendedTest"
},
"description": "Tests the user or agent should run when tests are not generated directly."
},
"generated_tests": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/generatedTest"
},
"description": "Test files or cases produced as part of the remediation."
}
},
"anyOf": [
{
"required": ["recommended_tests"]
},
{
"required": ["generated_tests"]
}
]
},
"recommendedTest": {
"type": "object",
"additionalProperties": false,
"required": ["name", "type", "purpose", "command", "expected_result"],
"properties": {
"name": {
"$ref": "#/$defs/nonEmptyString"
},
"type": {
"type": "string",
"enum": ["static", "unit", "integration", "e2e", "regression", "manual"]
},
"purpose": {
"$ref": "#/$defs/nonEmptyString",
"description": "Behavior, vulnerability condition, or regression this test proves."
},
"command": {
"$ref": "#/$defs/nonEmptyString",
"description": "Command or manual check to execute for this test."
},
"expected_result": {
"$ref": "#/$defs/nonEmptyString"
}
}
},
"generatedTest": {
"type": "object",
"additionalProperties": false,
"required": ["path", "type", "purpose", "command", "expected_result"],
"properties": {
"path": {
"$ref": "#/$defs/nonEmptyString",
"description": "Path to the generated or modified test file."
},
"type": {
"type": "string",
"enum": ["static", "unit", "integration", "e2e", "regression"]
},
"purpose": {
"$ref": "#/$defs/nonEmptyString",
"description": "Behavior, vulnerability condition, or regression this generated test proves."
},
"command": {
"$ref": "#/$defs/nonEmptyString",
"description": "Command that runs the generated test."
},
"expected_result": {
"$ref": "#/$defs/nonEmptyString"
}
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Leonxlnx
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File diff suppressed because it is too large. Load diff
+73
View File
@@ -0,0 +1,73 @@
---
name: dev-router
description: Use no início de qualquer pedido de código (feature, bug, refactor, UI, API, migração, review; "implement", "fix", "build", "add", "change"). Classifica o pedido em nível 0 a 3 e decide quais workflows, agentes e checagens rodar, para um pedido pequeno não pagar o custo de um grande.
license: MIT
metadata:
dev-workflows:
uses: [lean-code, wf-bugfix, wf-refactor, wf-frontend, wf-backend, wf-architecture, wf-security-review, safedeps]
external: []
---
# Dev Router
A primeira linha da resposta declara o nível: `Nível N: <motivo em uma frase>`.
## 1. Classificar
| Nível | Quando | Exemplos |
|---|---|---|
| 0, trivial | nenhum comportamento muda; 1 arquivo | texto, cor, typo, renomear variável local |
| 1, pequeno | comportamento muda em 1 a 3 arquivos, sem superfície pública nova | bug localizado, ajuste de validação, refactor local |
| 2, feature | superfície nova ou contrato alterado; 4+ arquivos; dependência nova | endpoint, tela, módulo, integração |
| 3, grande ou de risco | vários módulos ou serviços, dados existentes, arquitetura, release | migração com dados, troca de auth, novo serviço |
Na dúvida entre dois níveis, escolha o menor e suba quando aparecer um gatilho.
## 2. Gatilhos que sobem o nível a qualquer momento
| Gatilho | Mínimo | Soma |
|---|---|---|
| autenticação, autorização, sessão, tokens, criptografia | 2 | `security-auditor` |
| dinheiro, cobrança, dados pessoais (LGPD) | 2 | `security-auditor` |
| upload, SQL montado à mão, shell/exec, desserialização, template com entrada do usuário | 2 | `security-auditor` |
| dependência nova | 1 | `safedeps` antes de instalar |
| migração de schema | 2 (3 se mexe em dado existente) | rollback testado |
| feature que chama um LLM | 2 | OWASP LLM Top 10 no `security-auditor` |
Depois que um gatilho disparou, não rebaixe por conta própria.
O usuário pode forçar: "modo rápido" vira nível 0 ou 1, mas gatilho de segurança continua valendo (avise); "modo completo" vira nível 3.
## 3. O que cada nível roda
| Nível | Fluxo | Workflow | Agentes |
|---|---|---|---|
| 0 | fazer, rodar o gate | nenhum | nenhum |
| 1 | entender ou reproduzir, mudar, teste de regressão, gate | `wf-bugfix` ou `wf-refactor` | `explorer` só se não souber onde está o código |
| 2 | explorar, plano curto, TDD, revisão independente, gate | `wf-backend` e/ou `wf-frontend`; full-stack começa pelo contrato do backend | `explorer`, `implementer`, `reviewer`; `security-auditor` com gatilho; `ui-critic` com UI |
| 3 | spec EARS com IDs e ADR, aprovação do usuário, tarefas pequenas com TDD, revisões, gate | `wf-architecture` antes; `wf-backend`/`wf-frontend` na execução; `wf-security-review` no fim | `planner`, `implementer`, `reviewer`, `security-auditor`, `ui-critic` com UI, `verifier` |
Em todo nível: aplique `lean-code`. Peça aprovação do usuário só quando houver uma decisão que é dele (produto, custo, dado existente); no nível 3, a spec sempre passa por ele.
Delegue a um agente quando o trabalho dele não precisa voltar inteiro para esta conversa (mapear código, revisar um diff). Tarefa que cabe em poucos passos você mesmo faz.
## 4. Gate de qualidade
Antes de dizer que terminou, rode:
```bash
"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier N
```
- `fail`: corrija. Se não der, explique ao usuário o que falhou e por quê.
- `incomplete`: diga ao usuário quais checagens ficaram "não verificado" (ferramenta ausente). Nunca chame de testado o que não rodou.
- `dependências novas`: justifique cada uma (ver `lean-code`).
O hook de `Stop` bloqueia o encerramento enquanto houver código alterado sem gate atualizado ou com gate falho. Configuração por projeto e lista de checagens: [references/quality-gate.md](references/quality-gate.md).
## 5. Relatório final (nível 1 ou mais)
1. Nível e motivo.
2. O que mudou: arquivos e linhas líquidas (`diff` do gate).
3. Evidência: veredito do gate; checagens ok, falhas e não verificadas.
4. O que ficou de fora ou é risco conhecido.
@@ -0,0 +1,71 @@
# Quality gate: checagens e configuração
`scripts/quality-gate --tier N` roda as checagens do nível N e dos níveis abaixo, só sobre os arquivos
alterados em relação à branch base (merge-base com `origin/HEAD`, `main` ou `master`). O resultado vai
para `.dev-workflows/gate.json` (ignorado pelo git automaticamente) e uma linha resumida vai para
`.dev-workflows/log.jsonl`.
`--list` mostra o que rodaria e o que está faltando, sem rodar nada.
## Checagens
| Nível | Checagem | Ferramenta | Como é detectada |
|---|---|---|---|
| 0 | lint | script `lint` do package.json, eslint, ruff, `go vet`, clippy | primeira que existir |
| 0 | typecheck | script `typecheck`, `tsc --noEmit`, pyright, mypy | tsconfig ou config do checker |
| 0 | test | script `test`, pytest (usa `.venv` se existir), `go test`, `cargo test` | stack do projeto |
| 0 | secrets | gitleaks, só nos arquivos alterados | binário no PATH |
| 1 | diff-coverage | diff-cover sobre `coverage.xml` | relatório de cobertura presente |
| 1 | semgrep | `semgrep --config p/default --baseline-commit <base>` | binário no PATH |
| 1 | dead-code (info) | knip, vulture | binário no projeto ou PATH |
| 2 | build | script `build` | package.json |
| 2 | mutation | Stryker nos arquivos alterados; mutmut (paths configurados) | config do Stryker ou `[tool.mutmut]` |
| 2 | osv-scanner | `osv-scanner scan source --recursive .` | binário no PATH |
| 2 | architecture | dependency-cruiser, import-linter | arquivo de config |
| 2 | duplication (info) | jscpd | binário no projeto |
| 3 | trivy | vulnerabilidades, misconfig e segredos, HIGH e CRITICAL | binário no PATH |
| 3 | traceability | todo `REQ-NNN` da spec aparece em algum teste | `[spec]` na config |
Estados: `pass`, `fail`, `unverified` (ferramenta ou config ausente, nunca conta como aprovado) e
`info` (só relatório). Veredito: `fail` se algo falhou; `incomplete` se algo ficou não verificado; senão `pass`.
## `.dev-workflows.toml` (opcional, na raiz do projeto)
```toml
timeout = 600 # segundos por checagem
[commands] # substitui o que foi detectado
test = "pnpm vitest run --coverage"
lint = "pnpm eslint ."
mutation = "pnpm stryker run --incremental"
[thresholds]
diff_coverage = 80
[coverage]
report = "coverage/cobertura-coverage.xml"
[spec] # nível 3: rastreabilidade requisito -> teste
file = "docs/spec.md"
tests = ["tests", "e2e"]
[[check]] # checagem extra; kind = "gate" (padrão) ou "info"
name = "lighthouse"
cmd = "npx lhci autorun"
tier = 2
[[check]]
name = "a11y"
cmd = "npx playwright test e2e/a11y.spec.ts"
tier = 2
[[check]]
name = "api-fuzz"
cmd = "schemathesis run http://localhost:8000/openapi.json --checks all"
tier = 2
```
Frontend, API e carga dependem do app estar de pé, então entram como `[[check]]` do projeto
(Lighthouse CI com orçamento, Playwright com `@axe-core/playwright`, schemathesis, k6 com thresholds).
`DW_GATE=off` desliga o hook de `Stop` numa sessão.
+53
View File
@@ -0,0 +1,53 @@
---
name: lean-code
description: Use sempre que for escrever ou mudar código. Escolhe a menor solução que resolve de verdade - reaproveitar antes de escrever, apagar antes de somar, sem abstração especulativa e sem dependência desnecessária.
license: MIT
metadata:
dev-workflows:
uses: [safedeps]
external: []
---
# Lean Code
Primeiro entenda o problema e o código que ele toca. Depois suba a escada e pare no primeiro degrau
que resolve.
## Escada
1. **Precisa existir?** Pedido especulativo ("para depois", "vai que") não entra. Diga isso em uma linha.
2. **Já existe no projeto?** Procure helper, componente, tipo ou padrão parecido antes de escrever (`grep` por nomes e por comportamento; o agente `explorer` faz isso).
3. **A biblioteca padrão resolve?**
4. **A plataforma resolve?** HTML/CSS nativo antes de JS, constraint do banco antes de código, recurso do framework antes de utilitário próprio.
5. **Uma dependência já instalada resolve?**
6. **Cabe em poucas linhas?**
7. Só então: o mínimo de código novo.
## Regras
- **Bug se corrige na causa.** Antes de editar uma função, ache todos os chamadores. Uma correção no ponto por onde todos passam é menor que uma por chamador, e não deixa os outros quebrados.
- **Sem abstração sem uso:** interface com uma implementação, factory de um produto, configuração para valor que nunca muda.
- **Dependência nova exige justificativa** em uma linha (o que ela faz que os degraus 3 a 6 não fazem) e consulta ao `safedeps` antes de instalar. O gate lista as novas.
- **Apague o que ficou morto** por causa da mudança.
- **Entre duas soluções do mesmo tamanho**, fique com a que está certa nos casos de borda.
## Nunca simplifique
Validação na fronteira do sistema, tratamento de erro que evita perda de dado, controles de segurança,
acessibilidade básica e qualquer coisa que o usuário pediu explicitamente.
## Orçamento de diff (linhas líquidas, referência)
| Nível | Orçamento |
|---|---|
| 0 | 20 |
| 1 | 100 |
| 2 | 400 |
| 3 | 400 por fatia entregue |
Estourou: justifique no relatório ou quebre em partes menores.
## Atalho consciente
Quando cortar caminho de propósito (lock global, busca O(n²), heurística simples), deixe um comentário
`lean:` dizendo o limite e quando evoluir: `# lean: lock global; trocar por lock por conta se a vazão importar`.
@@ -0,0 +1,345 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/UnitOneAI/SecuritySkills/schemas/finding.schema.json",
"title": "SecuritySkills Normalized Finding Output",
"description": "Machine-readable envelope for normalized security findings and remediation recommendations emitted by SecuritySkills workflows. This contract is independent of SARIF and may be mapped to downstream enterprise formats later.",
"type": "object",
"additionalProperties": false,
"required": ["schema_version", "run", "skill", "findings"],
"properties": {
"schema_version": {
"const": "1.0.0",
"description": "Version of this normalized SecuritySkills finding envelope."
},
"run": {
"$ref": "#/$defs/run",
"description": "Metadata for the analysis run that produced this output."
},
"skill": {
"$ref": "#/$defs/skill",
"description": "Metadata for the SecuritySkills entrypoint that produced this output."
},
"findings": {
"type": "array",
"items": {
"$ref": "#/$defs/finding"
},
"description": "Normalized findings produced by a skill run."
}
},
"$defs": {
"riskLevel": {
"type": "string",
"enum": ["low", "medium", "high"]
},
"nonEmptyString": {
"type": "string",
"minLength": 1
},
"uriString": {
"type": "string",
"format": "uri"
},
"run": {
"type": "object",
"additionalProperties": false,
"required": ["id", "timestamp"],
"properties": {
"id": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable run identifier supplied by the agent, CI job, or enterprise orchestrator."
},
"timestamp": {
"$ref": "#/$defs/nonEmptyString",
"description": "ISO 8601 timestamp for when the run output was produced."
},
"tool": {
"$ref": "#/$defs/nonEmptyString",
"description": "Agent, CLI, scanner, or workflow that executed the skill."
},
"target": {
"$ref": "#/$defs/nonEmptyString",
"description": "Repository, project, service, artifact, environment, or other target reviewed."
},
"source_ref": {
"$ref": "#/$defs/nonEmptyString",
"description": "Optional commit SHA, branch, image digest, build ID, ticket ID, or evidence package reference."
}
}
},
"skill": {
"type": "object",
"additionalProperties": false,
"required": ["name", "version"],
"properties": {
"name": {
"$ref": "#/$defs/nonEmptyString",
"description": "SecuritySkills skill name from SKILL.md frontmatter."
},
"version": {
"$ref": "#/$defs/nonEmptyString",
"description": "SecuritySkills skill version from SKILL.md frontmatter."
},
"path": {
"$ref": "#/$defs/nonEmptyString",
"description": "Path to the SKILL.md entrypoint used for the run."
},
"frameworks": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/nonEmptyString"
},
"description": "Framework identifiers declared by the skill frontmatter."
}
}
},
"finding": {
"type": "object",
"additionalProperties": false,
"required": ["id", "title", "severity", "status", "evidence", "remediations"],
"properties": {
"id": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable finding identifier within the output."
},
"fingerprint": {
"$ref": "#/$defs/nonEmptyString",
"description": "Stable deduplication key based on finding type, affected asset, and evidence location."
},
"title": {
"$ref": "#/$defs/nonEmptyString"
},
"description": {
"$ref": "#/$defs/nonEmptyString",
"description": "What the issue is and why it matters."
},
"severity": {
"type": "string",
"enum": ["info", "low", "medium", "high", "critical"]
},
"status": {
"type": "string",
"enum": ["open", "mitigated", "accepted_risk", "false_positive"]
},
"cwe": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"pattern": "^CWE-[0-9]+$"
},
"description": "Optional CWE mappings, when applicable."
},
"framework_refs": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/frameworkRef"
},
"description": "Framework/control references from the skill frontmatter frameworks."
},
"references": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/reference"
},
"description": "Optional advisory, standard, vendor, or knowledge-base references."
},
"evidence": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["location", "summary"],
"properties": {
"location": {
"$ref": "#/$defs/nonEmptyString",
"description": "File path, line range, asset ID, log source, policy path, or other concrete evidence location."
},
"summary": {
"$ref": "#/$defs/nonEmptyString"
},
"artifact_type": {
"type": "string",
"enum": ["source", "config", "policy", "log", "scan_result", "cloud_resource", "identity", "network", "document", "other"]
},
"snippet": {
"$ref": "#/$defs/nonEmptyString",
"description": "Minimal redacted snippet or observation needed to support the finding."
},
"redacted": {
"type": "boolean",
"description": "True when sensitive values were intentionally removed from this evidence."
}
}
}
},
"remediations": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/remediation"
},
"description": "Every fix recommendation for this finding. Each item must include remediation guidance, confidence, blast radius, behavior-change risk, and test strategy."
}
},
"anyOf": [
{
"required": ["cwe"]
},
{
"required": ["framework_refs"]
}
]
},
"frameworkRef": {
"type": "object",
"additionalProperties": false,
"required": ["framework", "control"],
"properties": {
"framework": {
"$ref": "#/$defs/nonEmptyString"
},
"control": {
"$ref": "#/$defs/nonEmptyString"
},
"name": {
"$ref": "#/$defs/nonEmptyString"
}
}
},
"reference": {
"type": "object",
"additionalProperties": false,
"required": ["type", "id"],
"properties": {
"type": {
"type": "string",
"enum": ["cve", "cwe", "framework", "advisory", "vendor", "documentation", "other"]
},
"id": {
"$ref": "#/$defs/nonEmptyString"
},
"url": {
"$ref": "#/$defs/uriString"
}
}
},
"remediation": {
"type": "object",
"additionalProperties": false,
"required": ["guidance", "confidence", "blast_radius", "behavior_change_risk", "test_strategy"],
"properties": {
"guidance": {
"$ref": "#/$defs/nonEmptyString",
"description": "Concrete remediation steps or patch guidance for the finding."
},
"confidence": {
"$ref": "#/$defs/riskLevel",
"description": "How confident the skill is that this recommendation is correct for the observed evidence."
},
"blast_radius": {
"$ref": "#/$defs/nonEmptyString",
"description": "Expected scope of systems, files, users, integrations, data, or workflows affected by the change."
},
"behavior_change_risk": {
"$ref": "#/$defs/riskLevel",
"description": "Risk that the remediation changes intended application or operational behavior."
},
"test_strategy": {
"$ref": "#/$defs/testStrategy",
"description": "Required validation strategy proving the remediation fixes the finding. Include recommended tests, generated tests, or both."
}
}
},
"testStrategy": {
"type": "object",
"additionalProperties": false,
"required": ["summary"],
"properties": {
"summary": {
"$ref": "#/$defs/nonEmptyString",
"description": "Concise explanation of what proves the remediation fixed the issue."
},
"recommended_tests": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/recommendedTest"
},
"description": "Tests the user or agent should run when tests are not generated directly."
},
"generated_tests": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/generatedTest"
},
"description": "Test files or cases produced as part of the remediation."
}
},
"anyOf": [
{
"required": ["recommended_tests"]
},
{
"required": ["generated_tests"]
}
]
},
"recommendedTest": {
"type": "object",
"additionalProperties": false,
"required": ["name", "type", "purpose", "command", "expected_result"],
"properties": {
"name": {
"$ref": "#/$defs/nonEmptyString"
},
"type": {
"type": "string",
"enum": ["static", "unit", "integration", "e2e", "regression", "manual"]
},
"purpose": {
"$ref": "#/$defs/nonEmptyString",
"description": "Behavior, vulnerability condition, or regression this test proves."
},
"command": {
"$ref": "#/$defs/nonEmptyString",
"description": "Command or manual check to execute for this test."
},
"expected_result": {
"$ref": "#/$defs/nonEmptyString"
}
}
},
"generatedTest": {
"type": "object",
"additionalProperties": false,
"required": ["path", "type", "purpose", "command", "expected_result"],
"properties": {
"path": {
"$ref": "#/$defs/nonEmptyString",
"description": "Path to the generated or modified test file."
},
"type": {
"type": "string",
"enum": ["static", "unit", "integration", "e2e", "regression"]
},
"purpose": {
"$ref": "#/$defs/nonEmptyString",
"description": "Behavior, vulnerability condition, or regression this generated test proves."
},
"command": {
"$ref": "#/$defs/nonEmptyString",
"description": "Command that runs the generated test."
},
"expected_result": {
"$ref": "#/$defs/nonEmptyString"
}
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Leonxlnx
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+178
View File
@@ -0,0 +1,178 @@
---
name: redesign-existing-projects
description: Upgrades existing websites and apps to premium quality. Audits current design, identifies generic AI patterns, and applies high-end design standards without breaking functionality. Works with any CSS framework or vanilla CSS.
---
# Redesign Skill
## How This Works
When applied to an existing project, follow this sequence:
1. **Scan** — Read the codebase. Identify the framework, styling method (Tailwind, vanilla CSS, styled-components, etc.), and current design patterns.
2. **Diagnose** — Run through the audit below. List every generic pattern, weak point, and missing state you find.
3. **Fix** — Apply targeted upgrades working with the existing stack. Do not rewrite from scratch. Improve what's there.
## Design Audit
### Typography
Check for these problems and fix them:
- **Browser default fonts or Inter everywhere.** Replace with a font that has character. Good options: `Geist`, `Outfit`, `Cabinet Grotesk`, `Satoshi`. For editorial/creative projects, pair a serif header with a sans-serif body.
- **Headlines lack presence.** Increase size for display text, tighten letter-spacing, reduce line-height. Headlines should feel heavy and intentional.
- **Body text too wide.** Limit paragraph width to roughly 65 characters. Increase line-height for readability.
- **Only Regular (400) and Bold (700) weights used.** Introduce Medium (500) and SemiBold (600) for more subtle hierarchy.
- **Numbers in proportional font.** Use a monospace font or enable tabular figures (`font-variant-numeric: tabular-nums`) for data-heavy interfaces.
- **Missing letter-spacing adjustments.** Use negative tracking for large headers, positive tracking for small caps or labels.
- **All-caps subheaders everywhere.** Try lowercase italics, sentence case, or small-caps instead.
- **Orphaned words.** Single words sitting alone on the last line. Fix with `text-wrap: balance` or `text-wrap: pretty`.
### Color and Surfaces
- **Pure `#000000` background.** Replace with off-black, dark charcoal, or tinted dark (`#0a0a0a`, `#121212`, or a dark navy).
- **Oversaturated accent colors.** Keep saturation below 80%. Desaturate accents so they blend with neutrals instead of screaming.
- **More than one accent color.** Pick one. Remove the rest. Consistency beats variety.
- **Mixing warm and cool grays.** Stick to one gray family. Tint all grays with a consistent hue (warm or cool, not both).
- **Purple/blue "AI gradient" aesthetic.** This is the most common AI design fingerprint. Replace with neutral bases and a single, considered accent.
- **Generic `box-shadow`.** Tint shadows to match the background hue. Use colored shadows (e.g., dark blue shadow on a blue background) instead of pure black at low opacity.
- **Flat design with zero texture.** Add subtle noise, grain, or micro-patterns to backgrounds. Pure flat vectors feel sterile.
- **Perfectly even gradients.** Break the uniformity with radial gradients, noise overlays, or mesh gradients instead of standard linear 45-degree fades.
- **Inconsistent lighting direction.** Audit all shadows to ensure they suggest a single, consistent light source.
- **Random dark sections in a light mode page (or vice versa).** A single dark-background section breaking an otherwise light page looks like a copy-paste accident. Either commit to a full dark mode or keep a consistent background tone throughout. If contrast is needed, use a slightly darker shade of the same palette — not a sudden jump to `#111` in the middle of a cream page.
- **Empty, flat sections with no visual depth.** Sections that are just text on a plain background feel unfinished. Add high-quality background imagery (blurred, overlaid, or masked), subtle patterns, or ambient gradients. Use reliable placeholder sources like `https://picsum.photos/seed/{name}/1920/1080` when real assets are not available. Experiment with background images behind hero sections, feature blocks, or CTAs — even a subtle full-width photo at low opacity adds presence.
### Layout
- **Everything centered and symmetrical.** Break symmetry with offset margins, mixed aspect ratios, or left-aligned headers over centered content.
- **Three equal card columns as feature row.** This is the most generic AI layout. Replace with a 2-column zig-zag, asymmetric grid, horizontal scroll, or masonry layout.
- **Using `height: 100vh` for full-screen sections.** Replace with `min-height: 100dvh` to prevent layout jumping on mobile browsers (iOS Safari viewport bug).
- **Complex flexbox percentage math.** Replace with CSS Grid for reliable multi-column structures.
- **No max-width container.** Add a container constraint (around 1200-1440px) with auto margins so content doesn't stretch edge-to-edge on wide screens.
- **Cards of equal height forced by flexbox.** Allow variable heights or use masonry when content varies in length.
- **Uniform border-radius on everything.** Vary the radius: tighter on inner elements, softer on containers.
- **No overlap or depth.** Elements sit flat next to each other. Use negative margins to create layering and visual depth.
- **Symmetrical vertical padding.** Top and bottom padding are always identical. Adjust optically — bottom padding often needs to be slightly larger.
- **Dashboard always has a left sidebar.** Try top navigation, a floating command menu, or a collapsible panel instead.
- **Missing whitespace.** Double the spacing. Let the design breathe. Dense layouts work for data dashboards, not for marketing pages.
- **Buttons not bottom-aligned in card groups.** When cards have different content lengths, CTAs end up at random heights. Pin buttons to the bottom of each card so they form a clean horizontal line regardless of content above.
- **Feature lists starting at different vertical positions.** In pricing tables or comparison cards, the list of features should start at the same Y position across all columns. Use consistent spacing above the list or fixed-height title/price blocks.
- **Inconsistent vertical rhythm in side-by-side elements.** When placing cards, columns, or panels next to each other, align shared elements (titles, descriptions, prices, buttons) across all items. Misaligned baselines make the layout look broken.
- **Mathematical alignment that looks optically wrong.** Centering by the math doesn't always look centered to the eye. Icons next to text, play buttons in circles, or text in buttons often need 1-2px optical adjustments to feel right.
### Interactivity and States
- **No hover states on buttons.** Add background shift, slight scale, or translate on hover.
- **No active/pressed feedback.** Add a subtle `scale(0.98)` or `translateY(1px)` on press to simulate a physical click.
- **Instant transitions with zero duration.** Add smooth transitions (200-300ms) to all interactive elements.
- **Missing focus ring.** Ensure visible focus indicators for keyboard navigation. This is an accessibility requirement, not optional.
- **No loading states.** Replace generic circular spinners with skeleton loaders that match the layout shape.
- **No empty states.** An empty dashboard showing nothing is a missed opportunity. Design a composed "getting started" view.
- **No error states.** Add clear, inline error messages for forms. Do not use `window.alert()`.
- **Dead links.** Buttons that link to `#`. Either link to real destinations or visually disable them.
- **No indication of current page in navigation.** Style the active nav link differently so users know where they are.
- **Scroll jumping.** Anchor clicks jump instantly. Add `scroll-behavior: smooth`.
- **Animations using `top`, `left`, `width`, `height`.** Switch to `transform` and `opacity` for GPU-accelerated, smooth animation.
### Content
- **Generic names like "John Doe" or "Jane Smith".** Use diverse, realistic-sounding names.
- **Fake round numbers like `99.99%`, `50%`, `$100.00`.** Use organic, messy data: `47.2%`, `$99.00`, `+1 (312) 847-1928`.
- **Placeholder company names like "Acme Corp", "Nexus", "SmartFlow".** Invent contextual, believable brand names.
- **AI copywriting cliches.** Never use "Elevate", "Seamless", "Unleash", "Next-Gen", "Game-changer", "Delve", "Tapestry", or "In the world of...". Write plain, specific language.
- **Exclamation marks in success messages.** Remove them. Be confident, not loud.
- **"Oops!" error messages.** Be direct: "Connection failed. Please try again."
- **Passive voice.** Use active voice: "We couldn't save your changes" instead of "Mistakes were made."
- **All blog post dates identical.** Randomize dates to appear real.
- **Same avatar image for multiple users.** Use unique assets for every distinct person.
- **Lorem Ipsum.** Never use placeholder latin text. Write real draft copy.
- **Title Case On Every Header.** Use sentence case instead.
### Component Patterns
- **Generic card look (border + shadow + white background).** Remove the border, or use only background color, or use only spacing. Cards should exist only when elevation communicates hierarchy.
- **Always one filled button + one ghost button.** Add text links or tertiary styles to reduce visual noise.
- **Pill-shaped "New" and "Beta" badges.** Try square badges, flags, or plain text labels.
- **Accordion FAQ sections.** Use a side-by-side list, searchable help, or inline progressive disclosure.
- **3-card carousel testimonials with dots.** Replace with a masonry wall, embedded social posts, or a single rotating quote.
- **Pricing table with 3 towers.** Highlight the recommended tier with color and emphasis, not just extra height.
- **Modals for everything.** Use inline editing, slide-over panels, or expandable sections instead of popups for simple actions.
- **Avatar circles exclusively.** Try squircles or rounded squares for a less generic look.
- **Light/dark toggle always a sun/moon switch.** Use a dropdown, system preference detection, or integrate it into settings.
- **Footer link farm with 4 columns.** Simplify. Focus on main navigational paths and legally required links.
### Iconography
- **Lucide or Feather icons exclusively.** These are the "default" AI icon choice. Use Phosphor, Heroicons, or a custom set for differentiation.
- **Rocketship for "Launch", shield for "Security".** Replace cliche metaphors with less obvious icons (bolt, fingerprint, spark, vault).
- **Inconsistent stroke widths across icons.** Audit all icons and standardize to one stroke weight.
- **Missing favicon.** Always include a branded favicon.
- **Stock "diverse team" photos.** Use real team photos, candid shots, or a consistent illustration style instead of uncanny stock imagery.
### Code Quality
- **Div soup.** Use semantic HTML: `<nav>`, `<main>`, `<article>`, `<aside>`, `<section>`.
- **Inline styles mixed with CSS classes.** Move all styling to the project's styling system.
- **Hardcoded pixel widths.** Use relative units (`%`, `rem`, `em`, `max-width`) for flexible layouts.
- **Missing alt text on images.** Describe image content for screen readers. Never leave `alt=""` or `alt="image"` on meaningful images.
- **Arbitrary z-index values like `9999`.** Establish a clean z-index scale in the theme/variables.
- **Commented-out dead code.** Remove all debug artifacts before shipping.
- **Import hallucinations.** Check that every import actually exists in `package.json` or the project dependencies.
- **Missing meta tags.** Add proper `<title>`, `description`, `og:image`, and social sharing meta tags.
### Strategic Omissions (What AI Typically Forgets)
- **No legal links.** Add privacy policy and terms of service links in the footer.
- **No "back" navigation.** Dead ends in user flows. Every page needs a way back.
- **No custom 404 page.** Design a helpful, branded "page not found" experience.
- **No form validation.** Add client-side validation for emails, required fields, and format checks.
- **No "skip to content" link.** Essential for keyboard users. Add a hidden skip-link.
- **No cookie consent.** If required by jurisdiction, add a compliant consent banner.
## Upgrade Techniques
When upgrading a project, pull from these high-impact techniques to replace generic patterns:
### Typography Upgrades
- **Variable font animation.** Interpolate weight or width on scroll or hover for text that feels alive.
- **Outlined-to-fill transitions.** Text starts as a stroke outline and fills with color on scroll entry or interaction.
- **Text mask reveals.** Large typography acting as a window to video or animated imagery behind it.
### Layout Upgrades
- **Broken grid / asymmetry.** Elements that deliberately ignore column structure — overlapping, bleeding off-screen, or offset with calculated randomness.
- **Whitespace maximization.** Aggressive use of negative space to force focus on a single element.
- **Parallax card stacks.** Sections that stick and physically stack over each other during scroll.
- **Split-screen scroll.** Two halves of the screen sliding in opposite directions.
### Motion Upgrades
- **Smooth scroll with inertia.** Decouple scrolling from browser defaults for a heavier, cinematic feel.
- **Staggered entry.** Elements cascade in with slight delays, combining Y-axis translation with opacity fade. Never mount everything at once.
- **Spring physics.** Replace linear easing with spring-based motion for a natural, weighty feel on all interactive elements.
- **Scroll-driven reveals.** Content entering through expanding masks, wipes, or draw-on SVG paths tied to scroll progress.
### Surface Upgrades
- **True glassmorphism.** Go beyond `backdrop-filter: blur`. Add a 1px inner border and a subtle inner shadow to simulate edge refraction.
- **Spotlight borders.** Card borders that illuminate dynamically under the cursor.
- **Grain and noise overlays.** A fixed, pointer-events-none overlay with subtle noise to break digital flatness.
- **Colored, tinted shadows.** Shadows that carry the hue of the background rather than using generic black.
## Fix Priority
Apply changes in this order for maximum visual impact with minimum risk:
1. **Font swap** — biggest instant improvement, lowest risk
2. **Color palette cleanup** — remove clashing or oversaturated colors
3. **Hover and active states** — makes the interface feel alive
4. **Layout and spacing** — proper grid, max-width, consistent padding
5. **Replace generic components** — swap cliche patterns for modern alternatives
6. **Add loading, empty, and error states** — makes it feel finished
7. **Polish typography scale and spacing** — the premium final touch
## Rules
- Work with the existing tech stack. Do not migrate frameworks or styling libraries.
- Do not break existing functionality. Test after every change.
- Before importing any new library, check the project's dependency file first.
- If the project uses Tailwind, check the version (v3 vs v4) before modifying config.
- If the project has no framework, use vanilla CSS.
- Keep changes reviewable and focused. Small, targeted improvements over big rewrites.
+140
View File
@@ -0,0 +1,140 @@
# Play: Software Composition Analysis Audit
Scan project dependencies for known vulnerabilities (CVEs), produce severity-ranked findings with remediation guidance.
## Trigger Conditions
Use this skill when:
- Reviewing a project's dependency files (package.json, requirements.txt, go.mod, pom.xml, Gemfile, Cargo.toml, etc.)
- A user asks to check for vulnerable dependencies
- Performing a pre-deployment security review
- Triaging a Dependabot/Renovate alert
## Inputs
- Project root directory (must contain dependency manifests and/or lockfiles)
- (Optional) Severity threshold — minimum severity to report (default: MEDIUM)
- (Optional) Ignore list — CVEs to suppress (with documented justification)
## Procedure
### 1. Identify Dependency Manifests
Scan for all dependency files in the project:
| Ecosystem | Manifest | Lockfile |
|-----------|----------|----------|
| Node.js | package.json | package-lock.json, yarn.lock, pnpm-lock.yaml |
| Python | requirements.txt, setup.py, pyproject.toml | Pipfile.lock, poetry.lock |
| Go | go.mod | go.sum |
| Java/Kotlin | pom.xml, build.gradle | gradle.lockfile |
| Ruby | Gemfile | Gemfile.lock |
| Rust | Cargo.toml | Cargo.lock |
| .NET | *.csproj, packages.config | packages.lock.json |
| PHP | composer.json | composer.lock |
Prefer lockfiles over manifests — they capture the exact resolved versions including transitive dependencies.
### 2. Run Vulnerability Scan
Use available tools in order of preference:
1. **osv-scanner** (recommended — uses OSV.dev database, covers all ecosystems):
```bash
osv-scanner --lockfile=<lockfile_path> --format=json
```
2. **npm audit** (Node.js projects):
```bash
npm audit --json
```
3. **pip-audit** (Python projects):
```bash
pip-audit -r requirements.txt --format=json
```
4. **govulncheck** (Go projects):
```bash
govulncheck ./...
```
5. **trivy** (multi-ecosystem, container images too):
```bash
trivy fs --format json --scanners vuln <project_path>
```
If no scanner is installed, **stop and ask the user to install one** rather than attempting manual analysis. Even small projects have 50+ dependencies — manually cross-referencing versions against CVE databases is not cost-effective. Recommend:
```bash
# Fastest to install, covers all ecosystems
brew install osv-scanner # or: npm install -g osv-scanner
# Node.js projects already have this
npm audit --json
```
For manual triage of individual packages, use the [OSV.dev vulnerability database](https://osv.dev/list) to search by package name or CVE.
### 3. Analyze Results
For each vulnerability found:
1. **Determine reachability**: Is the vulnerable code path actually used by this project?
- Check import statements and usage patterns
- A vulnerability in an unused function of a dependency is lower priority
2. **Check exploitability context**: Is the vulnerability exploitable in this deployment?
- A client-side library vuln in a server-only project may not apply
- A DoS vulnerability may be less critical for internal tools
3. **Identify fix availability**: Is there a patched version?
- Check if upgrading is a minor/patch bump (low risk) or major bump (breaking changes)
- Check if the fix is in a direct dependency or requires bumping a transitive dep
### 4. Produce Findings
For each confirmed vulnerability, generate a finding with:
- CVE/GHSA identifier
- Affected package and version
- Fixed version (if available)
- CVSS score and severity
- Whether the vulnerable code path is reachable
- Upgrade command to fix
### 5. Generate Dependency Health Summary
Beyond CVEs, flag:
- **Unmaintained packages**: No commits in 2+ years, archived repos
- **Typosquatting risk**: Package names that are suspiciously similar to popular packages
- **License concerns**: Packages with no license or unexpected license changes
- **Pinning issues**: Using ranges (^, ~) instead of exact versions in production lockfiles
## Output Format
```markdown
## SCA Audit: [Project Name]
### Scan Summary
- **Ecosystems**: [Node.js, Python, etc.]
- **Total dependencies**: [N direct, M transitive]
- **Scanner used**: [tool name and version]
- **Vulnerabilities found**: [X critical, Y high, Z medium, W low]
### Critical & High Findings
[Standard finding template for each, sorted by severity]
### Medium & Low Findings
[Condensed table format]
| Package | Version | CVE | Severity | Fixed In | Reachable? |
|---------|---------|-----|----------|----------|------------|
### Dependency Health
[Flags for unmaintained, license, pinning issues]
### Remediation Commands
[Exact commands to fix — e.g., `npm install package@version`]
```
## OWASP References
- **A06:2021** — Vulnerable and Outdated Components
- OWASP Dependency-Check
- OWASP Software Component Verification Standard (SCVS)
- OWASP Cheat Sheet: Vulnerable Dependency Management
+48
View File
@@ -0,0 +1,48 @@
# Finding Template
Use this structure for all security findings produced by skills.
```markdown
### [SEVERITY] Title
- **ID**: NDC-YYYY-NNN (auto-incrementing)
- **CWE**: CWE-XXX (if applicable)
- **CVE**: CVE-YYYY-NNNNN (if applicable)
- **OpenCRE**: [CRE-ID](https://www.opencre.org/cre/CRE-ID) — requirement name (see data/opencre/)
- **OWASP Ref**: Top 10 A01, ASVS V4.1.1, MASVS-STORAGE-1, MASWE-0001, MASTG-TEST-0200, LLM01, etc.
- **Location**: file_path:line_number or component name
- **Impact**: What an attacker can achieve (1-2 sentences)
- **Evidence**: Code snippet, command output, or proof-of-concept
- **Remediation**: Specific fix with code example
- **Confidence**: HIGH | MEDIUM | LOW (how certain is this finding)
```
### Resolving OpenCRE Links
When you have a CWE, look up its OpenCRE mapping via the API:
```
GET https://www.opencre.org/rest/v1/standard/CWE/sectionid/{cwe-number}
```
This returns the CRE ID and linked standards (ASVS, WSTG, NIST 800-53, cheat sheets). Include the CRE link in findings to give readers one-click access to all related standards and remediation guidance.
Common mappings are pre-populated in `data/opencre/README.md`.
## Severity Definitions
| Severity | CVSS Range | Criteria |
|----------|-----------|----------|
| CRITICAL | 9.0-10.0 | Remote code execution, full system compromise, mass data breach |
| HIGH | 7.0-8.9 | Privilege escalation, significant data exposure, auth bypass |
| MEDIUM | 4.0-6.9 | Limited data exposure, requires user interaction or specific conditions |
| LOW | 0.1-3.9 | Information disclosure, minor misconfigurations |
| INFORMATIONAL | N/A | Best practice recommendations, defense-in-depth suggestions |
## Confidence Levels
| Level | Meaning |
|-------|---------|
| HIGH | Confirmed via code path analysis, PoC, or tool output |
| MEDIUM | Strong indicators but not fully confirmed — needs manual verification |
| LOW | Heuristic match or pattern-based — may be false positive |
+147
View File
@@ -0,0 +1,147 @@
# Play: Secrets Scan
Detect hardcoded credentials, API keys, tokens, and other secrets in source code and configuration files.
## Trigger Conditions
Use this skill when:
- Reviewing code for leaked secrets before commit or merge
- Auditing a repository for historical secret exposure
- A user asks to check for hardcoded credentials
- Setting up pre-commit hooks for secret detection
## Inputs
- Repository or directory to scan
- (Optional) List of known-safe patterns to ignore (e.g., test fixtures, example placeholders)
- (Optional) Whether to scan git history or just current files
## Procedure
### 1. Run Automated Scanner
Use available tools in order of preference:
1. **trufflehog** (recommended — scans current files + git history):
```bash
trufflehog filesystem --directory=<path> --json
trufflehog git file://<repo_path> --json # includes git history
```
2. **gitleaks** (git-aware scanning):
```bash
gitleaks detect --source=<path> --report-format=json --report-path=results.json
```
3. **detect-secrets** (Yelp's baseline-aware scanner):
```bash
detect-secrets scan <path> --all-files
```
If no scanner is installed, proceed with manual analysis.
### 2. Manual Pattern Analysis
Search for these high-confidence patterns:
#### API Keys & Tokens
| Pattern | Service | Regex Hint |
|---------|---------|-----------|
| `AKIA[0-9A-Z]{16}` | AWS Access Key ID | Exact format |
| `sk-[a-zA-Z0-9]{48}` | OpenAI API Key | Prefix match |
| `sk-ant-[a-zA-Z0-9-]{80,}` | Anthropic API Key | Prefix match |
| `ghp_[a-zA-Z0-9]{36}` | GitHub Personal Access Token | Prefix match |
| `gho_`, `ghu_`, `ghs_`, `ghr_` | GitHub OAuth/App tokens | Prefix match |
| `xoxb-`, `xoxp-`, `xoxs-` | Slack tokens | Prefix match |
| `SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}` | SendGrid API Key | Format match |
| `sk_live_`, `pk_live_`, `rk_live_` | Stripe keys | Prefix match |
#### Credentials in Config
| Pattern | What to Look For |
|---------|-----------------|
| Connection strings | `://user:password@host` patterns |
| Password assignments | `password = "..."`, `PASSWORD: ...`, `passwd`, `secret` |
| Private keys | `-----BEGIN (RSA\|EC\|OPENSSH) PRIVATE KEY-----` |
| Certificates | PEM-encoded certificates with private key material |
| JWT secrets | `JWT_SECRET`, `TOKEN_SECRET` assignments |
| Database credentials | `DB_PASSWORD`, `MONGO_URI`, `DATABASE_URL` with embedded credentials |
#### High-Risk File Patterns
Scan these files with extra scrutiny:
- `.env`, `.env.*` files
- `**/config/**`, `**/settings/**`
- `docker-compose*.yml` (environment sections)
- `*.tfvars`, `terraform.tfstate`
- `kubeconfig`, `*.kubeconfig`
- `credentials`, `credentials.json`, `service-account*.json`
- `.npmrc`, `.pypirc`, `pip.conf` (registry tokens)
- `**/ci/**`, `.github/workflows/**` (inline secrets)
### 3. Contextual Analysis
For each detected secret:
1. **Is it real?** Filter out:
- Placeholder values (`CHANGE_ME`, `xxx`, `your-api-key-here`, `<token>`)
- Test fixtures with known dummy values
- Documentation examples
- Base64-encoded non-secret data that matches key patterns
2. **Is it active?** If possible:
- Check if the key format is currently valid for the service
- Look for rotation evidence (was it replaced in a later commit?)
- Check `.gitignore` — is the file supposed to be excluded?
3. **What's the blast radius?**
- What service does this credential access?
- What permissions does it grant?
- Is it a production or development credential?
- How long has it been exposed?
### 4. Check Preventive Controls
Verify that the project has:
- [ ] `.gitignore` entries for sensitive files (`.env`, `*.key`, `*.pem`, tfstate, etc.)
- [ ] Pre-commit hooks for secret scanning (trufflehog, gitleaks, detect-secrets)
- [ ] CI pipeline secret scanning step
- [ ] Documentation on how to manage secrets (env vars, vault, etc.)
- [ ] `.gitleaks.toml` or equivalent allowlist config for known false positives
## Output Format
```markdown
## Secrets Scan: [Repository/Directory]
### Scan Summary
- **Scanner used**: [tool or manual]
- **Scope**: Current files | Git history | Both
- **Files scanned**: [count]
- **Secrets found**: [count by category]
### Findings
[Standard finding template for each secret, with type and blast radius]
### Preventive Controls
| Control | Status |
|---------|--------|
| .gitignore covers sensitive files | Present/Missing |
| Pre-commit secret scanning | Present/Missing |
| CI secret scanning | Present/Missing |
### Immediate Actions Required
[If active production secrets are found, list rotation steps]
```
## Important Notes
- **Never include the actual secret value in findings.** Show a redacted version: `AKIA****EXAMPLE`
- If active production secrets are found, flag this as requiring **immediate rotation** — the secret must be assumed compromised once it's been in version control
- Historical secrets in git history remain accessible even after deletion from current files — git history rewriting or rotation is required
## OWASP References
- **A07:2021** — Identification and Authentication Failures
- **CWE-798** — Use of Hard-coded Credentials
- **CWE-312** — Cleartext Storage of Sensitive Information
- OWASP Cheat Sheet: Secrets Management
- OWASP WSTG-CONF-04: Review Old Backup and Unreferenced Files for Sensitive Information
+48
View File
@@ -0,0 +1,48 @@
# Finding Template
Use this structure for all security findings produced by skills.
```markdown
### [SEVERITY] Title
- **ID**: NDC-YYYY-NNN (auto-incrementing)
- **CWE**: CWE-XXX (if applicable)
- **CVE**: CVE-YYYY-NNNNN (if applicable)
- **OpenCRE**: [CRE-ID](https://www.opencre.org/cre/CRE-ID) — requirement name (see data/opencre/)
- **OWASP Ref**: Top 10 A01, ASVS V4.1.1, MASVS-STORAGE-1, MASWE-0001, MASTG-TEST-0200, LLM01, etc.
- **Location**: file_path:line_number or component name
- **Impact**: What an attacker can achieve (1-2 sentences)
- **Evidence**: Code snippet, command output, or proof-of-concept
- **Remediation**: Specific fix with code example
- **Confidence**: HIGH | MEDIUM | LOW (how certain is this finding)
```
### Resolving OpenCRE Links
When you have a CWE, look up its OpenCRE mapping via the API:
```
GET https://www.opencre.org/rest/v1/standard/CWE/sectionid/{cwe-number}
```
This returns the CRE ID and linked standards (ASVS, WSTG, NIST 800-53, cheat sheets). Include the CRE link in findings to give readers one-click access to all related standards and remediation guidance.
Common mappings are pre-populated in `data/opencre/README.md`.
## Severity Definitions
| Severity | CVSS Range | Criteria |
|----------|-----------|----------|
| CRITICAL | 9.0-10.0 | Remote code execution, full system compromise, mass data breach |
| HIGH | 7.0-8.9 | Privilege escalation, significant data exposure, auth bypass |
| MEDIUM | 4.0-6.9 | Limited data exposure, requires user interaction or specific conditions |
| LOW | 0.1-3.9 | Information disclosure, minor misconfigurations |
| INFORMATIONAL | N/A | Best practice recommendations, defense-in-depth suggestions |
## Confidence Levels
| Level | Meaning |
|-------|---------|
| HIGH | Confirmed via code path analysis, PoC, or tool output |
| MEDIUM | Strong indicators but not fully confirmed — needs manual verification |
| LOW | Heuristic match or pattern-based — may be false positive |
@@ -0,0 +1,374 @@
# Play: OWASP Top 10 Web Security Review
Review web applications against the OWASP Top 10 for Web Applications (2021), producing actionable findings with severity ratings and remediation guidance.
## Trigger Conditions
Use this play when:
- Auditing a web application (monolith, microservices, or serverless)
- Reviewing server-side web code for security vulnerabilities
- A user asks for an "OWASP Top 10 review" or "web security assessment"
- Assessing a web framework or CMS for security posture
- Performing a pre-deployment security review of a web app
## Inputs
- Web application source code (frontend and backend)
- Framework/language information (React, Django, Rails, etc.)
- Deployment context (internet-facing, internal, cloud platform)
- Authentication/authorization implementation details
- (Optional) Previous security assessments or pentest reports
## Procedure
### 1. Application Mapping
Before assessing risks, understand the application:
| Aspect | Questions |
|--------|-----------|
| **Framework** | What language/framework? (Node.js/Express, Python/Django, Ruby/Rails, Java/Spring, PHP/Laravel, etc.) |
| **Architecture** | Monolith, microservices, serverless (Lambda/Cloud Functions), SPA vs SSR? |
| **Trust Boundary** | Internet-facing, internal network, or local-only? |
| **Data Sensitivity** | Does it handle PII, credentials, financial data, health data (HIPAA)? |
| **Authentication** | Session-based, JWT, OAuth, SSO, API keys? |
| **Data Stores** | SQL database, NoSQL, cache (Redis), file storage, external APIs? |
Document the attack surface: entry points, data flows, trust boundaries.
### 2. Assess Each OWASP Top 10 Risk
#### A01: Broken Access Control
> CWE-200, CWE-201, CWE-352, CWE-639
**What to Look For:**
- [ ] **Missing authorization checks** — Endpoints or functions accessible without verifying user permissions
- [ ] **IDOR (Insecure Direct Object References)** — Can User A access User B's data by changing IDs in URLs/parameters?
- [ ] **Privilege escalation** — Can regular users access admin functions? Can users elevate their own privileges?
- [ ] **Path traversal** — Can file paths include `../` to escape intended directories?
- [ ] **CORS misconfiguration** — Overly permissive CORS allowing cross-origin attacks
- [ ] **Forced browsing** — Can unauthenticated users access protected resources by guessing URLs?
- [ ] **JWT token issues** — Missing signature validation, algorithm confusion attacks
- [ ] **Broken function-level authorization** — Different auth requirements for UI vs API endpoints
**Testing Approach:**
1. Map all endpoints requiring authentication
2. Test each without authentication (should fail)
3. Test cross-user access (User A accessing User B's resources)
4. Test privilege escalation paths (user → admin)
5. Verify authorization on every object access, not just initial authentication
---
#### A02: Cryptographic Failures
> CWE-261, CWE-296, CWE-310, CWE-319, CWE-326, CWE-327, CWE-916
**What to Look For:**
- [ ] **Weak algorithms** — MD5, SHA1 for passwords; DES, RC4 for encryption; ECB mode
- [ ] **Missing TLS** — HTTP instead of HTTPS, weak TLS versions (<1.2), insecure ciphers
- [ ] **Hardcoded credentials/keys** — API keys, database passwords, encryption keys in source code
- [ ] **Improper key management** — Keys stored in version control, no key rotation, weak key generation
- [ ] **Cleartext transmission** — Sensitive data sent over unencrypted channels
- [ ] **Cleartext storage** — Passwords, tokens, or PII stored without encryption
- [ ] **Insufficient randomness** — Predictable tokens, session IDs, or nonces
- [ ] **Missing integrity checks** — Unsigned or unvalidated data that could be tampered with
**Testing Approach:**
1. Search for hardcoded secrets using patterns (see secrets-scan.md)
2. Verify TLS configuration (certificates, protocol versions, cipher suites)
3. Check password storage (should use bcrypt, Argon2, or PBKDF2)
4. Validate encryption implementations (no custom crypto)
5. Test for sensitive data in URLs, headers, and logs
---
#### A03: Injection
> CWE-74, CWE-78, CWE-79, CWE-89, CWE-91, CWE-564, CWE-943
**What to Look For:**
| Injection Type | Indicators | Impact |
|---------------|------------|---------|
| **SQL Injection** | String concatenation in SQL, `cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")`, dynamic queries | Data exfiltration, authentication bypass, RCE |
| **NoSQL Injection** | Unsanitized JSON in MongoDB queries, `$where` clauses with user input | Data manipulation, authentication bypass |
| **OS Command Injection** | `exec()`, `system()`, `subprocess.call()` with user input | Remote code execution |
| **LDAP Injection** | User input in LDAP filters without escaping | Authentication bypass, data access |
| **XSS (Cross-Site Scripting)** | User input rendered without encoding, `innerHTML`, `dangerouslySetInnerHTML`, unescaped template output | Session hijacking, credential theft, defacement |
| **SSTI (Server-Side Template Injection)** | User input in Jinja2, ERB, EJS templates | RCE, file access |
| **XPath Injection** | User input in XPath queries | XML data access |
| **Log Injection** | CRLF in log entries (`\n\r`), log forging | Log tampering, data exfiltration |
| **Header Injection** | CRLF in HTTP headers | Response splitting, XSS |
**Testing Approach:**
1. Search for dangerous functions (concatenation, eval, exec, innerHTML)
2. Test each input field with injection payloads
3. Verify output encoding for all user-controlled data
4. Check prepared statements/parameterized queries usage
5. Validate Content Security Policy (CSP) headers for XSS mitigation
---
#### A04: Insecure Design
> CWE-73, CWE-183, CWE-209, CWE-213, CWE-235, CWE-256, CWE-257, CWE-266, CWE-269, CWE-280, CWE-434, CWE-444, CWE-501, CWE-522, CWE-697, CWE-799, CWE-807, CWE-840, CWE-841, CWE-927, CWE-1021, CWE-1173, CWE-1174, CWE-1233
**What to Look For:**
- [ ] **Missing threat modeling** — No documented attack surface, trust boundaries, or threat actors
- [ ] **Business logic flaws** — Workflow bypasses (skip payment step), race conditions (TOCTOU), price manipulation
- [ ] **Insecure workflows** — Missing confirmation steps for destructive actions, no CSRF protection on state changes
- [ ] **Lack of rate limiting** — Brute force vulnerabilities on login, password reset, or sensitive operations
- [ ] **Insufficient validation** — Client-side only validation, missing server-side checks
- [ ] **Insecure defaults** — Debug mode enabled, verbose errors in production, default credentials
- [ ] **Trust without verification** — Trusting client-provided data (prices, user IDs, permissions)
- [ ] **Missing defense in depth** — Single point of failure for security controls
**Testing Approach:**
1. Review architecture documentation for security considerations
2. Test business logic flows for bypass opportunities
3. Check for race conditions in multi-step processes
4. Verify rate limiting on sensitive endpoints
5. Ensure all validation happens server-side
---
#### A05: Security Misconfiguration
> CWE-2, CWE-11, CWE-13, CWE-15, CWE-16, CWE-209, CWE-250, CWE-260, CWE-312, CWE-497, CWE-538, CWE-540, CWE-541, CWE-547, CWE-611, CWE-614, CWE-756, CWE-942
**What to Look For:**
- [ ] **Default configurations** — Default passwords, default admin accounts, sample applications deployed
- [ ] **Verbose error messages** — Stack traces, internal paths, SQL errors exposed to users
- [ ] **Missing security headers** — No `X-Content-Type-Options`, `X-Frame-Options`, `Content-Security-Policy`, `Strict-Transport-Security`
- [ ] **Unnecessary features** — Unused ports open, unnecessary services running, debug endpoints enabled
- [ ] **Directory listing** — Web servers showing directory contents
- [ ] **Outdated software** — Old framework versions, unpatched components
- [ ] **Cloud misconfigurations** — Exposed S3 buckets, open security groups, public databases
- [ ] **Missing hardening** — Default SSL/TLS settings, unnecessary HTTP methods enabled
**Testing Approach:**
1. Review configuration files (nginx.conf, .htaccess, application.yml)
2. Check for default credentials and accounts
3. Verify security headers using tools or manual inspection
4. Test error handling (trigger errors, check responses)
5. Scan for unnecessary open ports and services
6. Check cloud configurations for public exposure
---
#### A06: Vulnerable and Outdated Components
> CWE-937, CWE-1035, CWE-1104
**What to Look For:**
- [ ] **Unpatched dependencies** — Known CVEs in libraries (see sca-audit.md)
- [ ] **Unsupported software** — End-of-life frameworks, operating systems, databases
- [ ] **Missing SBOM** — No inventory of software components
- [ ] **Unused dependencies** — Dead code increasing attack surface
- [ ] **Transitive vulnerabilities** — Vulnerabilities in dependencies of dependencies
- [ ] **Supply chain risks** — Typosquatting, malicious packages, compromised dependencies
**Testing Approach:**
1. Run SCA scanner (osv-scanner, npm audit, pip-audit)
2. Review dependency files (package.json, requirements.txt, etc.)
3. Check for end-of-life components
4. Verify dependency update processes
5. Review lockfiles for reproducible builds
---
#### A07: Identification and Authentication Failures
> CWE-287, CWE-288, CWE-290, CWE-294, CWE-295, CWE-297, CWE-300, CWE-302, CWE-304, CWE-306, CWE-307, CWE-346, CWE-384, CWE-521, CWE-613, CWE-620, CWE-640, CWE-798, CWE-940, CWE-1216
**What to Look For:**
- [ ] **Weak password policy** — No minimum length, no complexity requirements, common passwords allowed
- [ ] **Credential stuffing** — No protection against automated login attempts using breached credentials
- [ ] **Brute force** — No rate limiting or account lockout on authentication endpoints
- [ ] **Session vulnerabilities** — Predictable session IDs, session fixation, missing HttpOnly/Secure flags
- [ ] **Missing MFA** — No multi-factor authentication for sensitive accounts
- [ ] **Weak session management** — Sessions don't expire, no concurrent session limits
- [ ] **Insecure password recovery** — Weak reset tokens, predictable questions, unverified email changes
- [ ] **JWT issues** — None algorithm allowed, weak signing keys, missing expiration
**Testing Approach:**
1. Test password requirements and complexity
2. Attempt credential stuffing with known breached credentials
3. Test for brute force protection (rate limiting, CAPTCHA, lockout)
4. Analyze session handling (cookies, tokens, expiration)
5. Test password reset flows for security
6. Verify MFA implementation and bypass opportunities
---
#### A08: Software and Data Integrity Failures
> CWE-345, CWE-353, CWE-426, CWE-494, CWE-502, CWE-565, CWE-784, CWE-829, CWE-830, CWE-915
**What to Look For:**
- [ ] **Insecure deserialization** — Deserializing untrusted data (Python pickle, Java ObjectInputStream, PHP unserialize)
- [ ] **Unsigned updates** — Software updates without integrity verification
- [ ] **CI/CD attacks** — Unprotected build pipelines, compromised build agents
- [ ] **Dependency confusion** — Internal packages with names matching public packages
- [ ] **Unsigned commits** — No signature verification on code commits
- [ ] **Tamper-evident logs** — No integrity protection for audit logs
- [ ] **XML external entities (XXE)** — XML parsers with external entity processing enabled
**Testing Approach:**
1. Search for deserialization functions with user-controlled input
2. Verify update mechanisms include signature verification
3. Review CI/CD configurations for security controls
4. Check for XXE vulnerabilities in XML parsing
5. Verify integrity checks on critical data
---
#### A09: Security Logging and Monitoring Failures
> CWE-117, CWE-223, CWE-532, CWE-778, CWE-1175
**What to Look For:**
- [ ] **Missing audit logs** — No logging of authentication events, access to sensitive data, or security-critical actions
- [ ] **Insufficient log detail** — Logs don't include enough context (who, what, when, where)
- [ ] **Sensitive data in logs** — Passwords, tokens, PII logged in plaintext
- [ ] **No log protection** — Logs stored without integrity checks, accessible to attackers
- [ ] **Missing monitoring** — No alerting on suspicious activity, no SIEM integration
- [ ] **Log injection** — Attackers can forge or tamper with log entries
- [ ] **No incident response** — No documented procedures for security incidents
**Testing Approach:**
1. Review what events are logged (authentication, authorization, data access)
2. Check log format and content for sufficiency
3. Search for sensitive data in log statements
4. Verify log storage security and retention
5. Assess monitoring and alerting capabilities
---
#### A10: Server-Side Request Forgery (SSRF)
> CWE-918
**What to Look For:**
- [ ] **Unvalidated URL parameters** — User-supplied URLs fetched by the server without validation
- [ ] **Internal service access** — Can attacker reach internal services (metadata endpoints, admin panels, databases)?
- [ ] **Cloud metadata endpoints** — Access to `169.254.169.254` (AWS, Azure, GCP metadata services)
- [ ] **File protocol access** — Can `file://` URLs be used to read local files?
- [ ] **Redirect following** — Server follows redirects to attacker-controlled URLs
- [ ] **DNS rebinding** — Time-of-check vs time-of-use vulnerabilities
- [ ] **URL parsing inconsistencies** — Differences between URL parsers (e.g., `@` handling)
**Testing Approach:**
1. Identify all endpoints accepting URLs from users
2. Test for internal service access (localhost, private IPs)
3. Attempt cloud metadata endpoint access
4. Test alternative protocols (file://, gopher://, dict://)
5. Test for URL parsing bypasses (unicode, encoding, case variations)
---
### 3. Framework-Specific Checks
Apply additional checks based on detected framework:
| Framework | Key Security Checks |
|-----------|---------------------|
| **React/Next.js** | XSS via `dangerouslySetInnerHTML`, SSRF in `getServerSideProps`, API routes without auth |
| **Angular** | XSS protection bypasses, unsafe `bypassSecurityTrustHtml`, HTTP client interceptors |
| **Vue.js** | `v-html` XSS risks, server-side rendering vulnerabilities |
| **Express.js** | Missing Helmet middleware, no rate limiting, prototype pollution |
| **Django** | `DEBUG=True`, `SECRET_KEY` exposure, raw SQL, CSRF exemptions |
| **Flask** | Jinja2 autoescape disabled, unsafe session handling, debug mode |
| **Ruby on Rails** | Mass assignment, `render` with user input, SQL fragments, weak parameters |
| **Spring Boot** | SpEL injection, actuator endpoints exposed, mass assignment, CORS issues |
| **Laravel** | Mass assignment, raw queries, debug mode, configuration exposure |
| **ASP.NET Core** | Razor XSS, insecure deserialization, missing anti-forgery tokens |
---
### 4. Configuration Review
Examine these configuration areas:
#### Web Server Configuration
- **nginx/Apache**: Security headers, TLS settings, rate limiting, access controls
- **Reverse proxy**: Header forwarding, SSL termination, upstream validation
- **Load balancer**: Health checks, session affinity, DDoS protection
#### Application Configuration
- **Environment-specific settings**: Debug mode, error handling, logging levels
- **Security settings**: Password policies, session timeouts, CSRF protection
- **External integrations**: API keys, webhook secrets, OAuth configs
#### Deployment Configuration
- **Container security**: Non-root user, read-only filesystems, resource limits
- **Kubernetes**: Network policies, security contexts, RBAC
- **Cloud services**: IAM roles, security groups, encryption at rest
---
### 5. Produce Findings
For each identified vulnerability:
- Assign severity based on exploitability and impact in deployment context
- Provide concrete evidence (code locations, configuration gaps, test results)
- Propose specific remediation steps with code examples
- Rate confidence (HIGH, MEDIUM, LOW)
---
## Output Format
```markdown
## Web Security Review: [Application Name]
### Application Overview
- **Framework**: [React/Express, Django, Rails, etc.]
- **Deployment**: [Internet-facing, internal, cloud platform]
- **Architecture**: [Monolith, microservices, serverless]
- **Authentication**: [Session-based, JWT, OAuth]
### Risk Matrix
| OWASP Ref | Risk | Severity | Status |
|-----------|------|----------|--------|
| A01 | Broken Access Control | HIGH | Finding |
| A02 | Cryptographic Failures | MEDIUM | Finding |
| A03 | Injection | CRITICAL | Finding |
| A04 | Insecure Design | LOW | Finding |
| A05 | Security Misconfiguration | MEDIUM | Finding |
| A06 | Vulnerable Components | HIGH | Finding |
| A07 | Auth Failures | HIGH | Finding |
| A08 | Integrity Failures | N/A | N/A |
| A09 | Logging Failures | MEDIUM | Finding |
| A10 | SSRF | N/A | N/A |
### Findings
[Standard finding template for each identified risk]
### Positive Controls Observed
[Security controls already in place — acknowledge good practices]
### Recommendations
[Prioritized remediation roadmap]
```
---
## OWASP References
- **OWASP Top 10 for Web Applications (2021)** — [owasp.org/Top10](https://owasp.org/Top10/)
- **OWASP ASVS v5.0** — Application Security Verification Standard
- **OWASP Testing Guide (WSTG)** — Web Security Testing Guide
- **OWASP Cheat Sheet Series** — Language and framework-specific guidance
- **OWASP Proactive Controls** — Secure development practices
@@ -0,0 +1,48 @@
# Finding Template
Use this structure for all security findings produced by skills.
```markdown
### [SEVERITY] Title
- **ID**: NDC-YYYY-NNN (auto-incrementing)
- **CWE**: CWE-XXX (if applicable)
- **CVE**: CVE-YYYY-NNNNN (if applicable)
- **OpenCRE**: [CRE-ID](https://www.opencre.org/cre/CRE-ID) — requirement name (see data/opencre/)
- **OWASP Ref**: Top 10 A01, ASVS V4.1.1, MASVS-STORAGE-1, MASWE-0001, MASTG-TEST-0200, LLM01, etc.
- **Location**: file_path:line_number or component name
- **Impact**: What an attacker can achieve (1-2 sentences)
- **Evidence**: Code snippet, command output, or proof-of-concept
- **Remediation**: Specific fix with code example
- **Confidence**: HIGH | MEDIUM | LOW (how certain is this finding)
```
### Resolving OpenCRE Links
When you have a CWE, look up its OpenCRE mapping via the API:
```
GET https://www.opencre.org/rest/v1/standard/CWE/sectionid/{cwe-number}
```
This returns the CRE ID and linked standards (ASVS, WSTG, NIST 800-53, cheat sheets). Include the CRE link in findings to give readers one-click access to all related standards and remediation guidance.
Common mappings are pre-populated in `data/opencre/README.md`.
## Severity Definitions
| Severity | CVSS Range | Criteria |
|----------|-----------|----------|
| CRITICAL | 9.0-10.0 | Remote code execution, full system compromise, mass data breach |
| HIGH | 7.0-8.9 | Privilege escalation, significant data exposure, auth bypass |
| MEDIUM | 4.0-6.9 | Limited data exposure, requires user interaction or specific conditions |
| LOW | 0.1-3.9 | Information disclosure, minor misconfigurations |
| INFORMATIONAL | N/A | Best practice recommendations, defense-in-depth suggestions |
## Confidence Levels
| Level | Meaning |
|-------|---------|
| HIGH | Confirmed via code path analysis, PoC, or tool output |
| MEDIUM | Strong indicators but not fully confirmed — needs manual verification |
| LOW | Heuristic match or pattern-based — may be false positive |
+107
View File
@@ -0,0 +1,107 @@
---
name: wf-architecture
description: Use para decisões de arquitetura - desenho de sistema ou serviço novo, escolha de stack, mudança de fronteira entre módulos, migração com dado existente, troca de auth, diagrama C4, ADR, threat model, "isso é uma boa ideia arquitetonicamente?". É o workflow do nível 3 do dev-router (e do nível 2 quando surge uma decisão difícil de desfazer). Não use para bug, refactor local, tela ou endpoint isolado sem decisão estrutural (use wf-bugfix, wf-refactor, wf-frontend ou wf-backend).
license: MIT
metadata:
dev-workflows:
uses: []
external: [system-design, c4-architecture, isaqb-architecture-governance, secure-architecture-governance]
---
# Workflow Arquitetura
**Nível 3** do `dev-router`, ou nível 2 quando aparece uma decisão difícil de desfazer (banco,
protocolo, fronteira de serviço, modelo de auth). No nível 2, faça só a Fase 3 (um ADR para a decisão)
e siga com `wf-backend`/`wf-frontend`. Abaixo disso, este workflow não roda.
Cada fase produz um arquivo versionado. O que não virou arquivo não foi decidido.
Skills externas, se instaladas: `system-design` (raciocínio de design), `c4-architecture` (diagramas),
`isaqb-architecture-governance` (arc42 e ADR), `secure-architecture-governance` (STRIDE e S-ADR).
Sem elas, os modelos em [references/](references/) bastam.
## Fase 1: REQUIREMENTS
Entender antes de desenhar. Use o agente `planner` com o mapa do `explorer`.
1. Requisitos funcionais em **EARS com ID** (`REQ-001: WHEN ... THE SYSTEM SHALL ...`).
Modelo e padrões: [references/ears.md](references/ears.md).
2. Não funcionais **com número**: SLO (ex.: p95 < 250 ms, 99,9% ao mês), orçamento de performance
(LCP, tamanho de bundle, custo mensal), nível ASVS 5.0 (L2 por padrão no nível 3).
"Rápido" ou "escalável" sem número não é requisito.
3. Atores, entidades centrais e fronteiras de confiança.
4. Stack ou framework novo: consulte a documentação atual e registre URL e data. Não decida pela memória.
**Artefato:** `docs/specs/<nome>.md` com os `REQ-` e os não funcionais.
**Gate da fase:** o usuário aprova a spec antes do DESIGN.
Rastreabilidade: adicione ao `.dev-workflows.toml` do projeto
```toml
[spec]
file = "docs/specs/<nome>.md"
tests = ["tests"]
```
e o gate nível 3 falha se algum `REQ-` não aparecer em um teste
(ver `skills/dev-router/references/quality-gate.md`).
## Fase 2: DESIGN
1. Fluxo de design: requisitos, entidades, API, fluxo de dados, visão geral, pontos críticos.
2. **C4** em Mermaid: Context e Container sempre; Component só onde houver decisão.
Até 20 elementos por view, setas rotuladas, IDs estáveis. Modelo: [references/c4.md](references/c4.md).
3. Modelo de dados e estratégia de migração (reversível; com dado existente, plano de backfill e rollback).
4. **Pelo menos uma alternativa** por decisão importante, com o motivo da escolha.
**Artefato:** `docs/architecture/design.md` com os diagramas.
Confira que o Mermaid renderiza: `npx -y @mermaid-js/mermaid-cli -i docs/architecture/c4.mmd -o /tmp/c4.svg`.
## Fase 3: DOCS (ADR)
Um ADR por decisão difícil de desfazer: contexto, opções, decisão, consequências (boas e ruins).
Modelo: [references/adr.md](references/adr.md).
- `docs/architecture/adr/NNNN-<titulo>.md`, numeração sequencial, nunca reescrever um ADR aceito
(substitua por um novo com `Substitui: ADR-NNNN`).
- Decisão motivada por segurança vira S-ADR em `docs/security/adr/`.
- Todo ADR citado no design (`ADR-0003`) existe como arquivo.
## Fase 4: THREAT MODEL
STRIDE por fronteira de confiança, cada ameaça ligada a um controle ASVS 5.0 L2.
Tabela e mapeamento: [references/stride.md](references/stride.md).
1. Liste as fronteiras (internet/app, app/banco, serviço/serviço, app/terceiros, app/LLM).
2. Para cada fronteira, as seis categorias STRIDE: ameaça concreta, controle, capítulo ASVS, status.
3. Caminhos internos sem autenticação e confiança implícita entre serviços são achados, não detalhes.
4. Feature que chama LLM: inclua OWASP LLM Top 10 (prompt injection, excessive agency).
**Artefato:** `docs/security/threat-model.md`.
## Fase 5: REVIEW
1. Agente `reviewer` sobre spec, design e ADRs: consistência entre `REQ-`, diagramas e ADRs,
requisito sem dono, decisão sem alternativa.
2. Agente `security-auditor` sobre o threat model e as decisões de segurança.
3. Veredito por escrito: `Aprovado`, `Aprovado com mudanças` ou `Revisar`, cada achado com evidência
(arquivo e trecho). Gap de fronteira de confiança volta para o DESIGN.
4. O usuário aprova. A implementação segue com `wf-backend`/`wf-frontend`, tarefa a tarefa,
e fecha com `"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier 3`.
## Não faça
- Desenhar antes de ter requisito mensurável.
- ADR sem alternativa ou sem consequências.
- Mais de um ADR para a mesma decisão.
- Tratar segurança como nota mental: vira ameaça no threat model ou S-ADR.
- Decidir stack sem fonte atual.
## Checklist de entrega
- [ ] `docs/specs/<nome>.md` com `REQ-` em EARS e não funcionais com número, aprovado pelo usuário.
- [ ] `[spec]` no `.dev-workflows.toml` do projeto.
- [ ] `docs/architecture/design.md` com C4 que renderiza e alternativas registradas.
- [ ] Um ADR por decisão difícil de desfazer, com consequências.
- [ ] `docs/security/threat-model.md` com STRIDE por fronteira e controles ASVS L2.
- [ ] Revisão do `reviewer` e do `security-auditor` com veredito e evidência.
+31
View File
@@ -0,0 +1,31 @@
# Modelo de ADR
Arquivo: `docs/architecture/adr/NNNN-titulo-curto.md` (S-ADR de segurança em `docs/security/adr/`).
Numeração sequencial. ADR aceito não é reescrito: uma decisão nova cria outro ADR com `Substitui:`.
```markdown
# ADR-0003: PostgreSQL como banco de pedidos
- Status: proposto | aceito | substituído por ADR-NNNN
- Data: 2026-09-24
- Requisitos: REQ-002, REQ-010
- Substitui: (se houver)
## Contexto
O que força a decisão agora. Restrições reais (volume, equipe, custo, prazo), com números.
## Opções
1. PostgreSQL gerenciado: prós, contras.
2. MongoDB: prós, contras.
3. Manter o SQLite atual: prós, contras.
## Decisão
A opção escolhida e o motivo principal, em duas ou três frases.
## Consequências
- Boas: o que fica mais fácil.
- Ruins: o que fica mais difícil ou caro, e o que foi aceito conscientemente.
- Como desfazer, se precisar, e quanto custa.
```
Um ADR por decisão. Se duas decisões dependem uma da outra, dois ADRs que se referenciam.
+45
View File
@@ -0,0 +1,45 @@
# C4 em Mermaid
Regras: até 20 elementos por view, toda seta com rótulo (o que trafega e por qual protocolo),
IDs estáveis reaproveitados em ADRs e no threat model, declaração na ordem de leitura
(de quem usa para o que é usado).
## Context
```mermaid
C4Context
title Contexto: Sistema de Pedidos
Person(cliente, "Cliente", "Compra pelo site")
System(pedidos, "Sistema de Pedidos", "Cria e acompanha pedidos")
System_Ext(pagamento, "Gateway de pagamento", "Cobra o cartão")
Rel(cliente, pedidos, "Cria pedido", "HTTPS")
Rel(pedidos, pagamento, "Autoriza cobrança", "HTTPS/REST")
```
## Container
```mermaid
C4Container
title Containers: Sistema de Pedidos
Person(cliente, "Cliente")
System_Boundary(sp, "Sistema de Pedidos") {
Container(web, "Web", "Next.js", "Interface")
Container(api, "API", "FastAPI", "Regras de pedido")
ContainerDb(db, "Banco", "PostgreSQL", "Pedidos e itens")
Container(worker, "Worker", "Celery", "Cobrança assíncrona")
}
System_Ext(pagamento, "Gateway de pagamento")
Rel(cliente, web, "Usa", "HTTPS")
Rel(web, api, "Chama", "HTTPS/JSON")
Rel(api, db, "Lê e grava", "SQL/TLS")
Rel(api, worker, "Enfileira cobrança", "Redis")
Rel(worker, pagamento, "Autoriza", "HTTPS")
```
## Render
```bash
npx -y @mermaid-js/mermaid-cli -i docs/architecture/c4.mmd -o /tmp/c4.svg
```
Se o comando falhar, o diagrama tem erro de sintaxe e não está pronto.
+35
View File
@@ -0,0 +1,35 @@
# EARS: requisitos com ID
EARS (Easy Approach to Requirements Syntax) força cada requisito a ter gatilho e resposta
verificáveis. Um requisito por linha, ID estável `REQ-NNN`, nunca reaproveitado.
| Padrão | Forma | Exemplo |
|---|---|---|
| Ubíquo | THE SYSTEM SHALL <resposta> | `REQ-001: THE SYSTEM SHALL registrar toda alteração de preço com autor e data.` |
| Evento | WHEN <evento> THE SYSTEM SHALL <resposta> | `REQ-002: WHEN o usuário envia o formulário de cadastro THE SYSTEM SHALL responder 201 com o ID criado.` |
| Indesejado | IF <condição> THEN THE SYSTEM SHALL <resposta> | `REQ-003: IF o token expirou THEN THE SYSTEM SHALL responder 401 sem revelar se a conta existe.` |
| Estado | WHILE <estado> THE SYSTEM SHALL <resposta> | `REQ-004: WHILE a fila tiver mais de 1000 itens THE SYSTEM SHALL recusar novos jobs com 429.` |
| Opcional | WHERE <recurso> THE SYSTEM SHALL <resposta> | `REQ-005: WHERE o SSO estiver habilitado THE SYSTEM SHALL ocultar o login por senha.` |
## Não funcionais
Mesmo formato de ID, sempre com número e forma de medir:
```
REQ-010: THE SYSTEM SHALL responder GET /orders em p95 < 250 ms com 200 req/s (medido com k6).
REQ-011: THE SYSTEM SHALL manter 99,9% de disponibilidade mensal (SLO no monitoramento).
REQ-012: THE SYSTEM SHALL atender ASVS 5.0 nível L2 nos capítulos de autenticação e sessão.
REQ-013: THE SYSTEM SHALL carregar a página inicial com LCP <= 2,5 s e INP <= 200 ms (Lighthouse CI).
```
## Rastreabilidade
Cada teste cita o ID que prova, no nome ou num comentário:
```python
def test_req_003_token_expirado_retorna_401():
...
```
Com `[spec]` no `.dev-workflows.toml`, o gate nível 3 falha se algum `REQ-` da spec não aparecer
em nenhum arquivo de teste.
@@ -0,0 +1,35 @@
# Threat model STRIDE com ASVS 5.0
Arquivo: `docs/security/threat-model.md`. Uma tabela por fronteira de confiança.
## Categorias e onde procurar o controle no ASVS 5.0
| STRIDE | Ameaça típica | Capítulos ASVS 5.0 para o controle |
|---|---|---|
| Spoofing (identidade falsa) | login forjado, token roubado, serviço se passando por outro | Autenticação, Gerenciamento de sessão, Tokens autocontidos |
| Tampering (adulteração) | parâmetro alterado, mensagem na fila modificada, upload malicioso | Validação e lógica de negócio, Manipulação de arquivos, Comunicação segura |
| Repudiation (negação) | ação sensível sem rastro | Log e tratamento de erro |
| Information disclosure (vazamento) | IDOR, stack trace na resposta, segredo em log | Autorização, Proteção de dados, Log e tratamento de erro |
| Denial of service | endpoint sem limite, query sem paginação, arquivo gigante | Validação e lógica de negócio (limites), Manipulação de arquivos |
| Elevation of privilege | usuário comum chega em rota de admin, injeção de comando | Autorização, Codificação e sanitização |
Os nomes dos capítulos seguem o ASVS 5.0 (maio de 2025). Cite o requisito exato (`V<cap>.<seção>.<item>`)
consultando https://github.com/OWASP/ASVS, não pela memória.
## Modelo por fronteira
```markdown
## Fronteira: Internet -> API
| # | STRIDE | Ameaça concreta | Controle | ASVS | Status |
|---|---|---|---|---|---|
| T1 | S | Token JWT aceito com alg none | Validar alg fixo e assinatura | Tokens autocontidos | ok |
| T2 | I | GET /orders/{id} devolve pedido de outro cliente | Query escopada ao usuário autenticado | Autorização | pendente |
| T3 | D | POST /orders sem limite de taxa | Rate limit por usuário e IP | Validação e lógica de negócio | pendente |
```
Fronteiras que costumam faltar: serviço interno sem autenticação ("está na rede privada"),
worker que confia em qualquer mensagem da fila, integração com LLM (prompt injection, ferramenta
com permissão demais: OWASP LLM01 e LLM06).
Status `pendente` em ameaça alta bloqueia a aprovação da Fase 5.
+93
View File
@@ -0,0 +1,93 @@
---
name: wf-backend
description: Use para trabalho de backend e API - endpoint REST/GraphQL, autenticação, schema e migração de banco, integração, fila, webhook, job. Contrato antes do handler, defaults seguros, auditoria OWASP e gate de qualidade no nível que o dev-router definiu. Não use para UI (wf-frontend), para correção pontual sem mudança de contrato (wf-bugfix) nem para desenho de sistema com vários serviços (wf-architecture primeiro).
license: MIT
metadata:
dev-workflows:
uses: [api-security-review, safedeps, sca-audit, secrets-scan, hermaguard]
external: [secure-coding, bola-detector, auth-rbac-scaffold, injection-checker, openapi-hardener, security-test-generator]
---
# Workflow Backend/API
O `dev-router` define o nível. Cada fase diz a partir de qual nível roda. No nível 1, a mudança segue
o `wf-bugfix` (ou `wf-refactor`) com as regras de build seguro abaixo e o gate `--tier 1`.
## Fase 1: PLAN, contrato antes do código (nível 2+)
Nível 0 e 1 pulam esta fase. No nível 3, o `planner` escreve a spec EARS e esta fase vira a parte de
API dela.
1. `explorer` mapeia rotas, modelos e validações que já existem. Reaproveite antes de criar.
2. Contrato em `docs/contract.md` ou OpenAPI: rotas, métodos, payloads, status codes, erros em
RFC 9457 (`application/problem+json`), paginação, rate limit e versionamento.
3. Schemas validados na borda (Zod, Pydantic, OpenAPI). `openapi-hardener`, se instalado, saneia.
4. Modelo de dados e migração desenhados antes da query: idempotente e reversível.
5. Modelo de auth decidido e escrito no contrato (sessão, OAuth, JWT) com o motivo.
6. Contrato com decisão de produto passa pelo usuário antes do build.
## Fase 2: BUILD com defaults seguros (nível 1+)
`implementer` com TDD: comportamento novo começa por teste que falha. Regras:
- Validação de toda entrada externa na borda; nada de confiar em payload, header ou query.
- Erros estruturados (RFC 9457); nunca `except: pass` nem `catch` vazio.
- Timeout em todo cliente HTTP e conexão de banco; retry só em operação idempotente.
- Mutações idempotentes (chave de idempotência em POST que cobra ou cria); transação quando há várias escritas.
- Toda listagem com paginação e limite máximo.
- Query de dado do usuário escopada ao ID autenticado (ownership), nunca a um ID vindo do cliente.
- Senha com Argon2id; sessão em cookie `httpOnly`, `Secure`, `SameSite`; nenhum segredo, token ou senha em log.
- CORS com allowlist explícita (nunca `*` com credenciais); configuração por variável de ambiente.
- Tipos seguros na fronteira: sem `any` ou cast forçado no que entra ou sai.
- `secure-coding`, se instalado, como checklist da stack.
Dependência nova: justifique (`lean-code`) e consulte `safedeps` antes de instalar.
## Fase 3: SECURITY (nível 2+, ou nível 1 com gatilho)
Gatilhos do `dev-router` (auth, dinheiro, dado pessoal, SQL montado à mão, upload, shell, LLM) chamam
o `security-auditor`, que segue o `wf-security-review` com escopo no diff e no que ele alcança.
- Referências: OWASP API Security Top 10 (2023) e OWASP Top 10:2025.
- ASVS 5.0: L1 no nível 2, L2 no nível 3.
- Vendorizadas: `api-security-review` (OWASP API Top 10), `secrets-scan`, `sca-audit`, `safedeps` (CVE ao vivo no OSV.dev).
- Externas, se instaladas: `bola-detector` em rotas com `:id`, `auth-rbac-scaffold` em login e papéis, `injection-checker` em SQL/ORM/shell/template.
- Achado P0/P1 bloqueia a entrega; depois do fix, rode a auditoria de novo e confirme que sumiu.
- Nível 3 ou gatilho disparado: `hermaguard` no diff como passe adversarial (edge cases, ataque, blast radius).
## Fase 4: TEST + GATE (nível 1+)
1. Testes de validação, auth negativa (outro usuário, sem token, papel errado) e idempotência.
`security-test-generator`, se instalado, ajuda a gerar os casos negativos.
2. Gate: `"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier N`. Já cobre lint, typecheck, testes,
gitleaks, semgrep, cobertura do diff, mutação e osv-scanner conforme o nível.
3. Checagens que dependem do app de pé entram como `[[check]]` no `.dev-workflows.toml` do projeto
(receitas em [references/checks.md](references/checks.md)):
- schemathesis contra o OpenAPI (nível 2+): zero erro 5xx e zero violação de schema;
- Pact quando há outro serviço consumindo a API;
- migração up, down, up num banco descartável (testcontainers) quando o schema muda;
- `EXPLAIN` das queries novas e detecção de N+1 quando há query nova;
- k6 com thresholds de p95 quando a mudança toca um caminho quente (nível 3 ou gatilho de performance).
4. No nível 2+, `reviewer` revisa o diff; no nível 3, `verifier` roda o gate final e devolve a evidência.
Detalhes do gate e da configuração: [../dev-router/references/quality-gate.md](../dev-router/references/quality-gate.md).
## Relatório
Contrato entregue (nível 2+), achados de segurança por severidade e o que foi corrigido, testes que
provam (nomes e contagem real), veredito do gate com o que ficou não verificado, e linhas líquidas.
## Critérios de aceite
- [ ] Nível 2+: contrato aprovado antes do primeiro handler.
- [ ] Toda entrada externa validada na borda; erros em RFC 9457.
- [ ] Queries de dado do usuário escopadas ao ID autenticado.
- [ ] Nenhum P0/P1 de segurança aberto; CVEs consultados ao vivo, com data.
- [ ] Migração reversível provada (up, down, up) quando o schema mudou.
- [ ] Gate `pass`, ou `incomplete` com a lista do que não foi verificado dita ao usuário.
## Regras duras
- Nunca escrever handler antes do contrato aprovado (nível 2+).
- Nunca rodar `hermaguard` ou auditoria em código com testes vermelhos; corrija os testes primeiro.
- Nunca dizer "suíte passando" sem ter rodado a suíte.
+63
View File
@@ -0,0 +1,63 @@
# Checagens de backend que dependem do app de pé
Estas checagens entram como `[[check]]` no `.dev-workflows.toml` do projeto, porque precisam de
servidor, banco ou carga reais. O gate roda cada uma no nível indicado e trata ferramenta ausente
como "não verificado".
## Contrato de exemplo (`docs/contract.md`)
```text
POST /api/v1/users -> 201 | 400 | 401 | 409 | 429
GET /api/v1/users/:id -> 200 | 403 | 404
Erros: RFC 9457 (application/problem+json)
Paginação: ?cursor=&limit= (limit máx. 100)
Rate limit: 60 req/min por usuário em escrita; 429 com Retry-After
Auth: sessão em cookie httpOnly; rotas /admin exigem papel admin
```
## Receitas de `[[check]]`
```toml
# Fuzz da API a partir do OpenAPI: zero 5xx e zero violação de schema
[[check]]
name = "api-fuzz"
cmd = "schemathesis run http://localhost:8000/openapi.json --checks all"
tier = 2
# Contrato com consumidores (quando outro serviço usa a API)
[[check]]
name = "pact-verify"
cmd = "npx pact-provider-verifier --provider-base-url http://localhost:8000 --pact-broker-url $PACT_BROKER_URL"
tier = 2
# Migração reversível num banco descartável (up -> down -> up)
[[check]]
name = "migration-roundtrip"
cmd = "alembic upgrade head && alembic downgrade -1 && alembic upgrade head"
tier = 2
# Carga no caminho quente, com threshold de p95 no próprio script k6
[[check]]
name = "load"
cmd = "k6 run --quiet load/hot-path.js"
tier = 3
```
No k6, o threshold fica no script e faz o comando sair com erro quando estoura:
```js
export const options = {
vus: 20, duration: "30s",
thresholds: { http_req_duration: ["p(95)<300"], http_req_failed: ["rate<0.01"] },
};
```
Para a migração, suba um Postgres descartável (testcontainers ou `docker run --rm -p 5433:5432 postgres`)
e aponte a `DATABASE_URL` do comando para ele. Nunca rode o roundtrip num banco com dados reais.
## Queries novas
- Rode `EXPLAIN (ANALYZE, BUFFERS)` em cada query nova com volume parecido com o de produção; seq scan
em tabela grande pede índice ou filtro.
- N+1: conte as queries de uma requisição de listagem (log do ORM ou `django-debug-toolbar`,
`nplusone`, `bullet`). O número não pode crescer com o tamanho da página.
+45
View File
@@ -0,0 +1,45 @@
---
name: wf-bugfix
description: Use para corrigir bug, erro, exceção, falha, regressão, comportamento errado ("não funciona", "quebrou", "fix"). Reproduz, acha a causa raiz e prova a correção com um teste de regressão que falha antes e passa depois.
license: MIT
metadata:
dev-workflows:
uses: []
external: []
---
# Workflow Bugfix
## 1. Reproduzir
Encontre o comando, teste ou requisição que mostra o erro, e rode. Sem reprodução, colete mais dado
(stack trace, log, entrada exata) em vez de chutar uma correção.
## 2. Achar a causa raiz
- Siga o fluxo real do ponto de entrada até o erro.
- Ache todos os chamadores da função que você pretende mudar (`grep -rn "nomeDaFuncao(" .`).
- Escreva a causa em uma ou duas frases antes de editar. Se não consegue, ainda não achou.
- Corrija no ponto por onde todos os chamadores passam, não só no caminho que o relato citou.
## 3. Provar com teste de regressão
1. Escreva o teste que reproduz o bug.
2. Prove que ele falha sem a correção: `git stash push <arquivos da correção>`, rode o teste, veja vermelho, `git stash pop`.
3. Rode de novo com a correção: verde.
Um teste que passa com e sem a correção não prova nada; reescreva.
## 4. Gate
`"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier 1` (ou o nível que o `dev-router` definiu).
## 5. Relatório
Causa em uma frase, o que mudou, o teste que prova (nome e saída vermelho/verde) e o veredito do gate.
## Não faça
- Silenciar o erro com `try/except` ou `catch` vazio.
- Mudar o teste até ele passar em vez de corrigir o código.
- Corrigir o sintoma num chamador e deixar a causa na função compartilhada.
+98
View File
@@ -0,0 +1,98 @@
---
name: wf-frontend
description: Use para trabalho de frontend e UI - componentes, páginas, layouts, estilos, design system, animação, acessibilidade, redesign de tela existente, e geração de PDF ou documento visual a partir de HTML. Fluxo DESIGN, BUILD, REVIEW com profundidade definida pelo nível do dev-router. Não use para backend ou API (wf-backend), para bug sem mudança visual (wf-bugfix) nem para refactor sem mudança de comportamento (wf-refactor).
license: MIT
metadata:
dev-workflows:
uses: [design-taste-frontend, redesign-existing-projects, lean-code, dev-router]
external: [frontend-design, web-design, vercel-react-best-practices, vercel-composition-patterns, animate, impeccable, avoid-ai-writing]
---
# Workflow Frontend
A profundidade vem do nível que o `dev-router` definiu. Cada fase diz a partir de qual nível roda.
| Nível | O que roda |
|---|---|
| 0 | só o gate (`--tier 0`) |
| 1 | ajuste de UI: siga o design system que já existe; sem DESIGN.md, sem aprovação; BUILD enxuto + gate `--tier 1` |
| 2 | tela ou componente novo: DESIGN curto, BUILD, REVIEW com `ui-critic` e `reviewer` |
| 3 | fluxo ou design system novo: DESIGN com aprovação do usuário, BUILD por tarefas, REVIEW completo |
## Skills (carregar só na fase que usa)
- **Tela nova:** `design-taste-frontend` (~35 mil tokens; só para tela nova, nunca para ajuste) e, se instalada, `frontend-design`.
- **Tela existente:** `redesign-existing-projects` (audita antes de mudar).
- **Auditoria anti "UI de IA":** `impeccable` (`/impeccable audit`, externa).
- **React/Next:** `vercel-react-best-practices` (performance), `vercel-composition-patterns` (composição).
- **Motion:** `animate`. **Microcopy:** `avoid-ai-writing`.
- Sempre: `lean-code`.
Externas são opcionais: se não estiverem instaladas, siga as regras desta página. Instalação em `docs/SKILLS.md`.
## Fase 1, DESIGN (nível 2+, tela ou componente novo)
Nível 1 pula esta fase e usa os tokens, componentes e padrões que o projeto já tem.
1. `explorer` mapeia o design system existente: tokens (cor, tipografia, espaçamento), componentes reutilizáveis, biblioteca de UI. Reaproveitar vem antes de criar.
2. Defina a direção: paleta, tipografia, densidade, claro/escuro. Tela nova usa `design-taste-frontend`; redesign usa `redesign-existing-projects`.
3. Registre as decisões em `DESIGN.md` (curto: tokens e o porquê).
4. Nível 3, ou decisão que é do usuário (identidade visual, troca de stack): pare e peça aprovação antes de codar. Nível 2 segue sem parar se a direção vem do design system existente.
Evite: gradiente roxo genérico, glassmorphism sem motivo, cards idênticos em grade, ícone decorativo sem função, dois design systems na mesma tela.
## Fase 2, BUILD (nível 1+)
1. `implementer` (ou você, em mudança pequena) implementa com `lean-code`: componente e hook existentes antes de novos; CSS e HTML nativos antes de JS.
2. **Estados em todo fluxo com dados:** carregando, vazio, erro, sucesso.
3. **Acessibilidade por padrão:** HTML semântico, foco visível e em ordem, rótulos, contraste de texto >= 4.5:1. ARIA só quando o HTML não resolve.
4. **Responsivo mobile-first**, testado em 375 px e 1280 px.
5. **Composição:** compound components em vez de explosão de props booleanas (`isX`, `showY`).
6. **Motion com propósito** (estado, entrada, feedback) e `prefers-reduced-motion` respeitado.
7. React/Next: sem waterfall de dados, sem re-render em cascata, imagem com dimensões, código dividido por rota.
8. TypeScript sem `any` nem cast forçado para "passar".
9. Rode o gate a cada componente relevante, não só no fim.
Entrada de usuário renderizada como HTML, `dangerouslySetInnerHTML`, `eval`, `postMessage` ou mudança de CSP disparam `security-auditor` (XSS/CSP).
## Fase 3, REVIEW (nível 2+)
1. `ui-critic`: screenshot em 375 e 1280, estados, a11y, padrões genéricos. Se `impeccable` estiver instalada, `/impeccable audit`.
2. `reviewer`: correção e simplicidade do diff.
3. `avoid-ai-writing` nos textos entregues ao usuário (labels, vazios, erros), se instalada.
4. Corrija o que for `bloqueante` ou `importante` e rode os dois de novo só no que mudou.
## Gate
```bash
"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier N
```
Lint, typecheck, testes, segredos e build rodam sozinhos. O que depende do app de pé (Lighthouse,
axe, bundle, regressão visual) entra como `[[check]]` no `.dev-workflows.toml` do projeto: modelos em
[references/checks.md](references/checks.md). Lista completa de checagens:
`skills/dev-router/references/quality-gate.md`.
Metas de referência (nível 2+): LCP <= 2,5 s, INP <= 200 ms (TBT como proxy em laboratório),
CLS <= 0,1; axe sem violação `serious` ou `critical`; bundle dentro do limite do `size-limit`.
O `verifier` roda o gate e devolve a evidência. Ferramenta ausente aparece como "não verificado":
diga isso ao usuário, nunca chame de testado.
## PDF e documento visual
Sempre HTML + CSS renderizado pelo Playwright (`page.pdf()`), depois cada página convertida em PNG e
inspecionada com Read: nada cortado na margem, tabela longa quebrando entre páginas. Nunca
reportlab platypus direto para tabelas longas. Método completo: [references/pdf.md](references/pdf.md).
## Aceite
- [ ] Nível declarado; fases puladas coerentes com ele.
- [ ] Nível 2+: direção registrada em `DESIGN.md` (aprovada pelo usuário no nível 3).
- [ ] Estados carregando, vazio, erro e sucesso em todo fluxo com dados.
- [ ] Acessível: semântica, foco, rótulos, contraste >= 4.5:1; axe sem `serious`/`critical` se configurado.
- [ ] Responsivo em 375 px e 1280 px, sem corte ou sobreposição.
- [ ] `prefers-reduced-motion` respeitado; animação só com propósito.
- [ ] Sem explosão de props booleanas; composição com compound components.
- [ ] Gate `pass`, ou falhas explicadas; "não verificado" listado ao usuário.
- [ ] PDF: páginas renderizadas e inspecionadas, nada cortado.
+91
View File
@@ -0,0 +1,91 @@
# Checagens de frontend para o `.dev-workflows.toml`
Estas checagens precisam do app de pé ou de configuração do projeto, por isso entram como
`[[check]]`. O gate só roda as do nível pedido ou abaixo.
```toml
[[check]]
name = "lighthouse"
cmd = "npx lhci autorun"
tier = 2
[[check]]
name = "a11y"
cmd = "npx playwright test e2e/a11y.spec.ts"
tier = 2
[[check]]
name = "bundle"
cmd = "npx size-limit"
tier = 2
[[check]]
name = "visual"
cmd = "npx playwright test e2e/visual.spec.ts"
tier = 3
```
## Lighthouse CI com orçamento (`lighthouserc.json`)
```json
{
"ci": {
"collect": { "startServerCommand": "npm run start", "url": ["http://localhost:3000/"], "numberOfRuns": 3 },
"assert": {
"assertions": {
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
"total-blocking-time": ["error", { "maxNumericValue": 200 }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
"categories:accessibility": ["error", { "minScore": 0.9 }]
}
}
}
}
```
INP só existe com usuário real; em laboratório, TBT é o proxy.
## Acessibilidade com Playwright + axe (`e2e/a11y.spec.ts`)
```ts
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";
for (const path of ["/", "/login"]) {
test(`a11y ${path}`, async ({ page }) => {
await page.goto(path);
const { violations } = await new AxeBuilder({ page }).analyze();
const graves = violations.filter(v => v.impact === "serious" || v.impact === "critical");
expect(graves).toEqual([]);
});
}
```
## Regressão visual (`e2e/visual.spec.ts`)
```ts
import { test, expect } from "@playwright/test";
for (const width of [375, 1280]) {
test(`home ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 });
await page.goto("/");
await expect(page).toHaveScreenshot(`home-${width}.png`, { fullPage: true });
});
}
```
A primeira execução grava a referência (`--update-snapshots`); as seguintes comparam.
## Bundle (`size-limit` no `package.json`)
```json
"size-limit": [{ "path": "dist/**/*.js", "limit": "200 KB" }]
```
## Screenshot rápida para o `ui-critic`
```bash
npx playwright screenshot --viewport-size=375,812 http://localhost:3000 /tmp/ui-375.png
npx playwright screenshot --viewport-size=1280,800 http://localhost:3000 /tmp/ui-1280.png
```
+49
View File
@@ -0,0 +1,49 @@
# PDF e documento visual: HTML + CSS + Playwright
Todo PDF passa por aqui: design primeiro, depois render, depois inspeção visual das páginas.
## Por que não reportlab direto
`platypus` com tabela longa estoura margem e corta linhas entre páginas. HTML + CSS de impressão
resolve quebra de página, cabeçalho repetido e margens com regras declarativas.
## 1. HTML com CSS de impressão
```css
@page { size: A4; margin: 18mm 16mm; }
table { width: 100%; border-collapse: collapse; }
thead { display: table-header-group; } /* repete o cabeçalho em cada página */
tr, img, figure { break-inside: avoid; }
h1, h2 { break-after: avoid; }
td { overflow-wrap: anywhere; } /* texto longo não empurra a margem */
```
## 2. Render com Playwright
```python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
page = p.chromium.launch().new_page()
page.goto("file:///caminho/relatorio.html")
page.pdf(path="relatorio.pdf", format="A4", print_background=True, prefer_css_page_size=True)
```
## 3. Inspeção visual obrigatória
Converta cada página em PNG e abra com Read:
```bash
pdftoppm -png -r 110 relatorio.pdf /tmp/qa/pagina
ls /tmp/qa/pagina-*.png
```
Em cada imagem, confira:
- nada cortado nas bordas (texto, tabela, imagem);
- tabela longa quebra entre páginas com o cabeçalho repetido;
- nenhuma linha órfã de título no pé da página;
- fontes carregadas (sem fallback inesperado).
Achou problema: ajuste o CSS, renderize de novo e inspecione de novo. Só entregue depois de todas as
páginas passarem.
+98
View File
@@ -0,0 +1,98 @@
---
name: wf-readme
description: Use para criar, auditar, melhorar, reescrever ou padronizar o README (e docs vizinhos como CONTRIBUTING e CHANGELOG) de um repositório. Tudo que o README afirma vem de um fato real do repo e os comandos mostrados são executados antes da entrega. Não use para docstrings, comentários de código, documentação de API gerada ou textos de UI (esses ficam com wf-frontend).
license: MIT
metadata:
dev-workflows:
uses: []
external: [readme-crafter, good-readme, curating-readme, avoid-ai-writing]
---
# Workflow README
O README é construído a partir do repositório (manifest, código, scripts, config, git), nunca de
memória. Fato sem fonte vira pergunta ao usuário.
## Escala pelo tamanho do pedido
| Pedido | Fluxo |
|---|---|
| Ajuste pontual (corrigir um comando, um link, uma seção) | editar e rodar a Fase 5 só no trecho tocado |
| README novo, reescrita ou padronização | Fases 1 a 5 |
## Skills (se instaladas)
- `readme-crafter`: classifica o projeto e sugere estrutura sob medida.
- `good-readme`: cria com exemplos reais ou audita contra uma rubrica de 22 critérios.
- `curating-readme`: padroniza README e docs vizinhos; traz o script `audit-repo.sh`.
- `avoid-ai-writing`: remove AI-isms do texto final.
Sem elas, o fluxo abaixo funciona sozinho.
## Fase 1: SCAN (fatos reais)
1. Leia o manifest (`package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`...): nome, descrição,
versão, scripts, `bin`, dependências.
2. Ache os entrypoints e o que o projeto de fato faz (CLI, rotas, exports públicos).
3. Leia o README atual, `LICENSE`, `CONTRIBUTING.md`, a CI (`.github/workflows/`) e `.env.example`.
4. Capture o contexto: `git remote -v` e `git log --oneline -5`.
5. Monte a lista de fatos, cada um com a fonte (`arquivo:linha` ou comando). O que não tem fonte vira pergunta.
## Fase 2: CLASSIFY (tipo e público)
- Tipo: biblioteca, CLI, web app, API, framework, monorepo, agente.
- Distribuição: público ou interno. Público primário: novo usuário, contribuidor, operador ou avaliador.
- Cada decisão com a fonte ("CLI porque `package.json` tem `bin`").
- Para CLI, rode o `--help` real e use essa saída como base da seção de uso.
- Se o código não revela a intenção, até 3 perguntas ao usuário.
## Fase 3: AUDIT (se já existe README)
- Compare cada afirmação com o repo: comandos, caminhos, variáveis de ambiente, versões, badges.
- Registre o que está certo, desatualizado, errado e faltando. Divergência com o código é achado, mesmo em README bonito.
- Dependência opcional apresentada como obrigatória e passo que bloqueia o primeiro uso são achados.
- Com `good-readme`, registre a nota de partida.
Sem README, siga direto para a Fase 4.
## Fase 4: GENERATE
1. Estrutura por tipo: título, badges do que existe, uma linha de descrição, o que faz, pré-requisitos,
quick start copiável, uso, configuração (tabela de env vars do `.env.example`), estrutura,
contribuição, licença. Detalhe em [references/estrutura.md](references/estrutura.md).
2. Badge só do que existe: licença com `LICENSE`, build com CI configurada, versão com pacote publicado.
3. Todo comando e exemplo mostrado precisa rodar neste repo.
4. Uma língua por arquivo; tradução vai em arquivo separado (`README.pt-BR.md`).
5. Passe `avoid-ai-writing` no texto, se instalada.
## Fase 5: VERIFY (antes de entregar)
1. **Rode os comandos** de instalação e quick start num ambiente limpo (clone novo ou diretório
temporário). O que não der para rodar (precisa de credencial, serviço externo, hardware),
liste no relatório com o motivo. Nunca escreva "testado" sobre o que não rodou.
2. **Links locais resolvem**: cada `](caminho)` aponta para arquivo que existe.
3. **Links externos respondem**: `curl -sI -o /dev/null -w '%{http_code}' <url>` em cada um.
4. **Referências existem**: arquivos, scripts, env vars e flags citados estão no repo.
5. **Índice bate** com os headings, se houver índice.
6. Nenhum `TODO:` sobrou no texto final.
Comandos prontos: [references/verificacao.md](references/verificacao.md).
## Relatório
O que mudou, os achados da auditoria (antes e depois), os comandos executados com o resultado e o
que não pôde ser verificado.
## Não faça
- Inventar instalação, comando, exemplo, screenshot ou feature.
- Copiar a estrutura de outro projeto sem adaptar ao tipo e ao público.
- Duplicar a mesma informação em duas seções.
- Encher de emojis ou badges decorativos.
## Critério de aceite
- [ ] Toda afirmação tem fonte no repo ou virou pergunta respondida.
- [ ] Comandos de instalação e quick start executados, ou listados como não verificáveis com motivo.
- [ ] Links locais e externos resolvem; arquivos citados existem.
- [ ] Badges só do que existe; nenhum `TODO:` no texto final.
+30
View File
@@ -0,0 +1,30 @@
# Estrutura do README por tipo
Ordem base. Corte a seção que não se aplica em vez de preencher com texto genérico.
| Seção | Fonte no repo | Obrigatória para |
|---|---|---|
| Título e uma linha de descrição | `name`/`description` do manifest | todos |
| Badges | `LICENSE`, `.github/workflows/`, registro do pacote | só o que existe |
| O que faz | entrypoints, exports, rotas | todos |
| Pré-requisitos | `engines`, `requires-python`, `go` no `go.mod`, Dockerfile | todos |
| Quick start | scripts do manifest, `Makefile` | todos |
| Uso | saída real do `--help`, exemplos que rodam | CLI, biblioteca |
| API | exports públicos, OpenAPI | biblioteca, API |
| Configuração | `.env.example`, arquivo de config | quem tem env vars |
| Estrutura do projeto | árvore real (`git ls-files`) | monorepo, app |
| Contribuição | `CONTRIBUTING.md`, comandos de teste e lint | open source |
| Licença | `LICENSE` | todos |
## Por tipo
- **Biblioteca**: instalação pelo gerenciador, um exemplo mínimo que roda, link para a API.
- **CLI**: instalação, `--help` real, dois ou três comandos comuns com a saída.
- **Web app**: pré-requisitos, `.env`, como subir em dev, como rodar os testes.
- **API**: como subir, onde está o OpenAPI, autenticação, um `curl` que funciona.
- **Monorepo**: tabela de pacotes com uma linha cada e o comando para rodar todos.
## Quick start
Copiável de ponta a ponta: clonar, instalar, configurar, rodar, ver o primeiro resultado.
Dependência opcional fica fora do caminho principal, numa seção à parte.
@@ -0,0 +1,25 @@
# Comandos de verificação do README
Rode da raiz do repositório.
```bash
# Links locais que não existem no disco
grep -oE '\]\([^)#]+' README.md | sed 's/^](//' | grep -vE '^(https?:|mailto:)' \
| while read -r p; do [ -e "$p" ] || echo "FALTA: $p"; done
# Links externos que não respondem 2xx/3xx
grep -oE 'https?://[^) >"]+' README.md | sort -u | while read -r u; do
c=$(curl -sIL -o /dev/null -w '%{http_code}' --max-time 10 "$u")
case "$c" in 2*|3*) ;; *) echo "$c $u";; esac
done
# TODO esquecido
grep -n 'TODO' README.md
# Quick start num clone limpo (troque pelos comandos do README)
tmp=$(mktemp -d) && git clone -q . "$tmp/repo" && cd "$tmp/repo"
# ... cole aqui os comandos de instalação e quick start, na ordem do README
```
Para CLI, compare a seção de uso com `<cli> --help`. Para API, rode o `curl` do README contra o
servidor local e confira o status. Anote no relatório cada comando e o resultado.
+38
View File
@@ -0,0 +1,38 @@
---
name: wf-refactor
description: Use para refatorar, reorganizar, renomear, extrair, simplificar ou limpar código sem mudar o comportamento. Congela o comportamento com testes antes de mexer e mexe em passos pequenos.
license: MIT
metadata:
dev-workflows:
uses: []
external: []
---
# Workflow Refactor
## 1. Rede de segurança
Os testes atuais cobrem o comportamento que você vai tocar? Se não, escreva **testes de
caracterização** antes de mudar qualquer coisa: eles registram o que o código faz hoje, mesmo que
pareça estranho. Rode e confirme que estão verdes.
## 2. Passos pequenos
Cada passo deixa o código compilando e os testes verdes. Rode os testes a cada passo, não só no fim.
Renomeação: procure também em strings, configs, rotas e docs (`grep -rn`), não só nos imports.
## 3. Comportamento não muda
Os testes de caracterização não são editados. Se você precisa editar um deles, a mudança não é
refactor: pare e pergunte ao usuário.
## 4. Gate e relatório
`"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier 1` (nível 2 se o refactor atravessa módulos).
No relatório, as linhas líquidas: um bom refactor costuma reduzir. Se aumentou, explique.
## Não faça
- Misturar refactor com feature ou correção de bug no mesmo diff.
- Mudar API pública sem o usuário pedir.
- Criar camada ou abstração nova "para ficar mais limpo" sem um uso concreto hoje.
+104
View File
@@ -0,0 +1,104 @@
---
name: wf-security-review
description: Use para revisão de segurança de código, diff ou PR (frontend e backend), para varrer dependências atrás de CVE, procurar segredos commitados ou auditar auth, API e injeção; também quando o dev-router dispara um gatilho de segurança (auth, dinheiro, dados pessoais, upload, SQL montado à mão, dependência nova, feature com LLM). Consulta fontes vivas de vulnerabilidade com data. Não use para revisão de correção ou estilo sem aspecto de segurança (isso é o agente reviewer) nem para desenhar arquitetura (wf-architecture).
license: MIT
metadata:
dev-workflows:
uses: [safedeps, sca-audit, code-review-security, secrets-scan, api-security-review, web-security-review, cve-triage, patch-prioritization, dependency-scanning, hermaguard]
external: [bola-detector, injection-checker, auth-rbac-scaffold]
---
# Workflow Security Review
O conhecimento de CVE do modelo para na data de corte do treino. Por isso toda revisão consulta
fontes vivas (OSV.dev, GitHub Advisory Database, NVD, CISA KEV) e registra a data da consulta.
**Nunca afirme "sem CVE" sem ter consultado.** Uma revisão sem fonte e sem data já nasce vencida.
Este workflow vem pré-carregado no agente `security-auditor`.
## Profundidade por nível (do `dev-router`)
| Nível | Escopo | Padrão | Ferramentas |
|---|---|---|---|
| 1 com gatilho | só o diff | Top 10 no que o diff toca | gate `--tier 1` (gitleaks, semgrep) |
| 2 | diff + superfície alcançável (rotas, handlers, queries, componentes que usam o código alterado) | ASVS 5.0 L1 | gate `--tier 2` (+ osv-scanner), `safedeps` em toda dependência nova |
| 3 ou auditoria completa | toda a superfície | ASVS 5.0 L2 | gate `--tier 3` (+ trivy), passe adversarial do `hermaguard`, STRIDE contra a arquitetura |
Gate: `"${CLAUDE_PLUGIN_ROOT}/scripts/quality-gate" --tier N`. Checagens e configuração em
[../dev-router/references/quality-gate.md](../dev-router/references/quality-gate.md). Os scanners
são ponto de partida, não substituem a leitura do código.
## Fase 1: SCOPE
1. Delimite o alvo: `git diff --stat <base>` e arquivos não rastreados; front, back ou os dois.
2. Registre a stack, os gerenciadores de pacote e os lockfiles (`package-lock.json`, `pnpm-lock.yaml`, `requirements.txt`, `poetry.lock`, `go.mod`, `Cargo.lock`).
3. No nível 2 ou mais, mapeie a superfície alcançável: quem chama o código alterado e o que fica exposto (rota, fila, webhook, UI).
## Fase 2: HUNT (dependências)
1. `safedeps` nas dependências novas ou alteradas, com versão e ecossistema:
`python3 "${CLAUDE_PLUGIN_ROOT}/skills/safedeps/check_deps.py" [email protected]:npm`
ou o manifest inteiro: `python3 "${CLAUDE_PLUGIN_ROOT}/skills/safedeps/check_deps.py" requirements.txt`.
2. `sca-audit` para alcance (reachability): a função vulnerável é chamada pelo projeto?
3. `cve-triage` e `patch-prioritization` para ordenar por CVSS 4.0, EPSS e CISA KEV.
4. Separe **alcançável** (bloqueia) de **não alcançável** (risco residual registrado).
## Fase 3: CONSULT (fontes vivas)
Responda "há vulnerabilidade nova que eu não conheço?" consultando, com data:
- OSV.dev (já coberto pelo `safedeps`; batch: `POST https://api.osv.dev/v1/querybatch`).
- GitHub Advisory Database: `gh api graphql -f query='{securityAdvisories(first:10, orderBy:{field:PUBLISHED_AT,direction:DESC}){nodes{ghsaId summary severity publishedAt}}}'`.
- NVD: `curl -s "https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=<framework>&resultsPerPage=10"`.
- CISA KEV para saber se já há exploração ativa.
- Página de security ou changelog do framework em uso.
Vulnerabilidade nova que afeta a versão do projeto vira achado HIGH, com a versão de correção.
## Fase 4: CODE REVIEW
Referências atuais: **OWASP Top 10:2025**, **OWASP API Security Top 10 (2023)**, **ASVS 5.0** e,
se a feature chama um LLM, **OWASP LLM Top 10 (2025)**. As skills OWASP vendorizadas ainda citam o
Top 10 de 2021; use o mapa 2021 para 2025 em [references/owasp-2025.md](references/owasp-2025.md).
**Frontend** (`web-security-review`, `code-review-security`):
- renderização de HTML com entrada do usuário (`dangerouslySetInnerHTML`, `v-html`, `innerHTML`);
- segredo no bundle do cliente; token em `localStorage` (prefira cookie `httpOnly`, `Secure`, `SameSite`);
- CSP, links e redirecionamentos montados com entrada do usuário.
**Backend** (`code-review-security`, `api-security-review`; se instaladas, `bola-detector`, `injection-checker`, `auth-rbac-scaffold`):
- autenticação e autorização por objeto (BOLA/IDOR): a query é escopada pelo usuário autenticado?
- injeção: SQL, ORM cru, shell, template, path traversal; SSRF (agora dentro de A01);
- tratamento de condição excepcional (A10:2025): erro que falha aberto, exceção engolida, stack trace na resposta;
- rate limit em escrita e login, CORS com allowlist explícita, segredo nunca em log.
**Segredos**: `secrets-scan` no diff e no histórico (`git log -p -S "<padrão>"`); o gitleaks do gate cobre os arquivos alterados.
**Cadeia de suprimentos** (A03:2025): dependência nova justificada, lockfile commitado, scripts de
instalação suspeitos, versões fixadas no CI.
**Nível 3**: rode o `hermaguard` no diff (edge cases, ataque, blast radius) e confira o threat model
STRIDE do `wf-architecture`: cada ameaça tem mitigação no código?
Cada achado: severidade (CRITICAL, HIGH, MEDIUM, LOW), CWE, referência OWASP, `arquivo:linha`,
passos de exploração, impacto e correção. Diferencie confirmado de suspeita. "Não achei com grep"
não é "não existe": siga o fluxo.
## Fase 5: REPORT + GATE
Relatório com: cabeçalho (nível, escopo, padrão ASVS e a linha "consulta de atualização feita em
<AAAA-MM-DD> via <fontes>"), resumo por severidade, decisão do gate, os achados, tabela de
dependências (pacote, versão, CVE, severidade, corrigida em, alcançável, fonte), veredito do gate de
qualidade com o que ficou não verificado, e riscos aceitos.
Regra do gate: **CRITICAL ou HIGH alcançável em aberto = não aprovado.** MEDIUM entra no próximo
ciclo; LOW e residual ficam registrados como risco aceito. Depois de cada correção, rode de novo a
checagem que acusou o problema e o gate no mesmo nível.
## Regras duras
- Nunca "sem vulnerabilidades" sem consulta a fonte viva com data.
- Nunca CVE sem versão afetada e versão corrigida.
- Nunca expor um segredo encontrado no relatório: cite arquivo, linha e tipo, com o valor mascarado.
- Queries sempre parametrizadas, nunca concatenadas com entrada.
- Correção que muda dependência ou mais de 3 arquivos: nova rodada de revisão.
@@ -0,0 +1,48 @@
# Referências OWASP atuais
Confira a lista oficial em https://owasp.org/Top10/ se houver dúvida de nome ou ordem.
## Top 10:2021 (usado pelas skills vendorizadas) para Top 10:2025
| 2021 | 2025 | Observação |
|---|---|---|
| A01 Broken Access Control | A01 Broken Access Control | agora inclui SSRF |
| A02 Cryptographic Failures | A04 Cryptographic Failures | |
| A03 Injection | A05 Injection | XSS continua aqui |
| A04 Insecure Design | A06 Insecure Design | |
| A05 Security Misconfiguration | A02 Security Misconfiguration | subiu |
| A06 Vulnerable and Outdated Components | A03 Software Supply Chain Failures | **ampliada**: build, CI, registro de pacotes, dependências |
| A07 Identification and Authentication Failures | A07 Authentication Failures | |
| A08 Software and Data Integrity Failures | A08 Software or Data Integrity Failures | |
| A09 Security Logging and Monitoring Failures | A09 Security Logging and Alerting Failures | |
| A10 Server-Side Request Forgery | (dentro de A01) | |
| n/a | A10 Mishandling of Exceptional Conditions | **nova**: erro que falha aberto, exceção engolida, estado inconsistente após falha |
## API Security Top 10 (2023)
API1 Broken Object Level Authorization · API2 Broken Authentication · API3 Broken Object Property
Level Authorization · API4 Unrestricted Resource Consumption · API5 Broken Function Level
Authorization · API6 Unrestricted Access to Sensitive Business Flows · API7 Server Side Request
Forgery · API8 Security Misconfiguration · API9 Improper Inventory Management · API10 Unsafe
Consumption of APIs.
## ASVS 5.0 (maio de 2025)
Checklist por nível, mais de 300 requisitos em 17 capítulos (inclui segurança de frontend web e tokens
autocontidos). Use o nível que o `dev-router` definiu:
- **L1** (nível 2): o mínimo para qualquer aplicação exposta.
- **L2** (nível 3): aplicação com dados sensíveis ou transações; o padrão recomendado para a maioria.
- **L3**: só com pedido explícito (dado crítico, alto valor).
Fonte: https://github.com/OWASP/ASVS
## LLM Top 10 (2025), para features que chamam um LLM
LLM01 Prompt Injection · LLM02 Sensitive Information Disclosure · LLM03 Supply Chain · LLM04 Data and
Model Poisoning · LLM05 Improper Output Handling · LLM06 Excessive Agency · LLM07 System Prompt
Leakage · LLM08 Vector and Embedding Weaknesses · LLM09 Misinformation · LLM10 Unbounded Consumption.
O mais comum em código de aplicação: saída do modelo usada sem validação (LLM05), ferramentas ou
permissões demais para o agente (LLM06), segredo ou dado de outro usuário no prompt (LLM02) e custo
sem limite (LLM10).