vanara 0.1.0 → 0.3.0
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/README.md +14 -0
- package/bin/vanara.js +66 -2
- package/catalog/agents/api-designer/AGENT.md +156 -0
- package/catalog/agents/api-designer/examples/openapi-snippet.yaml +130 -0
- package/catalog/agents/api-designer/examples/review-notes.md +61 -0
- package/catalog/agents/api-designer/references/contract-and-openapi.md +82 -0
- package/catalog/agents/api-designer/references/design-checklist.md +68 -0
- package/catalog/agents/api-designer/references/versioning-and-evolution.md +63 -0
- package/catalog/agents/api-designer/scripts/lint-openapi.mjs +180 -0
- package/catalog/agents/code-reviewer/AGENT.md +184 -0
- package/catalog/agents/code-reviewer/examples/pr-comment-template.md +48 -0
- package/catalog/agents/code-reviewer/examples/sample-review-output.md +38 -0
- package/catalog/agents/code-reviewer/references/review-checklist.md +46 -0
- package/catalog/agents/code-reviewer/references/security-review.md +62 -0
- package/catalog/agents/code-reviewer/references/severity-rubric.md +63 -0
- package/catalog/agents/code-reviewer/scripts/review-guard.mjs +102 -0
- package/catalog/agents/debugger/AGENT.md +128 -0
- package/catalog/agents/debugger/examples/postmortem-template.md +59 -0
- package/catalog/agents/debugger/examples/repro-template.md +50 -0
- package/catalog/agents/debugger/references/bisection.md +63 -0
- package/catalog/agents/debugger/references/debugging-method.md +57 -0
- package/catalog/agents/debugger/references/observability.md +61 -0
- package/catalog/agents/debugger/scripts/parse-stacktrace.mjs +109 -0
- package/catalog/agents/pr-summarizer/AGENT.md +172 -0
- package/catalog/agents/pr-summarizer/examples/sample-pr-summary.md +46 -0
- package/catalog/agents/pr-summarizer/examples/weak-vs-strong-summary.md +68 -0
- package/catalog/agents/pr-summarizer/references/identifying-risk.md +68 -0
- package/catalog/agents/pr-summarizer/references/reading-the-diff.md +68 -0
- package/catalog/agents/pr-summarizer/references/test-plan-and-missing-tests.md +64 -0
- package/catalog/agents/pr-summarizer/references/writing-the-summary.md +63 -0
- package/catalog/agents/pr-summarizer/scripts/diff-risk.mjs +111 -0
- package/catalog/agents/refactoring-specialist/AGENT.md +201 -0
- package/catalog/agents/refactoring-specialist/examples/before-after.md +91 -0
- package/catalog/agents/refactoring-specialist/examples/refactor-plan.md +97 -0
- package/catalog/agents/refactoring-specialist/references/large-scale-refactor.md +50 -0
- package/catalog/agents/refactoring-specialist/references/safe-workflow.md +75 -0
- package/catalog/agents/refactoring-specialist/references/smell-catalog.md +76 -0
- package/catalog/agents/refactoring-specialist/scripts/detect-smells.mjs +150 -0
- package/catalog/agents/security-auditor/AGENT.md +184 -0
- package/catalog/agents/security-auditor/examples/audit-report.md +68 -0
- package/catalog/agents/security-auditor/examples/finding-template.md +31 -0
- package/catalog/agents/security-auditor/references/audit-workflow.md +116 -0
- package/catalog/agents/security-auditor/references/severity-and-reporting.md +56 -0
- package/catalog/agents/security-auditor/references/vuln-classes.md +129 -0
- package/catalog/agents/security-auditor/scripts/scan-secrets.mjs +86 -0
- package/catalog/agents/technical-writer/AGENT.md +179 -0
- package/catalog/agents/technical-writer/examples/how-to-example.md +76 -0
- package/catalog/agents/technical-writer/examples/reference-example.md +75 -0
- package/catalog/agents/technical-writer/references/clarity-and-style.md +52 -0
- package/catalog/agents/technical-writer/references/diataxis-and-doc-types.md +61 -0
- package/catalog/agents/technical-writer/references/structure-and-maintenance.md +59 -0
- package/catalog/agents/technical-writer/scripts/readability.mjs +103 -0
- package/catalog/agents/test-author/AGENT.md +193 -0
- package/catalog/agents/test-author/examples/test-plan.md +54 -0
- package/catalog/agents/test-author/examples/unit-test-example.ts +55 -0
- package/catalog/agents/test-author/references/aaa-and-naming.md +75 -0
- package/catalog/agents/test-author/references/mocking-and-fixtures.md +94 -0
- package/catalog/agents/test-author/references/test-types-and-pyramid.md +60 -0
- package/catalog/agents/test-author/scripts/check-coverage.mjs +145 -0
- package/catalog/agents/threat-modeler/AGENT.md +179 -0
- package/catalog/agents/threat-modeler/examples/dfd-example.md +55 -0
- package/catalog/agents/threat-modeler/examples/threat-model.md +81 -0
- package/catalog/agents/threat-modeler/references/dfd-and-trust-boundaries.md +76 -0
- package/catalog/agents/threat-modeler/references/mitigation-catalog.md +77 -0
- package/catalog/agents/threat-modeler/references/stride-method.md +68 -0
- package/catalog/agents/threat-modeler/scripts/stride-checklist.mjs +183 -0
- package/catalog/agents/vuln-scanner/AGENT.md +162 -0
- package/catalog/agents/vuln-scanner/examples/finding-template.md +57 -0
- package/catalog/agents/vuln-scanner/examples/scan-report.md +49 -0
- package/catalog/agents/vuln-scanner/references/remediation-and-severity.md +68 -0
- package/catalog/agents/vuln-scanner/references/scan-types-and-tools.md +83 -0
- package/catalog/agents/vuln-scanner/references/triage-and-false-positives.md +73 -0
- package/catalog/agents/vuln-scanner/scripts/parse-scan-results.mjs +133 -0
- package/catalog/packs/code-review-pack/PACK.md +100 -0
- package/catalog/packs/code-review-pack/examples/pr-flow-example.md +50 -0
- package/catalog/packs/code-review-pack/references/rollout-guide.md +40 -0
- package/catalog/packs/security-pack/PACK.md +128 -0
- package/catalog/packs/security-pack/examples/owasp-vuln-triage-and-fix.md +66 -0
- package/catalog/packs/security-pack/examples/threat-model-then-audit.md +77 -0
- package/catalog/packs/security-pack/references/choosing-the-right-tool.md +37 -0
- package/catalog/packs/security-pack/references/threat-model-to-remediation.md +69 -0
- package/catalog/packs/security-pack/references/workflow.md +56 -0
- package/catalog/skills/api-pagination/SKILL.md +83 -0
- package/catalog/skills/api-pagination/examples/keyset-queries.sql +38 -0
- package/catalog/skills/api-pagination/examples/response-shapes.md +51 -0
- package/catalog/skills/api-pagination/references/consuming-pages.md +39 -0
- package/catalog/skills/api-pagination/references/counting-and-totals.md +41 -0
- package/catalog/skills/api-pagination/references/cursor-encoding.md +34 -0
- package/catalog/skills/api-pagination/scripts/check-cursor.mjs +51 -0
- package/catalog/skills/caching-strategies/SKILL.md +180 -0
- package/catalog/skills/caching-strategies/examples/http-cache-headers.md +82 -0
- package/catalog/skills/caching-strategies/examples/redis-cache-aside.js +110 -0
- package/catalog/skills/caching-strategies/references/cache-patterns.md +93 -0
- package/catalog/skills/caching-strategies/references/eviction-and-ttl.md +67 -0
- package/catalog/skills/caching-strategies/references/invalidation-and-stampede.md +99 -0
- package/catalog/skills/caching-strategies/scripts/ttl-jitter.mjs +99 -0
- package/catalog/skills/conventional-commits/SKILL.md +135 -0
- package/catalog/skills/conventional-commits/examples/commit-examples.md +60 -0
- package/catalog/skills/conventional-commits/examples/commitlint.config.js +31 -0
- package/catalog/skills/conventional-commits/references/breaking-changes-semver.md +50 -0
- package/catalog/skills/conventional-commits/references/scoping-commits.md +42 -0
- package/catalog/skills/conventional-commits/references/spec.md +78 -0
- package/catalog/skills/conventional-commits/scripts/lint-commit.mjs +97 -0
- package/catalog/skills/database-migrations/SKILL.md +137 -0
- package/catalog/skills/database-migrations/examples/add-column-safe.sql +34 -0
- package/catalog/skills/database-migrations/examples/migration-config.example.json +27 -0
- package/catalog/skills/database-migrations/references/expand-contract.md +74 -0
- package/catalog/skills/database-migrations/references/rollback-and-safety.md +71 -0
- package/catalog/skills/database-migrations/references/zero-downtime-changes.md +84 -0
- package/catalog/skills/database-migrations/scripts/check-migration-reversible.mjs +139 -0
- package/catalog/skills/error-handling-patterns/SKILL.md +136 -0
- package/catalog/skills/error-handling-patterns/examples/express-error-middleware.js +93 -0
- package/catalog/skills/error-handling-patterns/examples/result-pattern.ts +81 -0
- package/catalog/skills/error-handling-patterns/references/error-taxonomy.md +91 -0
- package/catalog/skills/error-handling-patterns/references/language-patterns.md +102 -0
- package/catalog/skills/error-handling-patterns/references/retry-and-backoff.md +76 -0
- package/catalog/skills/error-handling-patterns/scripts/lint-empty-catch.mjs +113 -0
- package/catalog/skills/git-collaboration-workflows/SKILL.md +104 -0
- package/catalog/skills/git-collaboration-workflows/examples/branch-protection.md +48 -0
- package/catalog/skills/git-collaboration-workflows/examples/pr-review-playbook.md +48 -0
- package/catalog/skills/git-collaboration-workflows/references/branching-models.md +52 -0
- package/catalog/skills/git-collaboration-workflows/references/history-hygiene.md +44 -0
- package/catalog/skills/git-collaboration-workflows/scripts/check-branch-hygiene.mjs +62 -0
- package/catalog/skills/owasp-top10/SKILL.md +112 -0
- package/catalog/skills/owasp-top10/examples/sql-injection-fix.md +33 -0
- package/catalog/skills/owasp-top10/examples/xss-fix.md +27 -0
- package/catalog/skills/owasp-top10/references/access-control.md +36 -0
- package/catalog/skills/owasp-top10/references/crypto-failures.md +29 -0
- package/catalog/skills/owasp-top10/references/injection.md +39 -0
- package/catalog/skills/owasp-top10/references/ssrf-and-design.md +35 -0
- package/catalog/skills/owasp-top10/scripts/scan-injection.mjs +73 -0
- package/catalog/skills/prompt-engineering/SKILL.md +100 -0
- package/catalog/skills/prompt-engineering/examples/classification-prompt.md +29 -0
- package/catalog/skills/prompt-engineering/examples/extraction-prompt.md +25 -0
- package/catalog/skills/prompt-engineering/references/prompt-injection.md +34 -0
- package/catalog/skills/prompt-engineering/references/structured-output.md +34 -0
- package/catalog/skills/prompt-engineering/references/techniques.md +33 -0
- package/catalog/skills/prompt-engineering/scripts/validate-output.mjs +71 -0
- package/catalog/skills/readme-writing/SKILL.md +176 -0
- package/catalog/skills/readme-writing/examples/README.template.md +73 -0
- package/catalog/skills/readme-writing/examples/good-readme-example.md +95 -0
- package/catalog/skills/readme-writing/references/anatomy.md +107 -0
- package/catalog/skills/readme-writing/references/maintenance.md +68 -0
- package/catalog/skills/readme-writing/references/writing-style.md +79 -0
- package/catalog/skills/readme-writing/scripts/lint-readme.mjs +117 -0
- package/catalog/skills/refactoring-patterns/SKILL.md +178 -0
- package/catalog/skills/refactoring-patterns/examples/extract-function.before-after.js +57 -0
- package/catalog/skills/refactoring-patterns/examples/replace-conditional-with-polymorphism.before-after.ts +63 -0
- package/catalog/skills/refactoring-patterns/references/code-smells.md +92 -0
- package/catalog/skills/refactoring-patterns/references/refactoring-catalog.md +78 -0
- package/catalog/skills/refactoring-patterns/references/safe-workflow.md +74 -0
- package/catalog/skills/refactoring-patterns/scripts/detect-smells.mjs +137 -0
- package/catalog/skills/rest-api-design/SKILL.md +147 -0
- package/catalog/skills/rest-api-design/examples/error-envelope.json +26 -0
- package/catalog/skills/rest-api-design/examples/orders-api.openapi.yaml +106 -0
- package/catalog/skills/rest-api-design/references/error-handling.md +43 -0
- package/catalog/skills/rest-api-design/references/pagination.md +41 -0
- package/catalog/skills/rest-api-design/references/status-codes.md +32 -0
- package/catalog/skills/rest-api-design/references/versioning.md +31 -0
- package/catalog/skills/rest-api-design/scripts/check-envelope.mjs +62 -0
- package/catalog/skills/secrets-management/SKILL.md +134 -0
- package/catalog/skills/secrets-management/examples/env-example.md +41 -0
- package/catalog/skills/secrets-management/examples/rotation-runbook.md +50 -0
- package/catalog/skills/secrets-management/references/leak-response.md +47 -0
- package/catalog/skills/secrets-management/references/rotation.md +46 -0
- package/catalog/skills/secrets-management/references/secret-managers.md +52 -0
- package/catalog/skills/secrets-management/scripts/detect-hardcoded.mjs +96 -0
- package/catalog/skills/secure-auth/SKILL.md +135 -0
- package/catalog/skills/secure-auth/examples/auth-flow.md +60 -0
- package/catalog/skills/secure-auth/examples/jwt-verify.ts +89 -0
- package/catalog/skills/secure-auth/references/auth-attacks.md +76 -0
- package/catalog/skills/secure-auth/references/oauth2-oidc.md +65 -0
- package/catalog/skills/secure-auth/references/password-hashing.md +70 -0
- package/catalog/skills/secure-auth/references/sessions-vs-jwt.md +69 -0
- package/catalog/skills/secure-auth/scripts/check-password-policy.mjs +114 -0
- package/catalog/skills/sql-index-tuning/SKILL.md +171 -0
- package/catalog/skills/sql-index-tuning/examples/explain-walkthrough.sql +91 -0
- package/catalog/skills/sql-index-tuning/examples/index-ddl.sql +67 -0
- package/catalog/skills/sql-index-tuning/references/btree-internals.md +58 -0
- package/catalog/skills/sql-index-tuning/references/composite-and-covering.md +60 -0
- package/catalog/skills/sql-index-tuning/references/reading-explain.md +54 -0
- package/catalog/skills/sql-index-tuning/references/selectivity-and-cardinality.md +62 -0
- package/catalog/skills/sql-index-tuning/scripts/suggest-index.mjs +213 -0
- package/catalog/skills/test-plan-design/SKILL.md +154 -0
- package/catalog/skills/test-plan-design/examples/test-case-template.md +45 -0
- package/catalog/skills/test-plan-design/examples/test-plan.md +57 -0
- package/catalog/skills/test-plan-design/references/case-design.md +79 -0
- package/catalog/skills/test-plan-design/references/risk-prioritization.md +58 -0
- package/catalog/skills/test-plan-design/references/test-pyramid.md +58 -0
- package/catalog/skills/test-plan-design/scripts/coverage-gaps.mjs +109 -0
- package/free-tier.json +15 -0
- package/package.json +15 -4
- package/premium-index.json +1 -0
- package/src/config.js +31 -1
- package/src/license.js +143 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Example: Vulnerability Scan Report
|
|
2
|
+
|
|
3
|
+
A worked example of the report shape this agent produces. Note the structure: a tight summary, a short
|
|
4
|
+
*fix now* list, then everything else ranked below it. The raw scan had 47 findings; triage reduced the
|
|
5
|
+
release-blocking set to 3.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
- **Scope:** npm dependencies (lockfile), source secret scan, Dockerfile base image.
|
|
12
|
+
- **Findings:** 1 critical, 2 high, 6 medium, 38 low/info (47 raw -> 9 actionable after triage).
|
|
13
|
+
- **Most urgent:** rotate the AWS key committed in `config/legacy.env` — assume compromised.
|
|
14
|
+
|
|
15
|
+
## Fix now (release-blocking)
|
|
16
|
+
|
|
17
|
+
| Item | Severity | Fix | Breaking? | Reachability |
|
|
18
|
+
|---|---|---|---|---|
|
|
19
|
+
| AWS access key in `config/legacy.env` | critical | rotate in IAM, move to env var | n/a | Live credential, public history |
|
|
20
|
+
| `lodash@4.17.15` (CVE-2020-8203) | high | -> `4.17.21` | no | Reachable via `util/merge.js` |
|
|
21
|
+
| `axios@0.21.0` (SSRF, CVE-2021-3749) | high | -> `0.21.4` | no | Used in outbound webhook client |
|
|
22
|
+
|
|
23
|
+
## Plan (schedule, not blocking)
|
|
24
|
+
|
|
25
|
+
- **`next@12 -> 14` (3 medium CVEs):** breaking major. Clears 3 advisories but requires app-router
|
|
26
|
+
migration review. Estimate: 1 sprint. Group as one coordinated upgrade.
|
|
27
|
+
- **`debug=true` in `config/prod.json`:** medium. Leaks stack traces to clients; set `false`.
|
|
28
|
+
- **6 transitive medium CVEs in dev-only deps:** real but build-time only; bump opportunistically.
|
|
29
|
+
|
|
30
|
+
## Exposed secrets
|
|
31
|
+
|
|
32
|
+
| Secret | Location | Action |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| AWS access key `AKIA…` | `config/legacy.env:4` | **Rotate** in IAM (revoke old), replace with `AWS_ACCESS_KEY_ID` env var, add pre-commit secret hook |
|
|
35
|
+
| Slack webhook URL | `scripts/notify.sh:12` | Rotate webhook in Slack, move to secret manager |
|
|
36
|
+
|
|
37
|
+
Removal from the latest commit is **not** sufficient — both are still valid at the provider.
|
|
38
|
+
|
|
39
|
+
## Config / container risks
|
|
40
|
+
|
|
41
|
+
- **Base image `node:18.0-alpine`:** carries 4 OS-package CVEs. Bump to current `node:18-alpine` patch.
|
|
42
|
+
- **Container runs as root:** add a non-root `USER` to the Dockerfile.
|
|
43
|
+
|
|
44
|
+
## Accepted / suppressed (with reason)
|
|
45
|
+
|
|
46
|
+
- **CVE-2025-XXXX in `fast-xml@3.1.0` (CVSS 9.8):** vulnerable `parseAttrs` path requires
|
|
47
|
+
`allowAttributes:true`; app uses defaults. Downgraded critical -> medium, scheduled.
|
|
48
|
+
- **`AKIAEXAMPLE…` in `docs/setup.md`:** documentation placeholder, not a live key. Suppressed.
|
|
49
|
+
- **CVE in `jest@…`:** dev/test-only dependency, not in production bundle. Backlog.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Remediation and Severity
|
|
2
|
+
|
|
3
|
+
Once a finding is triaged, the deliverable is a *fix the reader can act on*. This reference defines the
|
|
4
|
+
severity scale, the dependency-fix strategy, and the secret-rotation playbook.
|
|
5
|
+
|
|
6
|
+
## Severity scale
|
|
7
|
+
|
|
8
|
+
Use a single normalized scale across all scan families so the report is comparable:
|
|
9
|
+
|
|
10
|
+
| Severity | Meaning | Default action |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `critical` | Reachable RCE, auth bypass, or active secret leak | Block release; fix now |
|
|
13
|
+
| `high` | Serious impact, exploitable with moderate effort | Fix before release |
|
|
14
|
+
| `medium` | Real but constrained (limited reach or impact) | Schedule next sprint |
|
|
15
|
+
| `low` | Minor / hardening | Backlog |
|
|
16
|
+
| `info` | Awareness only | No action required |
|
|
17
|
+
|
|
18
|
+
Final severity = scanner severity **adjusted by reachability and impact** (see
|
|
19
|
+
[triage-and-false-positives](triage-and-false-positives.md)). Always show your adjustment reasoning.
|
|
20
|
+
|
|
21
|
+
## Dependency remediation strategy
|
|
22
|
+
|
|
23
|
+
For every vulnerable dependency, state the fix version and whether it's breaking:
|
|
24
|
+
|
|
25
|
+
1. **Prefer the minimal bump that clears the CVE.** If `1.2.3 -> 1.2.4` fixes it, recommend that, not
|
|
26
|
+
the latest 3.x.
|
|
27
|
+
2. **Label breaking vs. non-breaking** by semver distance and changelog. Crossing a major is breaking
|
|
28
|
+
until proven otherwise.
|
|
29
|
+
3. **Transitive deps:** if you don't own the dependency directly, fix via the parent bump, or a
|
|
30
|
+
lockfile override / resolution (`overrides` in npm, `resolutions` in yarn/pnpm) — and flag overrides
|
|
31
|
+
as a temporary measure, not a permanent pin.
|
|
32
|
+
4. **Group breaking upgrades separately** under *plan* with a migration-risk note. Never bundle a risky
|
|
33
|
+
major bump into a "quick fix" list.
|
|
34
|
+
5. **No fix available?** Document the mitigation (disable the feature, add input validation, network
|
|
35
|
+
isolation) and mark for monitoring.
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
Fix-now bucket -> non-breaking bumps that clear critical/high, reachable
|
|
39
|
+
Plan bucket -> breaking upgrades, lower-severity, or coordinated changes
|
|
40
|
+
Accept/monitor -> no fix yet, or risk-accepted with justification
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Secret remediation — rotation, not removal
|
|
44
|
+
|
|
45
|
+
A committed secret is compromised the moment it lands in a shared repo. The fix is always:
|
|
46
|
+
|
|
47
|
+
1. **Rotate first.** Issue a new credential at the provider and revoke the old one. Until this is done,
|
|
48
|
+
the secret is live regardless of repo state.
|
|
49
|
+
2. **Remove from code.** Replace with an env var or secret-manager reference.
|
|
50
|
+
3. **Purge from history** if required (history rewrite or, more often, treat as exposed and rely on
|
|
51
|
+
rotation — rewriting shared history is disruptive and incomplete if the repo was cloned/forked).
|
|
52
|
+
4. **Add prevention.** A pre-commit secret hook and a `.gitignore` entry so it doesn't recur.
|
|
53
|
+
|
|
54
|
+
> "Deleted the key in the latest commit" is **not** remediation. The credential is still valid at the
|
|
55
|
+
> provider and still present in every prior commit, clone, and CI cache.
|
|
56
|
+
|
|
57
|
+
## Writing the remediation line
|
|
58
|
+
|
|
59
|
+
Each finding's recommendation should be copy-pasteable and unambiguous:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
lodash 4.17.15 -> 4.17.21 | high | non-breaking | prototype-pollution CVE-2020-8203, reachable in util/merge.js
|
|
63
|
+
AWS key in config/old.env | critical | rotate | revoke in IAM, replace with env var, add pre-commit hook
|
|
64
|
+
debug=true in prod config | medium | config | set debug=false; leaks stack traces to clients
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Tie remediation effort to severity so the reader can plan: a *fix now* of ten non-breaking bumps is an
|
|
68
|
+
afternoon; one breaking major in *plan* may be a sprint. Make that tradeoff visible.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Scan Types and Tools
|
|
2
|
+
|
|
3
|
+
Vulnerability scanning is not one activity — it is a family of complementary techniques, each with a
|
|
4
|
+
different blind spot. A credible scan combines several. Use this reference to pick the right family for
|
|
5
|
+
the target and to understand what each one *cannot* see.
|
|
6
|
+
|
|
7
|
+
## SCA — Software Composition Analysis (dependency scanning)
|
|
8
|
+
|
|
9
|
+
Matches your resolved dependency versions against known-vulnerability databases (CVE/NVD, GitHub
|
|
10
|
+
Advisory, OSV).
|
|
11
|
+
|
|
12
|
+
- **Inputs:** lockfiles (`package-lock.json`, `pnpm-lock.yaml`, `poetry.lock`, `Cargo.lock`, `go.sum`).
|
|
13
|
+
Always read the **lockfile**, not the manifest range — `^1.2.0` tells you nothing about what shipped.
|
|
14
|
+
- **Strengths:** high-precision for *known* CVEs; cheap; covers transitive deps.
|
|
15
|
+
- **Blind spots:** zero-days, logic bugs, anything not yet in an advisory DB. Version-only matching can
|
|
16
|
+
over-report (advisory may need a specific feature flag).
|
|
17
|
+
- **Triage hook:** flag direct vs. transitive — a transitive CVE may be fixable only by bumping the
|
|
18
|
+
parent, or pinning via an override/resolution.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Inventory before judging — never trust the manifest range alone
|
|
22
|
+
node -e "const l=require('./package-lock.json');console.log(Object.keys(l.packages||{}).length,'resolved packages')"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Secret scanning
|
|
26
|
+
|
|
27
|
+
Finds credentials committed to the repo: API keys, tokens, private keys, connection strings,
|
|
28
|
+
high-entropy blobs.
|
|
29
|
+
|
|
30
|
+
- **Inputs:** working tree by default; git history when explicitly requested.
|
|
31
|
+
- **Detection:** known-format regexes (e.g. `AKIA…` AWS keys, `ghp_…` GitHub tokens, `-----BEGIN ...
|
|
32
|
+
PRIVATE KEY-----`) plus entropy heuristics.
|
|
33
|
+
- **Blind spots:** secrets in untracked files, encrypted blobs, or rotated-but-still-referenced values.
|
|
34
|
+
- **Critical rule:** a found secret is assumed compromised. Removal ≠ remediation. See
|
|
35
|
+
[remediation-and-severity](remediation-and-severity.md) for the rotation playbook.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Cheap first pass for common key formats (illustrative — a real scan uses a tool)
|
|
39
|
+
grep -rERn 'AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|-----BEGIN [A-Z ]*PRIVATE KEY-----' . \
|
|
40
|
+
--include='*.*' || echo "no obvious key-format matches"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## SAST — Static Application Security Testing
|
|
44
|
+
|
|
45
|
+
Analyzes source/AST for vulnerable patterns: injection sinks, unsafe deserialization, path traversal,
|
|
46
|
+
hardcoded crypto, tainted-data flows.
|
|
47
|
+
|
|
48
|
+
- **Strengths:** finds bugs in *your* code, not just dependencies; runs without deploying.
|
|
49
|
+
- **Blind spots:** high false-positive rate; struggles with dynamic dispatch and framework magic;
|
|
50
|
+
cannot judge runtime config.
|
|
51
|
+
- **Triage hook:** SAST output needs the heaviest false-positive filtering. Confirm the sink is
|
|
52
|
+
reachable with attacker-controlled input before alarming.
|
|
53
|
+
|
|
54
|
+
## DAST — Dynamic Application Security Testing
|
|
55
|
+
|
|
56
|
+
Probes a *running* application from the outside: injection, auth handling, misconfigured headers, TLS.
|
|
57
|
+
|
|
58
|
+
- **Strengths:** finds runtime/config issues SAST can't see; low false positives for what it confirms.
|
|
59
|
+
- **Blind spots:** only covers exercised endpoints; needs a deployed target; can be destructive.
|
|
60
|
+
- **Boundary:** this agent does **not** perform live DAST/exploitation — that is a pen-test activity.
|
|
61
|
+
Note when DAST is warranted and hand off.
|
|
62
|
+
|
|
63
|
+
## Container & IaC scanning
|
|
64
|
+
|
|
65
|
+
When a `Dockerfile`, image, or infra-as-code (Terraform, Kubernetes manifests) is present:
|
|
66
|
+
|
|
67
|
+
- **Base-image CVEs:** OS packages in the image carry their own advisories; a clean app on a stale base
|
|
68
|
+
image is still vulnerable.
|
|
69
|
+
- **Image hygiene:** running as root, secrets baked into layers, unpinned `latest` tags.
|
|
70
|
+
- **IaC misconfig:** public S3 buckets, `0.0.0.0/0` security groups, disabled encryption.
|
|
71
|
+
|
|
72
|
+
## Choosing per target
|
|
73
|
+
|
|
74
|
+
| Target present | Run | Primary risk caught |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| Lockfile | SCA | Known CVEs in deps |
|
|
77
|
+
| Any source | Secret scan + SAST | Leaked creds, injection sinks |
|
|
78
|
+
| Dockerfile / image | Container scan | Base-image CVEs, root, baked secrets |
|
|
79
|
+
| Terraform / k8s | IaC scan | Public exposure, weak crypto config |
|
|
80
|
+
| Deployed URL | DAST (hand off) | Runtime/config exploits |
|
|
81
|
+
|
|
82
|
+
No single family is sufficient. Combine, then triage everything through
|
|
83
|
+
[triage-and-false-positives](triage-and-false-positives.md).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Triage and False Positives
|
|
2
|
+
|
|
3
|
+
Triage is the difference between a security agent and a `grep` wrapper. Raw scanner output is a starting
|
|
4
|
+
point with a high noise floor; this reference is how you turn it into signal.
|
|
5
|
+
|
|
6
|
+
## The triage pipeline
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
raw findings
|
|
10
|
+
-> normalize (one schema: id, package, severity, location, source-tool)
|
|
11
|
+
-> dedupe (same CVE from SCA + container scan = one finding)
|
|
12
|
+
-> false-positive filter (suppress with a recorded reason)
|
|
13
|
+
-> reachability assessment (is the vulnerable path used/exposed?)
|
|
14
|
+
-> final severity (CVSS adjusted by reachability + impact)
|
|
15
|
+
-> rank + bucket (fix now / plan / accept-monitor)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The bundled `scripts/parse-scan-results.mjs` automates normalize + dedupe + severity sort. Human
|
|
19
|
+
judgment owns the false-positive and reachability steps.
|
|
20
|
+
|
|
21
|
+
## Deduplication
|
|
22
|
+
|
|
23
|
+
The same underlying CVE often appears from multiple tools and multiple dependency paths. Collapse them:
|
|
24
|
+
|
|
25
|
+
- Key on the advisory ID (CVE / GHSA) **plus** the affected package+version.
|
|
26
|
+
- Keep the highest-confidence source and union the locations.
|
|
27
|
+
- Count once in the summary. Reporting one CVE five times manufactures fake urgency and is a form of
|
|
28
|
+
alert fatigue.
|
|
29
|
+
|
|
30
|
+
## Identifying false positives
|
|
31
|
+
|
|
32
|
+
Common false positives and how to confirm them:
|
|
33
|
+
|
|
34
|
+
| Pattern | Why it's flagged | How to confirm it's benign |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| Example/placeholder secret | Matches a key regex | Value is `AKIAEXAMPLE…`, in `*.example`, or in test fixtures |
|
|
37
|
+
| Vendored test data | CVE in a bundled sample | Path is under `test/`, `fixtures/`, `__mocks__/` and not shipped |
|
|
38
|
+
| Unreachable CVE | Vulnerable function never called | `grep` for the import/call; if absent, code path is dead |
|
|
39
|
+
| Dev-only dependency | CVE in a build/test tool | Not in production bundle; lower severity, not zero |
|
|
40
|
+
| Feature-gated advisory | Applies only with a flag on | Confirm the flag/default; note the qualifier |
|
|
41
|
+
|
|
42
|
+
**Always record the suppression reason.** A silently dropped finding is indistinguishable from a missed
|
|
43
|
+
one. Put suppressed items in an "Accepted / suppressed" section with their justification.
|
|
44
|
+
|
|
45
|
+
## Reachability — the multiplier
|
|
46
|
+
|
|
47
|
+
Reachability is what separates theoretical from exploitable risk:
|
|
48
|
+
|
|
49
|
+
- **Exposed + reachable** (e.g. a deserialization CVE on a public POST handler): keep or raise severity.
|
|
50
|
+
- **Present but unreachable** (vulnerable parser never invoked): downgrade, schedule, don't block.
|
|
51
|
+
- **Dev/build-time only:** real but lower; an attacker needs supply-chain or CI access to exploit.
|
|
52
|
+
|
|
53
|
+
State the reasoning explicitly so a reviewer can overrule:
|
|
54
|
+
|
|
55
|
+
> CVE-2025-XXXX (CVSS 9.8) in `fast-xml@3.1.0`. The vulnerable `parseAttrs` path is only hit when
|
|
56
|
+
> `allowAttributes:true`; this app calls the parser with defaults. **Downgraded critical -> medium**,
|
|
57
|
+
> scheduled, not release-blocking.
|
|
58
|
+
|
|
59
|
+
## Avoiding alert fatigue
|
|
60
|
+
|
|
61
|
+
- Hard-rank. The top finding must be the genuinely most urgent, not the highest raw CVSS.
|
|
62
|
+
- Bucket aggressively: *fix now* should be short (single digits ideally). Everything else goes to
|
|
63
|
+
*plan* or *accept/monitor*.
|
|
64
|
+
- Push low/info findings into an appendix. Do not make a reader scroll past 200 lows to find the one
|
|
65
|
+
critical — that is how real issues get missed.
|
|
66
|
+
- Be consistent run-to-run so developers can diff reports and see what's new.
|
|
67
|
+
|
|
68
|
+
## When triage is genuinely uncertain
|
|
69
|
+
|
|
70
|
+
If you cannot determine reachability from static analysis alone, say so and assign provisional severity
|
|
71
|
+
on the conservative side, with a note on what would resolve the uncertainty (e.g. "needs DAST against
|
|
72
|
+
staging" or "confirm whether `module X` is in the production bundle"). Honest uncertainty beats false
|
|
73
|
+
confidence in either direction.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Normalizes a list of raw vulnerability findings: dedupes and sorts by
|
|
3
|
+
// triaged severity. Demonstrates the triage step (raw output -> ranked list)
|
|
4
|
+
// from this agent package. Zero dependencies; Node built-ins only.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// node parse-scan-results.mjs findings.json # read a JSON array from a file
|
|
8
|
+
// cat findings.json | node parse-scan-results.mjs # read from stdin
|
|
9
|
+
// node parse-scan-results.mjs --selftest # run built-in tests (exit 0/1)
|
|
10
|
+
//
|
|
11
|
+
// Input: JSON array of findings, each with at least { id, severity }.
|
|
12
|
+
// Optional fields: package, location, cvss, reachability, fix, bucket.
|
|
13
|
+
// Output: { total, deduped, bySeverity, findings } sorted critical -> info.
|
|
14
|
+
|
|
15
|
+
const SEVERITY_ORDER = ['critical', 'high', 'medium', 'low', 'info'];
|
|
16
|
+
const SEVERITY_RANK = Object.fromEntries(SEVERITY_ORDER.map((s, i) => [s, i]));
|
|
17
|
+
|
|
18
|
+
function normalizeSeverity(sev) {
|
|
19
|
+
const s = String(sev ?? '').toLowerCase().trim();
|
|
20
|
+
return SEVERITY_RANK[s] !== undefined ? s : 'info';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Dedup key: advisory id + affected package/location. The same CVE reported by
|
|
24
|
+
// multiple tools or via multiple paths collapses to one finding.
|
|
25
|
+
function dedupKey(f) {
|
|
26
|
+
const id = String(f.id ?? 'unknown').toLowerCase();
|
|
27
|
+
const where = String(f.package ?? f.location ?? '').toLowerCase();
|
|
28
|
+
return `${id}::${where}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function parseFindings(rawList) {
|
|
32
|
+
if (!Array.isArray(rawList)) {
|
|
33
|
+
throw new Error('input must be a JSON array of findings');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const seen = new Map();
|
|
37
|
+
for (const raw of rawList) {
|
|
38
|
+
const finding = { ...raw, severity: normalizeSeverity(raw.severity) };
|
|
39
|
+
const key = dedupKey(finding);
|
|
40
|
+
if (!seen.has(key)) {
|
|
41
|
+
seen.set(key, finding);
|
|
42
|
+
} else {
|
|
43
|
+
// Keep the higher severity when duplicates disagree.
|
|
44
|
+
const existing = seen.get(key);
|
|
45
|
+
if (SEVERITY_RANK[finding.severity] < SEVERITY_RANK[existing.severity]) {
|
|
46
|
+
seen.set(key, finding);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const findings = [...seen.values()].sort((a, b) => {
|
|
52
|
+
const d = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];
|
|
53
|
+
if (d !== 0) return d;
|
|
54
|
+
return String(a.id ?? '').localeCompare(String(b.id ?? ''));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const bySeverity = Object.fromEntries(SEVERITY_ORDER.map((s) => [s, 0]));
|
|
58
|
+
for (const f of findings) bySeverity[f.severity] += 1;
|
|
59
|
+
|
|
60
|
+
return { total: rawList.length, deduped: findings.length, bySeverity, findings };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function run(json) {
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(json);
|
|
67
|
+
} catch {
|
|
68
|
+
console.error('✗ invalid JSON input');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const result = parseFindings(parsed);
|
|
73
|
+
console.log(JSON.stringify(result, null, 2));
|
|
74
|
+
process.exit(0);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
console.error(`✗ ${err.message}`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function selftest() {
|
|
82
|
+
const raw = [
|
|
83
|
+
{ id: 'CVE-1', package: 'lodash@4.17.15', severity: 'high' },
|
|
84
|
+
{ id: 'CVE-1', package: 'lodash@4.17.15', severity: 'medium' }, // dup, lower sev
|
|
85
|
+
{ id: 'CVE-2', package: 'axios@0.21.0', severity: 'CRITICAL' }, // case-insensitive
|
|
86
|
+
{ id: 'CVE-3', package: 'jest@29', severity: 'low' },
|
|
87
|
+
{ id: 'SECRET-1', location: 'config/x.env', severity: 'critical' },
|
|
88
|
+
{ id: 'CVE-4', package: 'debug@4', severity: 'weird' }, // -> info
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const result = parseFindings(raw);
|
|
92
|
+
const checks = [];
|
|
93
|
+
|
|
94
|
+
// Dedup: 6 raw -> 5 unique (the two CVE-1 collapse).
|
|
95
|
+
checks.push(['dedupes duplicates', result.total === 6 && result.deduped === 5]);
|
|
96
|
+
|
|
97
|
+
// Duplicate keeps the higher severity (high, not medium).
|
|
98
|
+
const cve1 = result.findings.find((f) => f.id === 'CVE-1');
|
|
99
|
+
checks.push(['dup keeps higher severity', cve1 && cve1.severity === 'high']);
|
|
100
|
+
|
|
101
|
+
// Severity counts after normalization.
|
|
102
|
+
checks.push(['critical count is 2', result.bySeverity.critical === 2]);
|
|
103
|
+
checks.push(['high count is 1', result.bySeverity.high === 1]);
|
|
104
|
+
checks.push(['unknown severity -> info', result.bySeverity.info === 1]);
|
|
105
|
+
|
|
106
|
+
// Sort order: criticals first, info last.
|
|
107
|
+
const order = result.findings.map((f) => f.severity);
|
|
108
|
+
const sorted = [...order].sort(
|
|
109
|
+
(a, b) => SEVERITY_RANK[a] - SEVERITY_RANK[b]
|
|
110
|
+
);
|
|
111
|
+
checks.push(['sorted by severity', JSON.stringify(order) === JSON.stringify(sorted)]);
|
|
112
|
+
checks.push(['first finding is critical', order[0] === 'critical']);
|
|
113
|
+
checks.push(['last finding is info', order[order.length - 1] === 'info']);
|
|
114
|
+
|
|
115
|
+
let ok = true;
|
|
116
|
+
for (const [label, passed] of checks) {
|
|
117
|
+
console.log(`${passed ? '✓' : '✗'} ${label}`);
|
|
118
|
+
ok &&= passed;
|
|
119
|
+
}
|
|
120
|
+
process.exit(ok ? 0 : 1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const arg = process.argv[2];
|
|
124
|
+
if (arg === '--selftest') {
|
|
125
|
+
selftest();
|
|
126
|
+
} else if (arg) {
|
|
127
|
+
const { readFileSync } = await import('node:fs');
|
|
128
|
+
run(readFileSync(arg, 'utf8'));
|
|
129
|
+
} else {
|
|
130
|
+
let buf = '';
|
|
131
|
+
process.stdin.on('data', (c) => (buf += c));
|
|
132
|
+
process.stdin.on('end', () => run(buf));
|
|
133
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review-pack
|
|
3
|
+
description: Review pull requests faster and better — automated first-pass review, PR summaries reviewers can trust, healthy git workflow settings, conventional history, and query-performance checks, sequenced into one review pipeline.
|
|
4
|
+
type: pack
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
updated: 2026-07-10
|
|
7
|
+
agents: [code-reviewer, pr-summarizer]
|
|
8
|
+
skills: [git-collaboration-workflows, conventional-commits, sql-index-tuning]
|
|
9
|
+
---
|
|
10
|
+
# Code Review Pack
|
|
11
|
+
|
|
12
|
+
The review toolkit for teams whose bottleneck is the pull-request queue: get every PR a
|
|
13
|
+
fast, rigorous first pass, give human reviewers a summary they can trust, and keep the
|
|
14
|
+
workflow settings and history hygiene that make review scale. The value of the pack is the
|
|
15
|
+
**sequence** — which item runs at which moment of a PR's life — not the item list.
|
|
16
|
+
|
|
17
|
+
## Who this is for
|
|
18
|
+
|
|
19
|
+
Teams merging more PRs than their senior reviewers can deeply read; leads who want review
|
|
20
|
+
latency down without review quality collapsing; anyone inheriting a repo where "review"
|
|
21
|
+
means LGTM-stamping.
|
|
22
|
+
|
|
23
|
+
## What's included
|
|
24
|
+
|
|
25
|
+
- **Agents:** `code-reviewer` (rigorous first-pass review: correctness, security, tests,
|
|
26
|
+
maintainability), `pr-summarizer` (what changed, why, risk areas — the reviewer's map).
|
|
27
|
+
- **Skills:** `git-collaboration-workflows` (branch protection, PR sizing, merge strategy,
|
|
28
|
+
monorepo questions), `conventional-commits` (machine-readable history that powers
|
|
29
|
+
changelogs and bisect), `sql-index-tuning` (the query-performance review lens most teams
|
|
30
|
+
lack — N+1s and missing indexes are the top silent regressions PRs ship).
|
|
31
|
+
|
|
32
|
+
## The review pipeline (how the pieces sequence)
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
PR opened
|
|
36
|
+
1. pr-summarizer → posts the map: what changed, why, blast radius, files to read first
|
|
37
|
+
2. code-reviewer → first-pass findings: blocking / question / nit, with file:line
|
|
38
|
+
└─ SQL touched? → sql-index-tuning lens: EXPLAIN the new queries, check indexes
|
|
39
|
+
3. human reviewer → reads the summary + findings, spends attention ONLY on judgment
|
|
40
|
+
calls the machine flagged and the design questions it can't make
|
|
41
|
+
merge
|
|
42
|
+
4. conventional-commits → squash message feeds changelog + bisect-friendly history
|
|
43
|
+
weekly
|
|
44
|
+
5. git-collaboration-workflows → hygiene audit: branch age, PR size trend, protection drift
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The division of labor is the point: agents do coverage (every line, every time), humans do
|
|
48
|
+
judgment (architecture, product fit, taste). Teams that flip this — humans doing coverage,
|
|
49
|
+
no machine pass — get slow reviews AND missed bugs.
|
|
50
|
+
|
|
51
|
+
## Setup
|
|
52
|
+
|
|
53
|
+
1. Install the pack; wire `pr-summarizer` + `code-reviewer` to run on PR-open (CI job or
|
|
54
|
+
scheduled agent).
|
|
55
|
+
2. Apply the branch-protection settings from `git-collaboration-workflows`
|
|
56
|
+
(`examples/branch-protection.md`) — required checks, stale-review dismissal, squash-only.
|
|
57
|
+
3. Adopt the `blocking:/q:/nit:` comment convention from the PR review playbook; announce
|
|
58
|
+
the review SLO (first response < 4h).
|
|
59
|
+
4. Enable commit-lint per `conventional-commits` so the history contract is enforced, not
|
|
60
|
+
hoped for.
|
|
61
|
+
|
|
62
|
+
## Comment convention (adopt verbatim)
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
blocking: must be fixed before merge — correctness, security, data loss
|
|
66
|
+
q: genuine question; answer may resolve it
|
|
67
|
+
nit: author's call; NEVER blocks
|
|
68
|
+
(unprefixed comments read as blocking — prefix everything)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Pitfalls
|
|
72
|
+
|
|
73
|
+
- **LGTM-stamping past machine findings** — the pipeline's failure mode; blocking findings
|
|
74
|
+
must actually block, or reverts won't move.
|
|
75
|
+
- **Bot-nit fatigue** — untuned severity turns the first-pass reviewer into noise; demote
|
|
76
|
+
misfiring rules weekly during rollout (see `references/rollout-guide.md`).
|
|
77
|
+
- **Summaries as gospel on giant PRs** — a wrong map on a 2,000-line PR is an argument for
|
|
78
|
+
the size norms, not against the mapper.
|
|
79
|
+
- **Skipping the SQL lens** — missing-index regressions pass every test and fail at the
|
|
80
|
+
10× tenant; the `EXPLAIN` step is not optional when queries change.
|
|
81
|
+
- **Anti-pattern: humans doing coverage** — re-reading every line the machine read wastes
|
|
82
|
+
the scarce resource (judgment) on the abundant one (attention).
|
|
83
|
+
|
|
84
|
+
## When NOT to use this shape
|
|
85
|
+
|
|
86
|
+
Solo projects (review theater), and rubber-stamp compliance environments where findings
|
|
87
|
+
can't block merges anyway — fix the process authority first, then install tooling.
|
|
88
|
+
Edge case worth naming: generated code and vendored files should be excluded from both
|
|
89
|
+
summary and review scope up front, or they drown every real finding.
|
|
90
|
+
|
|
91
|
+
## Verification
|
|
92
|
+
|
|
93
|
+
After two weeks, three numbers should move: median time-to-first-review (down), PR size p50
|
|
94
|
+
(down — the summary+size norms push authors to split), and post-merge defect
|
|
95
|
+
reverts (down). If reverts didn't move, check whether `code-reviewer` findings are being
|
|
96
|
+
LGTM'd past — the pipeline only works when blocking findings block. A full worked PR
|
|
97
|
+
walkthrough lives in [examples/pr-flow-example.md](examples/pr-flow-example.md).
|
|
98
|
+
|
|
99
|
+
Pairs with the `secure-delivery-pack` (security-focused review lenses) and
|
|
100
|
+
`craftsmanship-pack` (refactoring and test depth beyond the review gate).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Worked Example — one PR through the pipeline
|
|
2
|
+
|
|
3
|
+
PR #512: "Add invoice CSV export" — 380 lines, touches API + a new query + one UI table.
|
|
4
|
+
|
|
5
|
+
## 1. pr-summarizer posts (2 min after open)
|
|
6
|
+
|
|
7
|
+
> **What**: New `GET /invoices/export.csv` endpoint (streaming), export button on the
|
|
8
|
+
> invoices table, `invoices_export` permission.
|
|
9
|
+
> **Why**: FEAT-201 — finance team needs monthly exports.
|
|
10
|
+
> **Read first**: `export-controller.ts` (new query!), `permissions.ts` (auth change).
|
|
11
|
+
> **Blast radius**: read-only endpoint; new DB query on `invoices` (potentially large);
|
|
12
|
+
> no schema change. **Risk**: memory on large exports, query performance.
|
|
13
|
+
|
|
14
|
+
## 2. code-reviewer posts (5 min after open)
|
|
15
|
+
|
|
16
|
+
> `blocking:` export-controller.ts:41 — query selects `*` and loads all rows into memory
|
|
17
|
+
> before streaming; a 500k-invoice tenant OOMs the pod. Stream with a cursor
|
|
18
|
+
> (keyset pagination) or use the DB driver's row stream.
|
|
19
|
+
>
|
|
20
|
+
> `blocking:` export-query.sql — `WHERE tenant_id = ? AND created_at > ?` has no
|
|
21
|
+
> supporting composite index (per sql-index-tuning: needs `(tenant_id, created_at)`;
|
|
22
|
+
> current plan is a seq scan at 2M rows — EXPLAIN attached).
|
|
23
|
+
>
|
|
24
|
+
> `q:` permissions.ts:88 — `invoices_export` granted to `member` by default; FEAT-201
|
|
25
|
+
> says finance-only. Intended?
|
|
26
|
+
>
|
|
27
|
+
> `nit:` csv column headers hardcoded English — project is i18n'd (`internationalization`).
|
|
28
|
+
|
|
29
|
+
## 3. Human reviewer (18 min later, reads summary + findings first)
|
|
30
|
+
|
|
31
|
+
Spends attention on the two judgment calls: confirms permission should be finance-only
|
|
32
|
+
(product check), and decides streaming approach (driver row-stream over keyset — simpler
|
|
33
|
+
here). Doesn't re-read the 300 lines the machine already covered line-by-line; spot-checks
|
|
34
|
+
the test file.
|
|
35
|
+
|
|
36
|
+
## 4. Author revises → checks green → squash-merge
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
feat(invoices): add streaming CSV export (FEAT-201)
|
|
40
|
+
|
|
41
|
+
Finance-only permission; keyset-cursor streaming; composite index
|
|
42
|
+
(tenant_id, created_at) added expand-only.
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Outcome ledger
|
|
46
|
+
|
|
47
|
+
- OOM prevented pre-merge (would have been a Sev-2 at month-end).
|
|
48
|
+
- Missing index caught before it met the 2M-row tenant.
|
|
49
|
+
- Human review time: ~20 min for a 380-line PR, spent entirely on judgment.
|
|
50
|
+
- History entry supports changelog + bisect.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Rollout Guide
|
|
2
|
+
|
|
3
|
+
Review culture changes fail when imposed all at once. The two-week sequence that lands:
|
|
4
|
+
|
|
5
|
+
## Week 1 — observation mode
|
|
6
|
+
|
|
7
|
+
- Wire `pr-summarizer` only. Zero friction, immediate value: every PR gets a map. Nobody
|
|
8
|
+
argues with a summary.
|
|
9
|
+
- Run `code-reviewer` in **comment-only** mode (findings posted, nothing blocks). The team
|
|
10
|
+
calibrates trust: are the findings real? (Tune severity thresholds now, while stakes are
|
|
11
|
+
low.)
|
|
12
|
+
- Baseline the three metrics: time-to-first-review, PR size p50, revert rate. You need the
|
|
13
|
+
"before" or the "after" is a vibe.
|
|
14
|
+
|
|
15
|
+
## Week 2 — the contract
|
|
16
|
+
|
|
17
|
+
- Turn on branch protection per the skill's settings (checks required, stale-dismissal,
|
|
18
|
+
squash-only). Announce it as config, with the escape hatch documented (hotfix label path).
|
|
19
|
+
- Adopt comment prefixes (`blocking:/q:/nit:`) and the 4-hour first-response SLO — put the
|
|
20
|
+
SLO on a dashboard where standup sees it.
|
|
21
|
+
- commit-lint on (warning for 3 days, then required).
|
|
22
|
+
|
|
23
|
+
## Weeks 3+ — enforcement earned
|
|
24
|
+
|
|
25
|
+
- `code-reviewer` blocking findings now actually block (the team has seen two weeks of its
|
|
26
|
+
judgment; false-positive rate is known and tuned).
|
|
27
|
+
- Weekly hygiene audit (`check-branch-hygiene.mjs`) posted to the team channel — trends,
|
|
28
|
+
not blame.
|
|
29
|
+
|
|
30
|
+
## Objection handling (you will hear these)
|
|
31
|
+
|
|
32
|
+
- **"The bot nitpicks."** Nits never block — that's what the prefix system encodes. Tune or
|
|
33
|
+
demote rules that misfire; the config is code-reviewable.
|
|
34
|
+
- **"Summaries are wrong sometimes."** They're maps, not territory — a wrong summary on a
|
|
35
|
+
2,000-line PR is an argument for smaller PRs, which the size norms fix.
|
|
36
|
+
- **"This slows us down."** The SLO + protection settings measurably speed up the queue;
|
|
37
|
+
show the week-1 baseline vs week-4. What slows teams is review latency and re-review
|
|
38
|
+
churn, both of which drop.
|
|
39
|
+
- **"Admins need bypass."** The bypass IS the vulnerability; the hotfix path exists and is
|
|
40
|
+
faster than arguing at 2 a.m.
|