crewforth 0.0.1 → 3.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3784 -0
- package/LICENSE +21 -0
- package/README.md +37 -7
- package/VERSION +1 -0
- package/adopt.sh +1670 -0
- package/bin/cli.js +497 -0
- package/kit/AGENT_TEMPLATE.md +92 -0
- package/kit/CLAUDE.md +228 -0
- package/kit/README.md +107 -0
- package/kit/agents/crew-backend-expert.md +95 -0
- package/kit/agents/crew-commit-agent.md +96 -0
- package/kit/agents/crew-database-expert.md +84 -0
- package/kit/agents/crew-devops-expert.md +82 -0
- package/kit/agents/crew-frontend-expert.md +85 -0
- package/kit/agents/crew-performance-expert.md +78 -0
- package/kit/agents/crew-planner.md +60 -0
- package/kit/agents/crew-privacy-agent.md +71 -0
- package/kit/agents/crew-review-agent.md +95 -0
- package/kit/agents/crew-security-expert.md +73 -0
- package/kit/agents/crew-session-manager.md +77 -0
- package/kit/agents/crew-test-expert.md +64 -0
- package/kit/eval/doctor.sh +465 -0
- package/kit/eval/gate-report.sh +137 -0
- package/kit/eval/golden-holdout.txt +53 -0
- package/kit/eval/golden-routing.txt +199 -0
- package/kit/eval/lib/crew-env.sh +14 -0
- package/kit/eval/lib/settings-json.awk +154 -0
- package/kit/eval/lib/star.sh +70 -0
- package/kit/eval/parser-conformance.sh +612 -0
- package/kit/eval/preflight.sh +186 -0
- package/kit/eval/routing-eval.sh +209 -0
- package/kit/eval/scan-skill.sh +162 -0
- package/kit/eval/smoke-test.sh +6693 -0
- package/kit/eval/update-guard.sh +81 -0
- package/kit/eval/utilization.sh +130 -0
- package/kit/hooks/board-sync.sh +106 -0
- package/kit/hooks/board.sh +962 -0
- package/kit/hooks/commit-msg +49 -0
- package/kit/hooks/context-usage.sh +353 -0
- package/kit/hooks/floor-blocklist.txt +124 -0
- package/kit/hooks/guard-bash.sh +1431 -0
- package/kit/hooks/guard-commit-scan.sh +511 -0
- package/kit/hooks/guard-write.sh +513 -0
- package/kit/hooks/pre-commit +577 -0
- package/kit/hooks/route-hint.sh +185 -0
- package/kit/hooks/secret-blocklist.txt +82 -0
- package/kit/hooks/session-guard.sh +149 -0
- package/kit/hooks/session-rehydrate.sh +41 -0
- package/kit/hooks/session-stats.sh +252 -0
- package/kit/hooks/session-update-check.sh +236 -0
- package/kit/hooks/skill-trust.sh +150 -0
- package/kit/hooks/trace-blocklist.txt +53 -0
- package/kit/settings.json +132 -0
- package/kit/skills/a11y/SKILL.md +44 -0
- package/kit/skills/adr/SKILL.md +74 -0
- package/kit/skills/api-design/SKILL.md +50 -0
- package/kit/skills/automode-policy/SKILL.md +91 -0
- package/kit/skills/automode-policy/references/policy.json +13 -0
- package/kit/skills/automode-policy/scripts/apply.sh +84 -0
- package/kit/skills/automode-policy/scripts/check.sh +102 -0
- package/kit/skills/backend-architecture/SKILL.md +103 -0
- package/kit/skills/brainstorm/SKILL.md +47 -0
- package/kit/skills/ci-pipeline/SKILL.md +38 -0
- package/kit/skills/commit-message/SKILL.md +82 -0
- package/kit/skills/commit-message/references/examples.md +8 -0
- package/kit/skills/confidence-check/SKILL.md +86 -0
- package/kit/skills/crew-board/SKILL.md +55 -0
- package/kit/skills/crew-brainstorm/SKILL.md +19 -0
- package/kit/skills/crew-code-review/SKILL.md +151 -0
- package/kit/skills/crew-code-review/references/history-search.md +19 -0
- package/kit/skills/crew-code-review/references/panel-mode.md +32 -0
- package/kit/skills/crew-code-review/references/receiving.md +23 -0
- package/kit/skills/crew-doctor/SKILL.md +36 -0
- package/kit/skills/crew-gates/SKILL.md +25 -0
- package/kit/skills/crew-handoff/SKILL.md +14 -0
- package/kit/skills/crew-plan/SKILL.md +18 -0
- package/kit/skills/crew-review/SKILL.md +23 -0
- package/kit/skills/crew-ship/SKILL.md +19 -0
- package/kit/skills/crew-skill/SKILL.md +61 -0
- package/kit/skills/crew-studio/SKILL.md +129 -0
- package/kit/skills/crew-update/SKILL.md +43 -0
- package/kit/skills/db-migration/SKILL.md +120 -0
- package/kit/skills/db-migration/references/backup-restore.md +33 -0
- package/kit/skills/db-migration/references/raw-sql.md +30 -0
- package/kit/skills/db-migration/references/tool-matrix.md +35 -0
- package/kit/skills/dependency-audit/SKILL.md +61 -0
- package/kit/skills/dependency-upgrade/SKILL.md +82 -0
- package/kit/skills/deploy/SKILL.md +100 -0
- package/kit/skills/deploy/references/proxy-ssl.md +56 -0
- package/kit/skills/deploy/references/rollback.md +18 -0
- package/kit/skills/deploy/references/scripts.md +9 -0
- package/kit/skills/deploy/references/topology-a.md +128 -0
- package/kit/skills/deploy/references/topology-b.md +44 -0
- package/kit/skills/docs-writer/SKILL.md +53 -0
- package/kit/skills/docs-writer/references/coauthoring.md +34 -0
- package/kit/skills/eval-grader/SKILL.md +75 -0
- package/kit/skills/eval-grader/references/method.md +51 -0
- package/kit/skills/frontend/SKILL.md +56 -0
- package/kit/skills/frontend/references/verify-contract.md +41 -0
- package/kit/skills/frontend-design/SKILL.md +71 -0
- package/kit/skills/frontend-design/references/design-review.md +34 -0
- package/kit/skills/frontend-rn-expo/SKILL.md +25 -0
- package/kit/skills/handoff/SKILL.md +71 -0
- package/kit/skills/handoff/references/cold-reader.md +51 -0
- package/kit/skills/i18n-integrity/SKILL.md +31 -0
- package/kit/skills/incident-runbook/SKILL.md +40 -0
- package/kit/skills/incident-runbook/references/postmortem.md +16 -0
- package/kit/skills/iterate/SKILL.md +40 -0
- package/kit/skills/mcp-builder/SKILL.md +54 -0
- package/kit/skills/mcp-builder/references/building.md +71 -0
- package/kit/skills/observability/SKILL.md +50 -0
- package/kit/skills/performance/SKILL.md +38 -0
- package/kit/skills/performance/references/bottlenecks.md +10 -0
- package/kit/skills/privacy-compliance/SKILL.md +75 -0
- package/kit/skills/red-team/SKILL.md +48 -0
- package/kit/skills/reflect/SKILL.md +57 -0
- package/kit/skills/release/SKILL.md +44 -0
- package/kit/skills/security-scan/SKILL.md +99 -0
- package/kit/skills/security-scan/references/ai-agents.md +107 -0
- package/kit/skills/security-scan/references/fronts.md +99 -0
- package/kit/skills/security-scan/references/prompting.md +23 -0
- package/kit/skills/security-scan/references/reporting.md +75 -0
- package/kit/skills/security-scan/references/verify.md +131 -0
- package/kit/skills/sonarqube-check/SKILL.md +108 -0
- package/kit/skills/sonarqube-check/references/local-engines.md +32 -0
- package/kit/skills/sonarqube-check/references/stand-up-server.md +25 -0
- package/kit/skills/spec-planning/SKILL.md +92 -0
- package/kit/skills/systematic-debugging/SKILL.md +57 -0
- package/kit/skills/systematic-debugging/references/techniques.md +44 -0
- package/kit/skills/teamboard/SKILL.md +88 -0
- package/kit/skills/teamboard/references/setup.md +37 -0
- package/kit/skills/testing/SKILL.md +49 -0
- package/kit/skills/testing/references/flaky-triage.md +51 -0
- package/kit/skills/threat-model/SKILL.md +57 -0
- package/kit/skills/threat-model/references/interview.md +51 -0
- package/kit/skills/threat-model/references/schema.md +42 -0
- package/kit/skills/token-budget/SKILL.md +51 -0
- package/kit/skills/trace-scan/SKILL.md +43 -0
- package/kit/skills/worktree/SKILL.md +40 -0
- package/kit/studio/README.md +266 -0
- package/kit/studio/ensure-node.sh +471 -0
- package/kit/studio/package.json +14 -0
- package/kit/studio/server/hooks/studio-gate.sh +169 -0
- package/kit/studio/server/index.js +902 -0
- package/kit/studio/server/lib/crew-env.js +11 -0
- package/kit/studio/server/lib/fleet.js +146 -0
- package/kit/studio/server/lib/graph.js +533 -0
- package/kit/studio/server/lib/instance.js +135 -0
- package/kit/studio/server/lib/kit-telemetry.js +182 -0
- package/kit/studio/server/lib/kit.js +158 -0
- package/kit/studio/server/lib/palette.js +118 -0
- package/kit/studio/server/lib/peers.js +72 -0
- package/kit/studio/server/lib/permissions.js +150 -0
- package/kit/studio/server/lib/projects.js +294 -0
- package/kit/studio/server/lib/roster.js +191 -0
- package/kit/studio/server/lib/session.js +309 -0
- package/kit/studio/server/lib/terminal.js +91 -0
- package/kit/studio/server/lib/transcript.js +100 -0
- package/kit/studio/web/app.js +1098 -0
- package/kit/studio/web/canvas.js +1179 -0
- package/kit/studio/web/chat.js +543 -0
- package/kit/studio/web/index.html +86 -0
- package/kit/studio/web/md.js +110 -0
- package/kit/studio/web/storage-migrate.js +23 -0
- package/kit/studio/web/style.css +1453 -0
- package/package.json +46 -8
- package/start.sh +748 -0
- package/bin/crewforth.js +0 -10
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Front 5 — AI, agent and MCP code
|
|
2
|
+
|
|
3
|
+
Read this front when the code under review builds on a model: it assembles prompts, retrieves context, stores
|
|
4
|
+
memory, exposes or calls tools, delegates to sub-agents, or speaks MCP. It is about the CODE around the model. For
|
|
5
|
+
testing whether a deployed agent's defences hold under attack, that is `red-team`.
|
|
6
|
+
|
|
7
|
+
## The rule that decides what counts
|
|
8
|
+
|
|
9
|
+
**Persuasive text is not a vulnerability. A missing deterministic control is.** A model can always be talked into
|
|
10
|
+
something; that alone proves nothing about the system. A finding here needs a boundary that code failed to hold:
|
|
11
|
+
content reached another principal's context, an action ran with authority the requester did not have, data was
|
|
12
|
+
disclosed to someone who could not read it, or a sink was driven that the attacker could not reach directly.
|
|
13
|
+
|
|
14
|
+
Three consequences follow, and they rule out most false positives in this front:
|
|
15
|
+
|
|
16
|
+
- **Instructions in a prompt guard nothing.** "The system prompt forbids it" is not a control. Count only what
|
|
17
|
+
a deterministic path enforces: authorization scoped to the resource, isolation, binding, constrained
|
|
18
|
+
credentials.
|
|
19
|
+
- **Everything the model reads or writes is untrusted input** — its own output, retrieved documents, memory, tool
|
|
20
|
+
descriptions, MCP responses. Point to the line of code that trusts it.
|
|
21
|
+
- **Using your own authority on purpose is not a defect.** A user who asks the agent to do something they are
|
|
22
|
+
allowed to do has not been attacked because a model carried it out.
|
|
23
|
+
|
|
24
|
+
Name, for every candidate: the attacker, the affected principal, the identity the action actually ran as, the
|
|
25
|
+
resource, the exact action, the authority used, and the result someone can observe.
|
|
26
|
+
|
|
27
|
+
## Where it breaks
|
|
28
|
+
|
|
29
|
+
### Context, retrieval and memory
|
|
30
|
+
- **Injected content reaching someone else's context.** Who can write each retrieved source — a document, page,
|
|
31
|
+
ticket, email, tool result — and whose session ends up reading it? Check that retrieval is scoped to the reader,
|
|
32
|
+
not just that the content looks benign.
|
|
33
|
+
- **Context bleeding across sessions or tenants.** History, embeddings, retrieval results and prompt caches keyed
|
|
34
|
+
too broadly. A tenant field on the record is not enforcement if one query path or one cache key leaves it out.
|
|
35
|
+
- **Memory that turns low-trust observations into durable instructions.** Content an attacker influenced, or a
|
|
36
|
+
model's own summary of it, written into memory that later steers another user or a privileged task. Who may
|
|
37
|
+
create, merge and delete memory, and does retrieval tell a user's preference apart from policy? A note a user
|
|
38
|
+
keeps for themself, read back only by that user, crosses no boundary.
|
|
39
|
+
- **Forged provenance.** Prompt assembly that lets untrusted text pass as a system message, an earlier turn, a tool
|
|
40
|
+
result or a memory record — string concatenation, untyped history, a caller-supplied role field. It matters when
|
|
41
|
+
the forged label changes a trust decision or unlocks a capability.
|
|
42
|
+
|
|
43
|
+
### Tools and actions
|
|
44
|
+
- **Model-written arguments reaching a sink unchecked.** A tool schema shapes input; it does not authorize a path,
|
|
45
|
+
a URL, a query or a resource id. Follow each argument from the decoded call to the SQL, shell, file or network
|
|
46
|
+
call, and look for the handler's own validation.
|
|
47
|
+
- **Confused deputy.** The agent acts with a broad service credential and the handler never re-checks whether the
|
|
48
|
+
requesting principal may touch that resource. Ask what that user could already do without the agent. One service
|
|
49
|
+
credential is fine when every call made with it is still scoped to the requester.
|
|
50
|
+
- **Approval that does not bind the action.** The user approves one described action, and execution can use
|
|
51
|
+
different arguments, a different target, a later turn, a retry or a resumed session. Or attacker content triggers
|
|
52
|
+
a side effect under the victim's valid authority that the victim never asked for — generic permission does not
|
|
53
|
+
make that intentional. The approval has to bind the normalized tool name, the complete argument object, the
|
|
54
|
+
requester and the target.
|
|
55
|
+
- **Schema and handler disagreeing.** Validation and the handler read one input two ways: an alias, a repeated or
|
|
56
|
+
unexpected key, a type that gets coerced, a free-form nested object, a value out of range. Validate again where a value
|
|
57
|
+
becomes a resource selector or a security option.
|
|
58
|
+
- **Delegated loops with no ceiling.** A bounded request that can enqueue unbounded spend, sends, mutations or
|
|
59
|
+
external calls — no per-request budget, no per-action check, no cancellation, no idempotency. Establish it from
|
|
60
|
+
the code and a locally bounded loop, never by exhausting a real service.
|
|
61
|
+
|
|
62
|
+
### MCP and sub-agents
|
|
63
|
+
- **Delegation that hands over everything.** A sub-agent or MCP call receives the whole session, its credentials,
|
|
64
|
+
its memory, rather than the least authority the task needs; or its result is trusted on return.
|
|
65
|
+
- **Identity by name instead of by connection.** Calls or results routed by a server name, tool name, request id,
|
|
66
|
+
resource URI or a model-chosen alias that an attacker can influence, instead of the authenticated connection and
|
|
67
|
+
the pending request. Can two servers claim one tool? Does a reconnect change the binding? Can one server's
|
|
68
|
+
response satisfy another's pending call?
|
|
69
|
+
- **Metadata treated as policy.** Whatever an MCP peer says about itself — tool text, resource details, suggested
|
|
70
|
+
prompts, schemas, completions — can steer the model and can never grant it anything. Find the allowlist, the server
|
|
71
|
+
identity check and the handler authorization that stay authoritative when the metadata says otherwise.
|
|
72
|
+
|
|
73
|
+
### Output and disclosure
|
|
74
|
+
- **Model output rendered unencoded.** Output reaching HTML, Markdown, a template, a URL or a command without that
|
|
75
|
+
sink's encoding. Whether a renderer outside the repository sanitizes it is a fact you do not have — that makes
|
|
76
|
+
the candidate CANNOT_VERIFY, not confirmed.
|
|
77
|
+
- **Secrets extractable from the assembled context.** Credentials, another user's data or access-granting policy
|
|
78
|
+
values placed in context that user-influenced output can reveal. Leaking generic instructions crosses no
|
|
79
|
+
boundary and is not a finding.
|
|
80
|
+
|
|
81
|
+
## How to hunt it
|
|
82
|
+
|
|
83
|
+
Before opening single files, make four inventories: the identities code runs under, the capabilities it holds, the
|
|
84
|
+
context and memory stores something can write into, and the destinations output reaches. Then trace each request
|
|
85
|
+
from the one who made it to the power finally used on its behalf. From each tool with side effects, walk back
|
|
86
|
+
through dispatch, schema, confirmation, context, retrieval and ingestion; from each memory read, walk back to
|
|
87
|
+
everyone who writes there. One action can arrive directly, from a queue, as a retry, a resumed run, a batch or
|
|
88
|
+
through a delegate — the deciding check belongs after the arguments are fixed and before anything happens, on every
|
|
89
|
+
one of those routes.
|
|
90
|
+
|
|
91
|
+
## Before a finding here leaves the verifier
|
|
92
|
+
|
|
93
|
+
Apply `verify.md` as usual, plus:
|
|
94
|
+
|
|
95
|
+
1. It says which boundary was crossed and what anyone can see afterwards: who attacks, who (or which shared
|
|
96
|
+
resource) is harmed, the identity the action ran as, the target, and the action or disclosure nobody authorized
|
|
97
|
+
or asked for.
|
|
98
|
+
2. A confused-deputy claim shows two things: the handler never checks the requester against the resource, AND the
|
|
99
|
+
attacker has no way to do the same through the product itself. An action-binding claim shows instead that
|
|
100
|
+
content the attacker controlled set off an action, carried out with the victim's authority, that the victim did
|
|
101
|
+
not mean to request or approve.
|
|
102
|
+
3. A memory or retrieval claim shows both halves: where the attacker writes, and where another principal or a
|
|
103
|
+
privileged decision later reads. A shared record that nothing reads across a boundary does not qualify.
|
|
104
|
+
4. An MCP identity claim looks at four things: which connection is authenticated, how a response is matched to its
|
|
105
|
+
request, how tool names are namespaced, and which credential is actually used. When the answer depends on
|
|
106
|
+
routing done by an outside server or the deployment, the verdict is CANNOT_VERIFY, naming the one fact that
|
|
107
|
+
would decide it.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Review fronts
|
|
2
|
+
|
|
3
|
+
The scan applies the **source → gate → sink** model on these fronts. Read the fronts you're scanning.
|
|
4
|
+
|
|
5
|
+
## Front 0 — Discovery (map the surface)
|
|
6
|
+
|
|
7
|
+
The rest of the audit rests on the map produced here.
|
|
8
|
+
|
|
9
|
+
1. Scan for manifest/build files at the root and in subdirectories: `package.json`, `requirements.txt`, `pyproject.toml`, `go.mod`, `Cargo.toml`, `Gemfile`, `pom.xml`, `build.gradle`, `composer.json`, `*.csproj`, `*.sln`, `mix.exs`. In a monorepo, note each ecosystem separately.
|
|
10
|
+
2. Derive the framework and runtime from the manifest.
|
|
11
|
+
3. **List the attack surface:** all the points where user input enters the system (the "Source" list above). These are the starting points for the following fronts.
|
|
12
|
+
4. Run a **web search** for the detected framework — tooling and patterns change often: `"[framework] security best practices"`, `"[framework] common vulnerabilities"`, the current `"OWASP Top 10"` list.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Front 1 — Dependencies
|
|
17
|
+
|
|
18
|
+
Known vulnerabilities in third-party packages are the cheapest path to most breaches.
|
|
19
|
+
|
|
20
|
+
1. Run the audit command that suits the ecosystem (if it is not installed, suggest installing it, do not install it yourself):
|
|
21
|
+
|
|
22
|
+
| Ecosystem | Command |
|
|
23
|
+
|---|---|
|
|
24
|
+
| Node | `npm audit` · `pnpm audit` · `yarn npm audit` |
|
|
25
|
+
| Python | `pip-audit` |
|
|
26
|
+
| .NET | `dotnet list package --vulnerable --include-transitive` |
|
|
27
|
+
| Rust | `cargo audit` |
|
|
28
|
+
| Go | `govulncheck ./...` |
|
|
29
|
+
| Ruby | `bundle audit` |
|
|
30
|
+
| Java | OWASP Dependency-Check |
|
|
31
|
+
|
|
32
|
+
2. If you are unsure of the correct/current command, verify it on the web; where possible, get machine-readable output with `--json`.
|
|
33
|
+
3. Extract from each finding: package · installed version · vulnerability id (CVE/GHSA) · severity · fixed version.
|
|
34
|
+
4. In a monorepo, audit each sub-project separately. The results go into the report (below).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Front 2 — Code (source→sink tracing)
|
|
39
|
+
|
|
40
|
+
Start from every entry point on the attack surface, trace the input to where it is used, and check whether there is a gate in between. The table below is the **minimum** coverage — if you see another sink during the scan, add it.
|
|
41
|
+
|
|
42
|
+
| Sink class | Vulnerability | What the "gate" should be |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| **Query** | SQL / NoSQL / LDAP / ORM raw query injection | Parameterized query; no string concatenation |
|
|
45
|
+
| **Command** | Shell/OS command injection | Argument array; no passing a string to the shell |
|
|
46
|
+
| **Render** | XSS (input in HTML without escaping), SSTI (input as template code) | Context-appropriate escaping; input as data, not code |
|
|
47
|
+
| **Path** | Path traversal, unrestricted file upload | Path allowlist/normalization; type-size-content validation |
|
|
48
|
+
| **Object** | Insecure deserialization, mass assignment | Safe format; field allowlist |
|
|
49
|
+
| **Expression** | Expression/eval injection, `eval`/`exec` | Never evaluate input as code |
|
|
50
|
+
|
|
51
|
+
**On state-changing + browser-originating endpoints, additionally:**
|
|
52
|
+
- **CSRF** — does the state-changing endpoint have token protection?
|
|
53
|
+
- **CORS** — is there a wildcard origin with credentials, or an origin reflected without validation?
|
|
54
|
+
|
|
55
|
+
**Secret leakage — hardcoded credentials in the source:** search for these patterns, excluding `.env.example` and test fixtures:
|
|
56
|
+
```
|
|
57
|
+
(password|api[_-]?key|secret|token)\s*[:=]\s*["'][^"']+["']
|
|
58
|
+
-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----
|
|
59
|
+
```
|
|
60
|
+
Also: unmasked password/token/PII in logs; a stack trace or internal path leaked to the user.
|
|
61
|
+
|
|
62
|
+
**Tracing method:** read the route/controller files (input enters here) → grep for dangerous calls (`eval`, `exec`, string-SQL) → check whether the middleware/interceptor has auth·CSRF·rate-limit → check whether the data model has mass-assignment protection. Run a web search for language-specific dangerous functions.
|
|
63
|
+
|
|
64
|
+
**Record for each finding:** file:line · vulnerability · what an attacker could do (impact) · fix specific to this code.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Front 3 — Configuration
|
|
69
|
+
|
|
70
|
+
**Is a secret in the repo:**
|
|
71
|
+
```bash
|
|
72
|
+
git ls-files --error-unmatch .env 2>/dev/null && echo "WARNING: .env is tracked"
|
|
73
|
+
```
|
|
74
|
+
If it's a finding, CRITICAL: `git rm --cached .env` → add to `.gitignore` → **rotate the exposed secrets**.
|
|
75
|
+
|
|
76
|
+
**Debug on in prod:** search for the framework-specific flag with `"[framework] debug mode production"`. Signs: an open debug flag, an error page showing a stack trace, a published source map, accessible development endpoints.
|
|
77
|
+
|
|
78
|
+
**Insecure transport:** hardcoded `http://` addresses (API, webhook, OAuth redirect, CDN) that should be `https`, and cookies without `Secure`. Exclude `localhost`/`127.0.0.1`/`0.0.0.0`.
|
|
79
|
+
|
|
80
|
+
**Missing security headers:** CSP, HSTS, X-Frame-Options, X-Content-Type-Options.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Front 4 — Authorization (auth-z)
|
|
85
|
+
|
|
86
|
+
Access-control flaws are the class most often missed in a scan, because the code appears to "work." Mandatory if the project includes admin/dashboard or role-based access:
|
|
87
|
+
|
|
88
|
+
1. Enumerate all roles/levels (admin, moderator, user, guest…).
|
|
89
|
+
2. Write all routes/endpoints and the **required** permission level into a matrix.
|
|
90
|
+
3. Verify that each protected route actually checks — "being logged in" is not authorization.
|
|
91
|
+
4. Look for endpoints that should be protected but aren't; try whether there is an admin endpoint reachable by guessing the URL.
|
|
92
|
+
5. Verify that authorization is enforced both at the controller **and** at the data-access layer (IDOR: object reference without ownership validation).
|
|
93
|
+
6. Privilege escalation: can a user change their own role/permission? Does a sensitive admin action require extra protection (re-auth/2FA)?
|
|
94
|
+
7. **JWT:** `alg: none` / algorithm confusion, secret embedded in code, missing expiration.
|
|
95
|
+
|
|
96
|
+
## Front 5 — AI, agent and MCP code
|
|
97
|
+
|
|
98
|
+
Only when the code under review builds on a model. The classes, the rule that decides what counts, and the extra
|
|
99
|
+
checks a finding must pass before it leaves the verifier are in **`ai-agents.md`**.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Prompting the review sub-agents (defensive security)
|
|
2
|
+
|
|
3
|
+
When the scan fans out a sub-agent per front, *how* you prompt it decides recall. Field-tested rules — these also
|
|
4
|
+
apply to `red-team` and any agent you point at a codebase to find bugs:
|
|
5
|
+
|
|
6
|
+
1. **Give the model room.** A high-level task beats prescriptive scaffolding. Long instructions, staged checklists,
|
|
7
|
+
and piles of reference material tend to backfire — the model pattern-matches your scaffold instead of reasoning
|
|
8
|
+
about the code.
|
|
9
|
+
2. **Describe vulnerability *shapes*, not a checklist.** Enumerating bug types ("find SQLi, XSS, and CSRF")
|
|
10
|
+
**worsens** recall — the model stops at your list. Describe the structural property instead: *"attacker input
|
|
11
|
+
that alters the syntactic structure of an interpreted string — SQL, shell, HTML, a template — or crosses a trust
|
|
12
|
+
boundary without a gate."*
|
|
13
|
+
3. **Scope each agent.** Tell it precisely which slice of the surface to search **and which classes you don't care
|
|
14
|
+
about**, so parallel agents don't all converge on the same easy findings. (A `threat-model` gives you this scope.)
|
|
15
|
+
4. **Frame verification adversarially.** "Actively look for reasons this finding is *wrong*" beats "check for
|
|
16
|
+
protections" — the whole disprove pass lives in `references/verify.md`.
|
|
17
|
+
5. **State that vulnerabilities exist.** "Act like a pentester" is weak. Strong: *"Produce a findings report with a
|
|
18
|
+
PoC for each Critical/High; assume there ARE vulnerabilities here; keep going until you've covered the surface."*
|
|
19
|
+
6. **Share mitigations the code doesn't show** (a WAF rule, a gateway auth check, a platform default) up front — it
|
|
20
|
+
saves the reviewer from re-finding a path that is already closed one layer up (a common false positive).
|
|
21
|
+
7. **Prompt-level guardrails are defense-in-depth only.** Real safety is human approval + the tool-level gates
|
|
22
|
+
(§4.4/§4.5), never a sentence in a prompt. Don't rely on "please don't exploit this" — rely on the gate.
|
|
23
|
+
8. **The sub-agent's final report is all the caller reads** — put every finding and its coverage in it.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Reporting & fix presentation
|
|
2
|
+
|
|
3
|
+
## Report
|
|
4
|
+
|
|
5
|
+
**Severity scale:**
|
|
6
|
+
|
|
7
|
+
| Level | Meaning |
|
|
8
|
+
|---|---|
|
|
9
|
+
| CRITICAL | Directly exploitable — urgent (SQL injection, hardcoded secret in prod) |
|
|
10
|
+
| HIGH | Serious — close before deploy (XSS, command injection, known CVE) |
|
|
11
|
+
| MEDIUM | Defense gap — soon (missing CSRF, loose CORS) |
|
|
12
|
+
| LOW | Best-practice violation — when convenient (debug mode, missing header) |
|
|
13
|
+
| INFO | Observation — no immediate risk |
|
|
14
|
+
|
|
15
|
+
**Finding format** (ranked by severity):
|
|
16
|
+
```
|
|
17
|
+
[CRITICAL] SQL Injection — src/api/users.ts:42
|
|
18
|
+
Vuln : Input concatenated directly into the SQL query
|
|
19
|
+
Impact: DB can be read / modified / deleted
|
|
20
|
+
Fix : Use a parameterized query
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Summary line:**
|
|
24
|
+
```
|
|
25
|
+
=== Security Scan Summary ===
|
|
26
|
+
CRITICAL: X · HIGH: X · MEDIUM: X · LOW: X · INFO: X · Total: X
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Coverage — say what you did NOT look at
|
|
30
|
+
|
|
31
|
+
A report with no findings is read as "nothing is wrong". It can equally mean "that surface was never opened",
|
|
32
|
+
and the two are indistinguishable to the person acting on it — who then ships believing an audit happened. The
|
|
33
|
+
`CANNOT_VERIFY` verdict already handles this for an individual finding; coverage handles it for the audit.
|
|
34
|
+
|
|
35
|
+
Every report ends with a coverage ledger, one row per surface from the threat model ([[threat-model]]):
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
=== Coverage ===
|
|
39
|
+
complete auth/session handling — read every route + middleware
|
|
40
|
+
complete SQL data access — grepped all query construction sites
|
|
41
|
+
partial file upload — read the handler; storage backend config not available
|
|
42
|
+
unknown payment webhook — third-party signature logic, no source access
|
|
43
|
+
unknown admin client (Blazor) — out of scope this pass, agreed with the user
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Rules:
|
|
47
|
+
- **`complete` is a claim, not a hope.** Use it only where you can name what you read or ran. If you sampled,
|
|
48
|
+
it is `partial`.
|
|
49
|
+
- Every `partial` and `unknown` carries **why** — no access, out of scope, no time, third-party. A bare
|
|
50
|
+
`unknown` is the same silence the ledger exists to remove.
|
|
51
|
+
- `unknown` on a surface the threat model calls high-risk is itself a finding: report it at the severity that
|
|
52
|
+
surface would carry, not as a footnote.
|
|
53
|
+
- The ledger is written **before** the fixes are proposed. Written afterwards, it gets trimmed to match the
|
|
54
|
+
work that happened to be done.
|
|
55
|
+
- "Zero findings, coverage complete" is a strong claim and rare. "Zero findings, half the surface unknown" is
|
|
56
|
+
an honest and much more common one.
|
|
57
|
+
|
|
58
|
+
### When a previous report exists
|
|
59
|
+
Read it before planning, and let it shape priority — never coverage.
|
|
60
|
+
- A previous **TRUE_POSITIVE** carries into this report only if the code on its path is unchanged; the verifier
|
|
61
|
+
re-checks it like any other candidate. Changed code makes it a fresh candidate, not an inherited one.
|
|
62
|
+
- A previous **FALSE_POSITIVE** rules out that exact claim on that exact unchanged code — nothing more. The surface
|
|
63
|
+
it sat on is still reviewed.
|
|
64
|
+
- A previous **CANNOT_VERIFY** is current work, unless the fact it waited on is still unavailable; then it carries
|
|
65
|
+
with that same named blocker.
|
|
66
|
+
- A previous `partial` or `unknown` row is never inherited as `complete`, and a previous narrow or quick pass is
|
|
67
|
+
never read as "the rest was fine". Say in this report which rows came from the earlier one and why they still hold.
|
|
68
|
+
|
|
69
|
+
## Fix presentation
|
|
70
|
+
```
|
|
71
|
+
How shall we proceed?
|
|
72
|
+
1. Fix everything 2. CRITICAL+HIGH only
|
|
73
|
+
3. Approve one by one 4. Manual (no changes)
|
|
74
|
+
```
|
|
75
|
+
For each fix: preview the diff → wait for approval → (if a dependency) upgrade command + breaking-change note → re-run the relevant check.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Verify before you report — the adversarial pass
|
|
2
|
+
|
|
3
|
+
Discovery and verification want opposite things. **Discovery is recall-biased** — when unsure whether something is
|
|
4
|
+
real, surface it (a low-confidence finding beats a missed bug). **Verification is precision-biased** — a separate,
|
|
5
|
+
adversarial pass that tries to *disprove* each finding. Keeping them separate is the single biggest lever on false
|
|
6
|
+
positives. (This is the same two-stage-verdict discipline `crew-code-review` uses — reused here for security findings.)
|
|
7
|
+
|
|
8
|
+
Run this pass on every candidate before it reaches the report.
|
|
9
|
+
|
|
10
|
+
## The verifier stance
|
|
11
|
+
For each finding, run **N independent verifiers** (default **3**; 1 for a quick scan, 5 for a release/high-stakes
|
|
12
|
+
audit). Each verifier:
|
|
13
|
+
- **Starts from the code at the cited `file:line`, not the finding's summary.** If you start from the summary you
|
|
14
|
+
inherit its misreading.
|
|
15
|
+
- Is stanced **"find any reason this finding is wrong."** Actively hunt for why it is *not* exploitable.
|
|
16
|
+
- Is **blind to the other verifiers' reasoning** — shared context propagates the same blind spot.
|
|
17
|
+
|
|
18
|
+
### "Independent" means a separate context, or it means nothing
|
|
19
|
+
Three passes inside one context window are not three verifiers. The second pass has already read the first one's
|
|
20
|
+
reasoning; the blindness above is then a wish, not a property, and the agreement it produces is one argument
|
|
21
|
+
counted three times. So:
|
|
22
|
+
- **Each verifier is its own subagent** (`Agent`, one call per verifier, run in parallel). A subagent has its own
|
|
23
|
+
context window: it cannot see what the others concluded, which is the whole point. Read-only work, so no
|
|
24
|
+
`worktree` is needed — nothing is being written.
|
|
25
|
+
- **Give it the finding and the file:line, never your reasoning.** Not "I think X is exploitable because Y" —
|
|
26
|
+
just "claim: X at file:line. Try to refute it."
|
|
27
|
+
- **If you did not isolate, say so.** Write `verifiers: 1 (single pass, not isolated)` in the verdict block. A
|
|
28
|
+
single honest pass is useful; three passes labelled as independent when they were not is worse than one,
|
|
29
|
+
because it launders confidence.
|
|
30
|
+
|
|
31
|
+
**Cost gate, because isolation is not free** — each subagent re-pays for its own context (see `token-budget`), so
|
|
32
|
+
N×findings gets expensive fast. Isolate by stake, not by default:
|
|
33
|
+
- **critical / high severity, or anything heading for a release** → isolate, N=3 (N=5 for a release audit).
|
|
34
|
+
- **medium** → isolate, N=1. One genuinely independent pass beats three entangled ones.
|
|
35
|
+
- **low** → single inline pass, labelled as such. Do not spend a subagent proving a `low`.
|
|
36
|
+
|
|
37
|
+
### The verifiers must not be three copies of one method
|
|
38
|
+
Independent is still not uncorrelated. Three verifiers running the same four steps fail in the same place, and
|
|
39
|
+
their agreement then reads as confirmation when it is only repetition. Assign each a **different attack**:
|
|
40
|
+
- **Reachability** — can untrusted input actually arrive here? Quote the first call-site as evidence.
|
|
41
|
+
- **Protection** — does something on every path already stop it? Try to break each guard.
|
|
42
|
+
- **Reproduction** — what input, in what state, actually triggers it? If you cannot name one, that is
|
|
43
|
+
`CANNOT_VERIFY`, not agreement with the others.
|
|
44
|
+
|
|
45
|
+
At N=5 add **exclusion rules** (does this match a known FALSE_POSITIVE class below?) and **blast radius** (if it
|
|
46
|
+
is real, what does it actually reach?). Record which lens produced which verdict — a verdict whose lens is
|
|
47
|
+
unnamed cannot be weighed.
|
|
48
|
+
|
|
49
|
+
### Unanimity is a signal to check, not a verdict to trust
|
|
50
|
+
If every verifier returns the same verdict **for the same reason**, that is one argument counted N times. Before
|
|
51
|
+
accepting it, run one counterfactual pass: *"assume this verdict is wrong — what would have to be true, and what
|
|
52
|
+
evidence would show it?"* Record the answer beside the verdict. Unanimity with N distinct reasons is strong;
|
|
53
|
+
unanimity with one reason is a monoculture, and it is exactly how a whole panel misses the same guard.
|
|
54
|
+
|
|
55
|
+
## The 4-step verify procedure (each step kills a specific false-positive class)
|
|
56
|
+
1. **Read the cited code yourself** — do not trust the description.
|
|
57
|
+
2. **Trace reachability backward from the sink.** Can untrusted input actually reach it? **Quote the first
|
|
58
|
+
call-site `file:line`** as evidence. *Unreachable code is the single largest source of false positives* — a
|
|
59
|
+
plausible-sounding chain is not enough.
|
|
60
|
+
3. **Hunt for protections** on every path: validation, parameterization, auto-escaping, type/length bounds, an
|
|
61
|
+
auth/scope gate, or the code being dead/test-only.
|
|
62
|
+
4. **Stress-test each protection on every path** — a guard that holds on one route but not another is not a guard.
|
|
63
|
+
|
|
64
|
+
## Verdict — three outcomes, never a forced binary
|
|
65
|
+
- **TRUE_POSITIVE** — requires ALL of: reachable + protections insufficient + exploitation feasible.
|
|
66
|
+
- **FALSE_POSITIVE** — fails one of the above, or matches an exclusion rule below.
|
|
67
|
+
- **CANNOT_VERIFY** — static reasoning hit its limit (needs a running system / data you don't have). Report it
|
|
68
|
+
honestly as `needs_manual_test`; never inflate uncertainty into a confident verdict.
|
|
69
|
+
- It carries **no severity**. It is a specific, source-grounded hypothesis that one missing fact blocks — not a
|
|
70
|
+
low-confidence confirmed vulnerability — and a severity on it would be read as a rating it has not earned.
|
|
71
|
+
- Name the missing fact exactly, and the check that would settle it.
|
|
72
|
+
- Controls that live outside the repository — a proxy, a WAF, provider settings, identity policy, network
|
|
73
|
+
topology, how a renderer sanitizes — are real controls. When a verdict depends on one that the source does not
|
|
74
|
+
show, do not assume it is **present**, and do not assume it is **absent**: that is what CANNOT_VERIFY is for.
|
|
75
|
+
|
|
76
|
+
"I couldn't write a working PoC" is **weak** evidence of non-exploitability — do not downgrade on that alone.
|
|
77
|
+
|
|
78
|
+
## Exclusion rules — FALSE_POSITIVE even if technically accurate
|
|
79
|
+
1. Volumetric/rate DoS with no amplification (just "many requests").
|
|
80
|
+
2. Test, fixture, example, or provably dead/unreachable code.
|
|
81
|
+
3. Intended, documented design (a stated, accepted risk).
|
|
82
|
+
4. Memory-safety issue in a memory-safe language/runtime.
|
|
83
|
+
5. Input that only a trusted operator controls (a local CLI flag, an ops-only env var).
|
|
84
|
+
6. "Outdated dependency" with no reachable vulnerable call path.
|
|
85
|
+
7. Weak randomness used somewhere non-security (a cache key, a test seed).
|
|
86
|
+
8. XSS auto-neutralised by the framework's default escaping.
|
|
87
|
+
9. Traversal blocked one layer up (a gateway/service the reasoning didn't read).
|
|
88
|
+
10. A theoretical-only TOCTOU with no realistic race window.
|
|
89
|
+
11. "Missing hardening" with no concrete exploit (a nice-to-have header).
|
|
90
|
+
12. Low-impact nuisance with no security consequence.
|
|
91
|
+
|
|
92
|
+
Add project-specific rules as you confirm them.
|
|
93
|
+
|
|
94
|
+
## Structured verdict block (one per finding, parseable)
|
|
95
|
+
```
|
|
96
|
+
VERDICT: TRUE_POSITIVE | FALSE_POSITIVE | CANNOT_VERIFY
|
|
97
|
+
CONFIDENCE: 0-10
|
|
98
|
+
VERIFIERS: <N, isolated | N, single pass not isolated>
|
|
99
|
+
LENSES: <reachability, protection, reproduction — which ones actually ran>
|
|
100
|
+
AGREEMENT: <unanimous-same-reason | unanimous-distinct-reasons | split N-M>
|
|
101
|
+
REACHABILITY: <first untrusted call-site file:line, or "unreachable">
|
|
102
|
+
EXCLUSION_RULE: <number, or none>
|
|
103
|
+
RATIONALE: <cites concrete file:line, not prose>
|
|
104
|
+
```
|
|
105
|
+
`VERIFIERS` and `AGREEMENT` exist so the reader can discount the verdict without re-doing the work. "3, single
|
|
106
|
+
pass not isolated" and "unanimous-same-reason" together mean one argument wearing three hats — still worth
|
|
107
|
+
reporting, not worth treating as three. Leaving these fields out is how a weak verdict passes for a strong one.
|
|
108
|
+
|
|
109
|
+
## Tally
|
|
110
|
+
Verdict = majority of the N verifiers; confidence = mean of the agreeing votes. **Tie → the operator's noise
|
|
111
|
+
tolerance:** precision → drop; recall → keep as `needs_manual_test`; ask → one batched question. Never silently
|
|
112
|
+
drop a finding — a dropped finding is recorded (with its verdict) in the report's "Ruled out" section.
|
|
113
|
+
|
|
114
|
+
## Severity is a SEPARATE judgment from verification
|
|
115
|
+
"This is real" must not inflate into "this is critical." Derive severity from **preconditions × access level**, not
|
|
116
|
+
from the vulnerability category:
|
|
117
|
+
|
|
118
|
+
| access ↓ / preconditions → | 0 preconditions | 1–2 | 3+ |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| **unauthenticated / remote** | CRITICAL–HIGH | MEDIUM | LOW |
|
|
121
|
+
| **authenticated** | MEDIUM | MEDIUM | LOW |
|
|
122
|
+
| **local / operator** | LOW | LOW | INFO |
|
|
123
|
+
|
|
124
|
+
- Take the **lower** of the two axes. If the precondition list has **3+ items, HIGH is almost certainly wrong.**
|
|
125
|
+
- **HIGH or MEDIUM? Ask one question:** does the demonstrated result fully **defeat** an explicit control for an
|
|
126
|
+
action with real consequences, or only **weaken** it? Defeat is HIGH territory; weaken is MEDIUM at most. If you
|
|
127
|
+
cannot state the concrete damage in a sentence, the severity is lower than it feels.
|
|
128
|
+
- Severity never exceeds the impact actually demonstrated.
|
|
129
|
+
- A `threat-model` match may raise severity by **at most one step** — never two (a stated threat can't re-inflate a LOW to HIGH).
|
|
130
|
+
- Record `severity_alignment` (**-5..+5**): judged from the stance of a reviewer who has seen two hundred inflated
|
|
131
|
+
scanner findings this week — how over- or under-stated is the raw claim? Negative = deflate it.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sonarqube-check
|
|
3
|
+
description: |
|
|
4
|
+
SonarQube quality gate, any language, no company server needed: run SonarQube Community Build locally (Docker),
|
|
5
|
+
read the real gate + issues, fix by rule id, re-scan and diff. A linter's green build is a pre-check, never the gate.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# SonarQube quality gate — produce the real report, locally
|
|
9
|
+
|
|
10
|
+
<!-- routing-eval reads the next line; why it sits in the body: AGENT_TEMPLATE.md -->
|
|
11
|
+
Trigger phrases: "sonarqube", "quality gate", "code smell", "sonar scan", "sonar rapor", "A rating"
|
|
12
|
+
|
|
13
|
+
**Only a SonarQube analysis can say "rating A, 0 findings".** A clean `build` says the compiler was happy — a
|
|
14
|
+
different claim, about a different rule set. Passing one off as the other is how a team is told the code is clean
|
|
15
|
+
and then opens a report full of findings.
|
|
16
|
+
|
|
17
|
+
You do **not** need a company server or someone else's token to get the real thing: **SonarQube Community Build is
|
|
18
|
+
free, needs no licence key, and runs in one Docker container on this machine.** That is the default path here — the
|
|
19
|
+
gate is produced locally, offline, and it is a genuine SonarQube verdict, not a proxy for one.
|
|
20
|
+
|
|
21
|
+
Language-agnostic on purpose: SonarQube covers 20+ languages plus IaC (Terraform, Kubernetes, Dockerfile). Detect
|
|
22
|
+
what the project actually uses; never assume a stack.
|
|
23
|
+
|
|
24
|
+
## Step 1 — get a real analysis (pick the first that applies)
|
|
25
|
+
|
|
26
|
+
**a) The project already has a SonarQube** → use it, and skip to step 2.
|
|
27
|
+
|
|
28
|
+
**b) It does not → stand one up locally.** Docker one-liner, the Docker-free server zip, the first login and the
|
|
29
|
+
token: **`references/stand-up-server.md`**. No licence, no external account, nothing leaves the machine.
|
|
30
|
+
|
|
31
|
+
> **Restarting is not installing.** Bringing an already-approved service back up on this machine — the same
|
|
32
|
+
> image, the same volumes — is resuming what the user already said yes to, and this skill's own advice to keep
|
|
33
|
+
> a named volume assumes exactly that. A NEW image, a new volume, or a tool this machine does not have is an
|
|
34
|
+
> install, and needs the answer below.
|
|
35
|
+
>
|
|
36
|
+
> **Nothing here is installed without the user saying so.** Docker, Java, a scanner, a linter — each is a proposal
|
|
37
|
+
> with its cost stated, and the user picks. If they decline all of them, that is a valid answer: go to (c) and
|
|
38
|
+
> report "unverified" rather than installing anything to make a number appear.
|
|
39
|
+
|
|
40
|
+
Scan with whatever runner the project's stack uses — the scanner is the same product for every language:
|
|
41
|
+
|
|
42
|
+
| Project | Scan command |
|
|
43
|
+
|---|---|
|
|
44
|
+
| Any stack (generic) | `sonar-scanner -Dsonar.projectKey=app -Dsonar.sources=. -Dsonar.host.url=http://localhost:9000 -Dsonar.token=$T` |
|
|
45
|
+
| Maven / Gradle | `mvn sonar:sonar -Dsonar.host.url=… -Dsonar.token=$T` · `gradle sonarqube …` |
|
|
46
|
+
| .NET | `dotnet sonarscanner begin /k:app /d:sonar.host.url=… /d:sonar.token=$T` → `dotnet build` → `dotnet sonarscanner end /d:sonar.token=$T` |
|
|
47
|
+
| JS/TS, Python, Go, PHP, Ruby | the generic `sonar-scanner` above (add coverage report paths if the project produces them) |
|
|
48
|
+
|
|
49
|
+
**c) No server is possible at all** (no Docker, no Java, no permission to run one) → run the language's Sonar-rule
|
|
50
|
+
engine locally as a pre-check (**`references/local-engines.md`** — which engine per language, and how close it is
|
|
51
|
+
to Sonar's own rules) and **say what that is worth**, in these words rather than a
|
|
52
|
+
rating: *"the local rule engine reports N issues, none open; the SonarQube rating and the gate were not produced —
|
|
53
|
+
no analysis ran."* Then list what stays unverified: taint/injection, hotspot review state, coverage, duplication,
|
|
54
|
+
files outside the compiled language, and the project's own quality profile. Offer branch (b) — a local server, with
|
|
55
|
+
or without Docker — as the way to close it.
|
|
56
|
+
|
|
57
|
+
**Never invent the verdict.** A rating exists only where an analysis produced one; without it the honest output is
|
|
58
|
+
"unverified", and that is the sentence that saves the user from promising a clean report they cannot back.
|
|
59
|
+
|
|
60
|
+
## Step 2 — read the verdict, don't infer it
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
S=http://localhost:9000; K=app # or the project's own host/key
|
|
64
|
+
curl -sfu "$T:" "$S/api/qualitygates/project_status?projectKey=$K" # pass / fail, and which condition failed
|
|
65
|
+
curl -sfu "$T:" "$S/api/issues/search?componentKeys=$K&resolved=false&ps=500" # rule id + file + line per finding
|
|
66
|
+
curl -sfu "$T:" "$S/api/hotspots/search?projectKey=$K&status=TO_REVIEW" # hotspots are a SEPARATE endpoint
|
|
67
|
+
curl -sfu "$T:" "$S/api/measures/component?component=$K&metricKeys=alert_status,bugs,vulnerabilities,security_hotspots,code_smells,coverage,duplicated_lines_density,reliability_rating,security_rating,sqale_rating"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Also read the gate's definition (`/api/qualitygates/show`): most gates judge **new code**, not the whole project.
|
|
71
|
+
Chasing overall counts while the gate measures new code burns days and still fails; the reverse leaves real debt.
|
|
72
|
+
Know which one applies before planning the work.
|
|
73
|
+
|
|
74
|
+
## Step 3 — fix by rule, never by impression
|
|
75
|
+
|
|
76
|
+
Group findings by `rule` (`csharpsquid:S1481`, `typescript:S3776`, `python:S5852`, …) and take one rule at a time,
|
|
77
|
+
all occurrences together. Read what the rule actually asks, fix the cause, cite the rule id in the change. The
|
|
78
|
+
domain owner does the fixing — a security rule is `crew-security-expert`'s, a query/index rule is
|
|
79
|
+
`crew-database-expert`'s.
|
|
80
|
+
|
|
81
|
+
**Never close a finding by silencing it.** `#pragma warning disable`, `// NOSONAR`, `eslint-disable`, an exclusion in
|
|
82
|
+
`sonar-project.properties` — each one changes the report without changing the code. It needs a written reason and
|
|
83
|
+
the user's approval, every time.
|
|
84
|
+
|
|
85
|
+
**Security Hotspots do not close by editing code.** Each is reviewed in the UI and marked *safe* (with a rationale)
|
|
86
|
+
or *fixed*. Code changes alone leave it `TO_REVIEW` and the gate keeps failing.
|
|
87
|
+
|
|
88
|
+
## Step 4 — re-scan and diff. The loop is the deliverable
|
|
89
|
+
|
|
90
|
+
Re-run step 1's scan, re-read step 2, and report the **difference**: counts before → after, which rule ids
|
|
91
|
+
disappeared, which remain, which are new. "It should be clean now" is not a result — a second analysis is.
|
|
92
|
+
Repeat until the gate says `OK`, or every remaining finding has a user-approved suppression. Nothing here closes on a first pass.
|
|
93
|
+
|
|
94
|
+
## What even a local SonarQube cannot see
|
|
95
|
+
|
|
96
|
+
Community Build has no **taint/injection analysis** (data flow from user input to a dangerous sink — SQLi, XSS,
|
|
97
|
+
command injection); that engine is in the paid editions. It also has no branch/PR analysis. So a clean local gate
|
|
98
|
+
is not proof of injection safety: cover that with the **`security-scan`** and **`threat-model`** skills plus a
|
|
99
|
+
`crew-security-expert` review, and say which of the two verdicts you are reporting.
|
|
100
|
+
|
|
101
|
+
## DoD
|
|
102
|
+
- The verdict is quoted **from an analysis**: gate status, counts by severity, ratings, analysis date, and where it
|
|
103
|
+
ran (project server or local container).
|
|
104
|
+
- Every finding closed by a code change, or by a suppression the user explicitly approved with a written reason.
|
|
105
|
+
- Hotspots reviewed in the UI, not merely edited around.
|
|
106
|
+
- A re-scan ran after the fixes and the before → after diff by rule id is reported.
|
|
107
|
+
- Injection risk stated separately (taint analysis is not in Community Build).
|
|
108
|
+
- Anything not done is said plainly — never implied clean.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Running Sonar rules locally with no server at all
|
|
2
|
+
|
|
3
|
+
Read this only on branch (c) of step 1 — no server is possible (no Docker, no Java, no permission to run one), or
|
|
4
|
+
as a pre-check before anything is scanned.
|
|
5
|
+
|
|
6
|
+
This is worth more than it sounds: several languages have SonarSource's **own** rule engine as a normal dependency,
|
|
7
|
+
so you can find and fix most rule violations offline, before anything is ever scanned. What no local engine can
|
|
8
|
+
produce is the **verdict** — ratings (A/B/C), gate pass/fail, coverage, duplication, hotspot review state and the
|
|
9
|
+
project's quality profile are computed by the server, from an analysis. Findings yes; a rating no.
|
|
10
|
+
|
|
11
|
+
**The rule, for every language:** find whether SonarSource publishes its own rule engine for the project's
|
|
12
|
+
language and wire *that* into the build or the editor. Where only a third-party look-alike exists, use it and say
|
|
13
|
+
that the rule ids will not match the report. Ask which languages the repo actually contains — most repos have
|
|
14
|
+
more than one, and each needs its own engine.
|
|
15
|
+
|
|
16
|
+
| Stack (alphabetical — no language is the default) | Local engine | How close to Sonar's own rules |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Go | `golangci-lint` and friends | Third-party; overlaps in intent, not in rule ids |
|
|
19
|
+
| Java / Kotlin | SonarQube for IDE (SonarLint) in the editor; SpotBugs + PMD in the build | Editor-side runs Sonar analyzers; the build-side pair is a different rule set |
|
|
20
|
+
| JS / TS | `eslint-plugin-sonarjs` | SonarSource's own JS/TS rules, delivered through ESLint |
|
|
21
|
+
| .NET (C# · VB.NET) | `SonarAnalyzer.CSharp` / `.VisualBasic` (Roslyn, at build time) | SonarSource's own analyzer, 480+ C# rules; rule-set parity with the server is not documented either way — close, not proven identical |
|
|
22
|
+
| PHP / Ruby / other | that language's linter | Varies; check whether it is SonarSource's or a look-alike |
|
|
23
|
+
| Python | `ruff` / `pylint` + `bandit` | **Not Sonar rules** — an approximation |
|
|
24
|
+
|
|
25
|
+
**Injection / taint rules are not in any of these** — they run only on SonarQube Server/Cloud, in the commercial
|
|
26
|
+
editions. So even a spotless local run says nothing about SQLi/XSS/command injection; that gap is covered by
|
|
27
|
+
`security-scan` + `threat-model` + a `crew-security-expert` review, and is reported as its own line, never folded
|
|
28
|
+
into a "clean" claim.
|
|
29
|
+
|
|
30
|
+
Pin versions so builds stay reproducible (with Central Package Management, declare it there). Turning warnings into
|
|
31
|
+
errors is the project's call — propose it, don't impose it. And whatever the local run says, the honest wording
|
|
32
|
+
stays: *findings fixed; rating and gate not produced — no analysis ran.*
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Standing up SonarQube Community Build locally
|
|
2
|
+
|
|
3
|
+
Read this only on branch (b) of step 1 — the project has no SonarQube and one is being stood up. No licence, no
|
|
4
|
+
external account, nothing leaves the machine.
|
|
5
|
+
|
|
6
|
+
**The consent rule in SKILL.md governs every line below.** Docker, Java, a scanner — each is a proposal with its
|
|
7
|
+
cost stated, and the user picks. Restarting an already-approved service is not installing; a new image, a new
|
|
8
|
+
volume, or a tool this machine does not have is.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# b1 — with Docker (one command)
|
|
12
|
+
docker run -d --name sonarqube -p 9000:9000 sonarqube:community # first boot ~1-2 min
|
|
13
|
+
|
|
14
|
+
# b2 — WITHOUT Docker: the plain server zip. Needs Java 17 or 21 on PATH (`java -version`), nothing else.
|
|
15
|
+
# download SonarQube Community Build, unzip (e.g. C:\sonarqube), then start it:
|
|
16
|
+
# Windows C:\sonarqube\bin\windows-x86-64\StartSonar.bat
|
|
17
|
+
# Linux/macOS ./bin/<platform>/sonar.sh console
|
|
18
|
+
# It runs on an embedded H2 database — no database to install for local use.
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Either way: http://localhost:9000 · first login `admin`/`admin` · set a new password · then My Account → Security →
|
|
22
|
+
generate a token. **That token is local and yours** — it is not a company credential and nothing is sent anywhere.
|
|
23
|
+
|
|
24
|
+
Persist the container (`-v sonarqube_data:/opt/sonarqube/data`) so history survives, and put the key/exclusions in
|
|
25
|
+
`sonar-project.properties` so every later run is identical.
|