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.
Files changed (195) hide show
  1. package/README.md +14 -0
  2. package/bin/vanara.js +66 -2
  3. package/catalog/agents/api-designer/AGENT.md +156 -0
  4. package/catalog/agents/api-designer/examples/openapi-snippet.yaml +130 -0
  5. package/catalog/agents/api-designer/examples/review-notes.md +61 -0
  6. package/catalog/agents/api-designer/references/contract-and-openapi.md +82 -0
  7. package/catalog/agents/api-designer/references/design-checklist.md +68 -0
  8. package/catalog/agents/api-designer/references/versioning-and-evolution.md +63 -0
  9. package/catalog/agents/api-designer/scripts/lint-openapi.mjs +180 -0
  10. package/catalog/agents/code-reviewer/AGENT.md +184 -0
  11. package/catalog/agents/code-reviewer/examples/pr-comment-template.md +48 -0
  12. package/catalog/agents/code-reviewer/examples/sample-review-output.md +38 -0
  13. package/catalog/agents/code-reviewer/references/review-checklist.md +46 -0
  14. package/catalog/agents/code-reviewer/references/security-review.md +62 -0
  15. package/catalog/agents/code-reviewer/references/severity-rubric.md +63 -0
  16. package/catalog/agents/code-reviewer/scripts/review-guard.mjs +102 -0
  17. package/catalog/agents/debugger/AGENT.md +128 -0
  18. package/catalog/agents/debugger/examples/postmortem-template.md +59 -0
  19. package/catalog/agents/debugger/examples/repro-template.md +50 -0
  20. package/catalog/agents/debugger/references/bisection.md +63 -0
  21. package/catalog/agents/debugger/references/debugging-method.md +57 -0
  22. package/catalog/agents/debugger/references/observability.md +61 -0
  23. package/catalog/agents/debugger/scripts/parse-stacktrace.mjs +109 -0
  24. package/catalog/agents/pr-summarizer/AGENT.md +172 -0
  25. package/catalog/agents/pr-summarizer/examples/sample-pr-summary.md +46 -0
  26. package/catalog/agents/pr-summarizer/examples/weak-vs-strong-summary.md +68 -0
  27. package/catalog/agents/pr-summarizer/references/identifying-risk.md +68 -0
  28. package/catalog/agents/pr-summarizer/references/reading-the-diff.md +68 -0
  29. package/catalog/agents/pr-summarizer/references/test-plan-and-missing-tests.md +64 -0
  30. package/catalog/agents/pr-summarizer/references/writing-the-summary.md +63 -0
  31. package/catalog/agents/pr-summarizer/scripts/diff-risk.mjs +111 -0
  32. package/catalog/agents/refactoring-specialist/AGENT.md +201 -0
  33. package/catalog/agents/refactoring-specialist/examples/before-after.md +91 -0
  34. package/catalog/agents/refactoring-specialist/examples/refactor-plan.md +97 -0
  35. package/catalog/agents/refactoring-specialist/references/large-scale-refactor.md +50 -0
  36. package/catalog/agents/refactoring-specialist/references/safe-workflow.md +75 -0
  37. package/catalog/agents/refactoring-specialist/references/smell-catalog.md +76 -0
  38. package/catalog/agents/refactoring-specialist/scripts/detect-smells.mjs +150 -0
  39. package/catalog/agents/security-auditor/AGENT.md +184 -0
  40. package/catalog/agents/security-auditor/examples/audit-report.md +68 -0
  41. package/catalog/agents/security-auditor/examples/finding-template.md +31 -0
  42. package/catalog/agents/security-auditor/references/audit-workflow.md +116 -0
  43. package/catalog/agents/security-auditor/references/severity-and-reporting.md +56 -0
  44. package/catalog/agents/security-auditor/references/vuln-classes.md +129 -0
  45. package/catalog/agents/security-auditor/scripts/scan-secrets.mjs +86 -0
  46. package/catalog/agents/technical-writer/AGENT.md +179 -0
  47. package/catalog/agents/technical-writer/examples/how-to-example.md +76 -0
  48. package/catalog/agents/technical-writer/examples/reference-example.md +75 -0
  49. package/catalog/agents/technical-writer/references/clarity-and-style.md +52 -0
  50. package/catalog/agents/technical-writer/references/diataxis-and-doc-types.md +61 -0
  51. package/catalog/agents/technical-writer/references/structure-and-maintenance.md +59 -0
  52. package/catalog/agents/technical-writer/scripts/readability.mjs +103 -0
  53. package/catalog/agents/test-author/AGENT.md +193 -0
  54. package/catalog/agents/test-author/examples/test-plan.md +54 -0
  55. package/catalog/agents/test-author/examples/unit-test-example.ts +55 -0
  56. package/catalog/agents/test-author/references/aaa-and-naming.md +75 -0
  57. package/catalog/agents/test-author/references/mocking-and-fixtures.md +94 -0
  58. package/catalog/agents/test-author/references/test-types-and-pyramid.md +60 -0
  59. package/catalog/agents/test-author/scripts/check-coverage.mjs +145 -0
  60. package/catalog/agents/threat-modeler/AGENT.md +179 -0
  61. package/catalog/agents/threat-modeler/examples/dfd-example.md +55 -0
  62. package/catalog/agents/threat-modeler/examples/threat-model.md +81 -0
  63. package/catalog/agents/threat-modeler/references/dfd-and-trust-boundaries.md +76 -0
  64. package/catalog/agents/threat-modeler/references/mitigation-catalog.md +77 -0
  65. package/catalog/agents/threat-modeler/references/stride-method.md +68 -0
  66. package/catalog/agents/threat-modeler/scripts/stride-checklist.mjs +183 -0
  67. package/catalog/agents/vuln-scanner/AGENT.md +162 -0
  68. package/catalog/agents/vuln-scanner/examples/finding-template.md +57 -0
  69. package/catalog/agents/vuln-scanner/examples/scan-report.md +49 -0
  70. package/catalog/agents/vuln-scanner/references/remediation-and-severity.md +68 -0
  71. package/catalog/agents/vuln-scanner/references/scan-types-and-tools.md +83 -0
  72. package/catalog/agents/vuln-scanner/references/triage-and-false-positives.md +73 -0
  73. package/catalog/agents/vuln-scanner/scripts/parse-scan-results.mjs +133 -0
  74. package/catalog/packs/code-review-pack/PACK.md +100 -0
  75. package/catalog/packs/code-review-pack/examples/pr-flow-example.md +50 -0
  76. package/catalog/packs/code-review-pack/references/rollout-guide.md +40 -0
  77. package/catalog/packs/security-pack/PACK.md +128 -0
  78. package/catalog/packs/security-pack/examples/owasp-vuln-triage-and-fix.md +66 -0
  79. package/catalog/packs/security-pack/examples/threat-model-then-audit.md +77 -0
  80. package/catalog/packs/security-pack/references/choosing-the-right-tool.md +37 -0
  81. package/catalog/packs/security-pack/references/threat-model-to-remediation.md +69 -0
  82. package/catalog/packs/security-pack/references/workflow.md +56 -0
  83. package/catalog/skills/api-pagination/SKILL.md +83 -0
  84. package/catalog/skills/api-pagination/examples/keyset-queries.sql +38 -0
  85. package/catalog/skills/api-pagination/examples/response-shapes.md +51 -0
  86. package/catalog/skills/api-pagination/references/consuming-pages.md +39 -0
  87. package/catalog/skills/api-pagination/references/counting-and-totals.md +41 -0
  88. package/catalog/skills/api-pagination/references/cursor-encoding.md +34 -0
  89. package/catalog/skills/api-pagination/scripts/check-cursor.mjs +51 -0
  90. package/catalog/skills/caching-strategies/SKILL.md +180 -0
  91. package/catalog/skills/caching-strategies/examples/http-cache-headers.md +82 -0
  92. package/catalog/skills/caching-strategies/examples/redis-cache-aside.js +110 -0
  93. package/catalog/skills/caching-strategies/references/cache-patterns.md +93 -0
  94. package/catalog/skills/caching-strategies/references/eviction-and-ttl.md +67 -0
  95. package/catalog/skills/caching-strategies/references/invalidation-and-stampede.md +99 -0
  96. package/catalog/skills/caching-strategies/scripts/ttl-jitter.mjs +99 -0
  97. package/catalog/skills/conventional-commits/SKILL.md +135 -0
  98. package/catalog/skills/conventional-commits/examples/commit-examples.md +60 -0
  99. package/catalog/skills/conventional-commits/examples/commitlint.config.js +31 -0
  100. package/catalog/skills/conventional-commits/references/breaking-changes-semver.md +50 -0
  101. package/catalog/skills/conventional-commits/references/scoping-commits.md +42 -0
  102. package/catalog/skills/conventional-commits/references/spec.md +78 -0
  103. package/catalog/skills/conventional-commits/scripts/lint-commit.mjs +97 -0
  104. package/catalog/skills/database-migrations/SKILL.md +137 -0
  105. package/catalog/skills/database-migrations/examples/add-column-safe.sql +34 -0
  106. package/catalog/skills/database-migrations/examples/migration-config.example.json +27 -0
  107. package/catalog/skills/database-migrations/references/expand-contract.md +74 -0
  108. package/catalog/skills/database-migrations/references/rollback-and-safety.md +71 -0
  109. package/catalog/skills/database-migrations/references/zero-downtime-changes.md +84 -0
  110. package/catalog/skills/database-migrations/scripts/check-migration-reversible.mjs +139 -0
  111. package/catalog/skills/error-handling-patterns/SKILL.md +136 -0
  112. package/catalog/skills/error-handling-patterns/examples/express-error-middleware.js +93 -0
  113. package/catalog/skills/error-handling-patterns/examples/result-pattern.ts +81 -0
  114. package/catalog/skills/error-handling-patterns/references/error-taxonomy.md +91 -0
  115. package/catalog/skills/error-handling-patterns/references/language-patterns.md +102 -0
  116. package/catalog/skills/error-handling-patterns/references/retry-and-backoff.md +76 -0
  117. package/catalog/skills/error-handling-patterns/scripts/lint-empty-catch.mjs +113 -0
  118. package/catalog/skills/git-collaboration-workflows/SKILL.md +104 -0
  119. package/catalog/skills/git-collaboration-workflows/examples/branch-protection.md +48 -0
  120. package/catalog/skills/git-collaboration-workflows/examples/pr-review-playbook.md +48 -0
  121. package/catalog/skills/git-collaboration-workflows/references/branching-models.md +52 -0
  122. package/catalog/skills/git-collaboration-workflows/references/history-hygiene.md +44 -0
  123. package/catalog/skills/git-collaboration-workflows/scripts/check-branch-hygiene.mjs +62 -0
  124. package/catalog/skills/owasp-top10/SKILL.md +112 -0
  125. package/catalog/skills/owasp-top10/examples/sql-injection-fix.md +33 -0
  126. package/catalog/skills/owasp-top10/examples/xss-fix.md +27 -0
  127. package/catalog/skills/owasp-top10/references/access-control.md +36 -0
  128. package/catalog/skills/owasp-top10/references/crypto-failures.md +29 -0
  129. package/catalog/skills/owasp-top10/references/injection.md +39 -0
  130. package/catalog/skills/owasp-top10/references/ssrf-and-design.md +35 -0
  131. package/catalog/skills/owasp-top10/scripts/scan-injection.mjs +73 -0
  132. package/catalog/skills/prompt-engineering/SKILL.md +100 -0
  133. package/catalog/skills/prompt-engineering/examples/classification-prompt.md +29 -0
  134. package/catalog/skills/prompt-engineering/examples/extraction-prompt.md +25 -0
  135. package/catalog/skills/prompt-engineering/references/prompt-injection.md +34 -0
  136. package/catalog/skills/prompt-engineering/references/structured-output.md +34 -0
  137. package/catalog/skills/prompt-engineering/references/techniques.md +33 -0
  138. package/catalog/skills/prompt-engineering/scripts/validate-output.mjs +71 -0
  139. package/catalog/skills/readme-writing/SKILL.md +176 -0
  140. package/catalog/skills/readme-writing/examples/README.template.md +73 -0
  141. package/catalog/skills/readme-writing/examples/good-readme-example.md +95 -0
  142. package/catalog/skills/readme-writing/references/anatomy.md +107 -0
  143. package/catalog/skills/readme-writing/references/maintenance.md +68 -0
  144. package/catalog/skills/readme-writing/references/writing-style.md +79 -0
  145. package/catalog/skills/readme-writing/scripts/lint-readme.mjs +117 -0
  146. package/catalog/skills/refactoring-patterns/SKILL.md +178 -0
  147. package/catalog/skills/refactoring-patterns/examples/extract-function.before-after.js +57 -0
  148. package/catalog/skills/refactoring-patterns/examples/replace-conditional-with-polymorphism.before-after.ts +63 -0
  149. package/catalog/skills/refactoring-patterns/references/code-smells.md +92 -0
  150. package/catalog/skills/refactoring-patterns/references/refactoring-catalog.md +78 -0
  151. package/catalog/skills/refactoring-patterns/references/safe-workflow.md +74 -0
  152. package/catalog/skills/refactoring-patterns/scripts/detect-smells.mjs +137 -0
  153. package/catalog/skills/rest-api-design/SKILL.md +147 -0
  154. package/catalog/skills/rest-api-design/examples/error-envelope.json +26 -0
  155. package/catalog/skills/rest-api-design/examples/orders-api.openapi.yaml +106 -0
  156. package/catalog/skills/rest-api-design/references/error-handling.md +43 -0
  157. package/catalog/skills/rest-api-design/references/pagination.md +41 -0
  158. package/catalog/skills/rest-api-design/references/status-codes.md +32 -0
  159. package/catalog/skills/rest-api-design/references/versioning.md +31 -0
  160. package/catalog/skills/rest-api-design/scripts/check-envelope.mjs +62 -0
  161. package/catalog/skills/secrets-management/SKILL.md +134 -0
  162. package/catalog/skills/secrets-management/examples/env-example.md +41 -0
  163. package/catalog/skills/secrets-management/examples/rotation-runbook.md +50 -0
  164. package/catalog/skills/secrets-management/references/leak-response.md +47 -0
  165. package/catalog/skills/secrets-management/references/rotation.md +46 -0
  166. package/catalog/skills/secrets-management/references/secret-managers.md +52 -0
  167. package/catalog/skills/secrets-management/scripts/detect-hardcoded.mjs +96 -0
  168. package/catalog/skills/secure-auth/SKILL.md +135 -0
  169. package/catalog/skills/secure-auth/examples/auth-flow.md +60 -0
  170. package/catalog/skills/secure-auth/examples/jwt-verify.ts +89 -0
  171. package/catalog/skills/secure-auth/references/auth-attacks.md +76 -0
  172. package/catalog/skills/secure-auth/references/oauth2-oidc.md +65 -0
  173. package/catalog/skills/secure-auth/references/password-hashing.md +70 -0
  174. package/catalog/skills/secure-auth/references/sessions-vs-jwt.md +69 -0
  175. package/catalog/skills/secure-auth/scripts/check-password-policy.mjs +114 -0
  176. package/catalog/skills/sql-index-tuning/SKILL.md +171 -0
  177. package/catalog/skills/sql-index-tuning/examples/explain-walkthrough.sql +91 -0
  178. package/catalog/skills/sql-index-tuning/examples/index-ddl.sql +67 -0
  179. package/catalog/skills/sql-index-tuning/references/btree-internals.md +58 -0
  180. package/catalog/skills/sql-index-tuning/references/composite-and-covering.md +60 -0
  181. package/catalog/skills/sql-index-tuning/references/reading-explain.md +54 -0
  182. package/catalog/skills/sql-index-tuning/references/selectivity-and-cardinality.md +62 -0
  183. package/catalog/skills/sql-index-tuning/scripts/suggest-index.mjs +213 -0
  184. package/catalog/skills/test-plan-design/SKILL.md +154 -0
  185. package/catalog/skills/test-plan-design/examples/test-case-template.md +45 -0
  186. package/catalog/skills/test-plan-design/examples/test-plan.md +57 -0
  187. package/catalog/skills/test-plan-design/references/case-design.md +79 -0
  188. package/catalog/skills/test-plan-design/references/risk-prioritization.md +58 -0
  189. package/catalog/skills/test-plan-design/references/test-pyramid.md +58 -0
  190. package/catalog/skills/test-plan-design/scripts/coverage-gaps.mjs +109 -0
  191. package/free-tier.json +15 -0
  192. package/package.json +15 -4
  193. package/premium-index.json +1 -0
  194. package/src/config.js +31 -1
  195. package/src/license.js +143 -0
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ // Runnable linter: scans source code for SWALLOWED errors — the #1 error-handling
3
+ // defect. Flags empty catch blocks, bare `except: pass`, no-op promise .catch
4
+ // handlers, and ignored Go errors. Use it in CI to fail builds that hide failures.
5
+ //
6
+ // Usage:
7
+ // node lint-empty-catch.mjs <file> [<file>...] # lint files, exit 1 if any findings
8
+ // echo '<code>' | node lint-empty-catch.mjs # lint code from stdin
9
+ // node lint-empty-catch.mjs --selftest # run built-in test cases
10
+ //
11
+ // Exit code: 0 = clean, 1 = swallowed errors found (or a selftest case failed).
12
+
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ // Each rule: a label and a regex matching a swallow anti-pattern.
16
+ // Patterns are intentionally conservative to limit false positives.
17
+ const RULES = [
18
+ // JS/TS/Java/C#: catch with an empty or whitespace/comment-only body.
19
+ ['empty catch block', /catch\s*(\([^)]*\))?\s*\{\s*(\/\/[^\n]*\s*|\/\*[\s\S]*?\*\/\s*)*\}/g],
20
+ // JS/TS: a promise .catch that does nothing.
21
+ ['no-op .catch handler', /\.catch\s*\(\s*\(?\s*[\w$]*\s*\)?\s*=>\s*\{\s*\}\s*\)/g],
22
+ // JS/TS: .catch(() => undefined) style swallow.
23
+ ['no-op .catch (returns nothing)', /\.catch\s*\(\s*\(?\s*[\w$]*\s*\)?\s*=>\s*(undefined|null|void 0)\s*\)/g],
24
+ // Python: bare except (optionally typed) whose only statement is pass.
25
+ ['python except: pass', /except\b[^\n:]*:\s*(\n\s*)?pass\b/g],
26
+ // Python: except whose only statement is `...` (ellipsis stub left in prod).
27
+ ['python except: ...', /except\b[^\n:]*:\s*(\n\s*)?\.\.\.\s*/g],
28
+ // Go: an `if err != nil` block that is empty.
29
+ ['go empty err check', /if\s+err\s*!=\s*nil\s*\{\s*\}/g],
30
+ ];
31
+
32
+ export function lint(source) {
33
+ const findings = [];
34
+ for (const [label, re] of RULES) {
35
+ re.lastIndex = 0;
36
+ let m;
37
+ while ((m = re.exec(source)) !== null) {
38
+ const line = source.slice(0, m.index).split('\n').length;
39
+ findings.push({ label, line });
40
+ if (m.index === re.lastIndex) re.lastIndex++; // guard against zero-width loops
41
+ }
42
+ }
43
+ findings.sort((a, b) => a.line - b.line);
44
+ return findings;
45
+ }
46
+
47
+ function lintLabeled(label, source) {
48
+ const findings = lint(source);
49
+ if (findings.length === 0) {
50
+ console.log(`✓ ${label}: no swallowed errors`);
51
+ return true;
52
+ }
53
+ console.error(`✗ ${label}: ${findings.length} swallowed error(s)`);
54
+ for (const f of findings) console.error(` line ${f.line}: ${f.label}`);
55
+ return false;
56
+ }
57
+
58
+ function selftest() {
59
+ // name starts with "clean" => expect 0 findings; otherwise expect >=1 finding.
60
+ const cases = {
61
+ bad_empty_catch: 'try { risky(); } catch (e) {}',
62
+ bad_catch_comment_only: 'try { risky(); } catch (e) {\n // ignore\n}',
63
+ bad_noop_promise_catch: 'doThing().catch(() => {});',
64
+ bad_noop_catch_undefined: 'doThing().catch(e => undefined);',
65
+ bad_python_except_pass: 'try:\n risky()\nexcept Exception:\n pass',
66
+ bad_python_except_ellipsis: 'try:\n risky()\nexcept ValueError:\n ...',
67
+ bad_go_empty_err: 'v, err := load()\nif err != nil {}\nuse(v)',
68
+ clean_handled_catch: 'try { risky(); } catch (e) {\n logger.error(e);\n throw e;\n}',
69
+ clean_handled_promise: 'doThing().catch(e => logger.error(e));',
70
+ clean_python_handled: 'try:\n risky()\nexcept Exception as e:\n log.error(e)\n raise',
71
+ clean_go_handled: 'v, err := load()\nif err != nil {\n return err\n}\nuse(v)',
72
+ };
73
+
74
+ let allExpected = true;
75
+ for (const [name, code] of Object.entries(cases)) {
76
+ const found = lint(code).length;
77
+ const shouldBeClean = name.startsWith('clean');
78
+ const isClean = found === 0;
79
+ const correct = isClean === shouldBeClean;
80
+ allExpected &&= correct;
81
+ console.log(
82
+ `${correct ? '✓' : '✗'} selftest ${name}: ${found} finding(s) ` +
83
+ `(expected ${shouldBeClean ? 'clean' : 'swallow'})`,
84
+ );
85
+ }
86
+ console.log(allExpected ? '\nAll selftest cases passed.' : '\nSelftest FAILED.');
87
+ process.exit(allExpected ? 0 : 1);
88
+ }
89
+
90
+ // --- CLI -------------------------------------------------------------------
91
+
92
+ const args = process.argv.slice(2);
93
+ if (args[0] === '--selftest') {
94
+ selftest();
95
+ } else if (args.length > 0) {
96
+ let clean = true;
97
+ for (const file of args) {
98
+ let src;
99
+ try {
100
+ src = readFileSync(file, 'utf8');
101
+ } catch {
102
+ console.error(`✗ ${file}: cannot read file`);
103
+ clean = false;
104
+ continue;
105
+ }
106
+ clean = lintLabeled(file, src) && clean;
107
+ }
108
+ process.exit(clean ? 0 : 1);
109
+ } else {
110
+ let buf = '';
111
+ process.stdin.on('data', (c) => (buf += c));
112
+ process.stdin.on('end', () => process.exit(lintLabeled('stdin', buf) ? 0 : 1));
113
+ }
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: git-collaboration-workflows
3
+ description: Run git collaboration that scales — trunk-based vs git-flow decided by deploy cadence, branch protection and required checks, PR sizing and review etiquette, monorepo vs polyrepo trade-offs, release branches and hotfixes, and history hygiene with disciplined merges.
4
+ type: skill
5
+ version: 1.0.0
6
+ updated: 2026-07-10
7
+ ---
8
+ # Git Collaboration Workflows
9
+
10
+ Git workflow debates are proxy wars over one variable: **how often you ship**. Choose the
11
+ branching model from your deploy cadence, enforce it with branch protection instead of
12
+ vigilance, and keep PRs small enough to review honestly. Deep detail in `references/`;
13
+ protection settings and a PR-review playbook in `examples/`; `scripts/check-branch-hygiene.mjs`
14
+ audits a repo's local hygiene.
15
+
16
+ ## Choosing the branching model
17
+
18
+ | You deploy… | Model | Shape |
19
+ |---|---|---|
20
+ | Continuously (SaaS default) | **Trunk-based** | Short-lived branches (<2 days) → main; release = deploy main; flags hide unfinished work |
21
+ | On a cadence (mobile, desktop) | Trunk + **release branches** | Cut `release/1.24` from main; only cherry-picked fixes land on it; tag ships |
22
+ | Multiple supported majors (enterprise, on-prem) | Trunk + long-lived release lines | Fix on main first, cherry-pick back (never the reverse) |
23
+
24
+ Full git-flow (develop + feature + release + hotfix branches) earns its complexity only in
25
+ the third row — adopted by SaaS teams it mostly adds merge ceremony and delays integration.
26
+ The deciding question is never taste; it's "what do we support in production simultaneously?"
27
+
28
+ ```text
29
+ trunk-based: main ──●──●──●──●──► release = deploy latest green main
30
+ cadence: main ──●──●──●──► release/1.24 ──●(cp)──tag 1.24.1
31
+ hotfix: branch from the SHIPPED TAG, fix, tag — then forward-port to main SAME DAY
32
+ ```
33
+
34
+ Mechanics of each and the hotfix path: `references/branching-models.md`.
35
+
36
+ ## Short-lived branches or bust
37
+
38
+ Integration pain grows superlinearly with branch age — two weeks of divergence is a merge
39
+ project. Working rules:
40
+
41
+ ```text
42
+ branch age < 2 days (rebase on main daily if longer is unavoidable)
43
+ PR size ≤ ~400 changed lines — review quality collapses beyond that
44
+ one PR one logical change (refactor ≠ behavior change ≠ formatting)
45
+ big features land dark in slices behind a flag (feature-flags-experimentation),
46
+ never in a long-lived feature branch
47
+ ```
48
+
49
+ Stacked PRs (chain of small dependent PRs) are the escape hatch when a change is genuinely
50
+ large: reviewable slices, one logical narrative — etiquette and mechanics in
51
+ `examples/pr-review-playbook.md`.
52
+
53
+ ## Protection is policy-as-config
54
+
55
+ Trust the settings, not the culture doc — `examples/branch-protection.md` has the full
56
+ recommended set. The load-bearing ones: required status checks (build + tests + lint, the
57
+ same gate for everyone including admins), required review (1 for most teams, 2 for
58
+ money/security paths via CODEOWNERS), **stale-review dismissal** (a re-push invalidates old
59
+ approvals), and linear history or squash-only merges so `main` reads as a changelog.
60
+ Conventional commit messages (`conventional-commits`) make that changelog machine-readable.
61
+
62
+ ## Merge strategy: pick one, encode it
63
+
64
+ - **Squash-merge** (default recommendation): PR = one commit on main; messy WIP commits
65
+ vanish; revert = one commit. Cost: intra-PR history lost — fine when PRs are small (rule
66
+ above).
67
+ - **Rebase-merge**: preserves commit series linearly — only worth it if authors curate
68
+ commits (interactive rebase discipline); otherwise you're preserving noise.
69
+ - **Merge commits**: keeps true topology; `main` becomes unreadable at scale. Reserve for
70
+ release-branch merges where the merge point *is* the information.
71
+ - Never mix by whim — one strategy per repo, enforced in settings. And **never rewrite
72
+ pushed shared history**; `revert` forward instead (`references/history-hygiene.md` covers
73
+ recovery, bisect, and blame-friendly practices).
74
+
75
+ ## Monorepo vs polyrepo (an ownership decision)
76
+
77
+ Monorepo buys atomic cross-cutting changes, one dependency graph, and universal refactors —
78
+ at the price of tooling (selective CI via path filters/affected-graphs, CODEOWNERS, merge
79
+ queues at scale). Polyrepo buys independent pace and clear boundaries — at the price of
80
+ version-matrix coordination (`release-coordination` in `deployment-strategies`) and
81
+ cross-repo changes becoming N-PR projects. Rule of thumb: one product surface + one deploy
82
+ train → monorepo; genuinely independent products/teams → polyrepo. The failure mode is the
83
+ *unmanaged* middle: 40 repos with hand-maintained version matrices and no contract tests.
84
+
85
+ ## Pitfalls
86
+
87
+ - Long-lived feature branches "to keep main stable" — main stays stable via checks and
88
+ flags; the branch just batches risk into one giant merge.
89
+ - `main` broken and normalized ("just skip that test") — a red main blocks everyone's
90
+ integration; fixing it outranks all feature work, and a merge queue prevents most of it.
91
+ - Force-push to shared branches — reflog archaeology for the whole team; protect against it
92
+ in settings.
93
+ - Review theater: 2,000-line PRs approved in 4 minutes — the size rule exists because
94
+ reviewers are human.
95
+ - Cherry-picking main→release without fixing main first — the fix vanishes in the next
96
+ release cut.
97
+
98
+ ## Verification
99
+
100
+ Run `node scripts/check-branch-hygiene.mjs` inside any repo: it reports stale branches,
101
+ oversized undelivered work, and non-linear history segments. Then diff your repo settings
102
+ against `examples/branch-protection.md`. Pairs with `conventional-commits`,
103
+ `ci-pipeline-design`, `code-review` practices in `deployment-strategies`, and
104
+ `feature-flags-experimentation`.
@@ -0,0 +1,48 @@
1
+ # Branch Protection — recommended settings
2
+
3
+ GitHub terminology; GitLab/Bitbucket equivalents in parentheses. Apply to `main` and all
4
+ `release/*` patterns.
5
+
6
+ ## Required (the load-bearing set)
7
+
8
+ | Setting | Value | Why |
9
+ |---|---|---|
10
+ | Require a pull request before merging | on | No direct pushes, no exceptions |
11
+ | Required approvals | 1 (2 via CODEOWNERS for `/payments`, `/auth`, `/infra`) | Match rigor to blast radius |
12
+ | Dismiss stale approvals on new commits | **on** | Re-push invalidates what was reviewed |
13
+ | Require review from Code Owners | on where CODEOWNERS exists | Routing, not gatekeeping |
14
+ | Require status checks to pass | build, test, lint, typecheck | The same bar for everyone |
15
+ | Require branches to be up to date / merge queue | merge queue when >10 merges/day | Kills "two green PRs, red main" |
16
+ | Require linear history (or squash-only) | on | main reads as changelog; bisect stays fast |
17
+ | Include administrators (no bypass) | **on** | The bypass you allow is the one used at the worst moment |
18
+ | Allow force pushes / deletions | **off** | Non-negotiable on shared branches |
19
+
20
+ ## Recommended
21
+
22
+ - **Require signed commits** on release branches (supply-chain posture; pairs with
23
+ provenance in `OPEN-CORE`-style distribution).
24
+ - **Conversation resolution required** — threads don't vanish on merge.
25
+ - Auto-delete head branches after merge — stale-branch hygiene by default.
26
+ - `CODEOWNERS` kept small and real: teams, not individuals (vacation-proof); every entry
27
+ answers "who must know about changes here", not "who wrote it once".
28
+
29
+ ## The escape hatch, designed
30
+
31
+ Emergencies happen; design the fast path so nobody disables protection:
32
+
33
+ - A `hotfix` label + on-call approver satisfies the review requirement (a second human, fast).
34
+ - Checks stay required — a hotfix that doesn't build isn't fast, it's twice.
35
+ - Break-glass audit: any settings change to protection pages an owner (settings drift is
36
+ how "temporary" bypasses become permanent).
37
+
38
+ ## CODEOWNERS sketch
39
+
40
+ ```
41
+ # Default: any senior reviewer team
42
+ * @org/reviewers
43
+ # Blast-radius paths: two approvals via team + specialist
44
+ /services/payments/ @org/payments @org/security
45
+ /auth/ @org/security
46
+ /infra/ @org/platform
47
+ /.github/ @org/platform # CI is code; protect the protector
48
+ ```
@@ -0,0 +1,48 @@
1
+ # PR & Review Playbook
2
+
3
+ ## Author side
4
+
5
+ - **Size**: ≤ ~400 changed lines. Bigger? Split: mechanical prep PRs (rename, extract,
6
+ format — trivially approvable) first, the behavior change last and small.
7
+ - **Stacked PRs** for large features: each PR one reviewable slice, description links the
8
+ stack ("2/5, builds on #341"). Land bottom-up; rebase the stack on each merge (tooling
9
+ helps; discipline suffices).
10
+ - **Description contract**: what + why + how-verified (test evidence, screenshots for UI),
11
+ plus rollback note if non-trivial ("revert cleanly" or the flag to flip). A reviewer
12
+ should know the intent before reading the diff.
13
+ - **Self-review first**: your own pass catches the debug prints and stray files; respect
14
+ reviewers' attention as the scarce resource it is.
15
+ - Draft PRs early for direction checks ("is this approach sane?") — cheaper than polished
16
+ wrongness.
17
+
18
+ ## Reviewer side
19
+
20
+ - **First response < 4 working hours; small PRs same-day.** Review latency sets integration
21
+ speed for the whole team — it IS the constraint, treat it like on-call.
22
+ - Review for: correctness, tests actually asserting behavior, security on tainted paths,
23
+ and "will the next reader understand this" — not personal style (the linter owns style;
24
+ what the linter doesn't own isn't blocking).
25
+ - **Prefix comments by weight**: `blocking:` (must fix), `q:` (genuine question),
26
+ `nit:` (author's call, never blocks). Unprefixed comments read as blocking — inflation
27
+ by default.
28
+ - Approve with nits rather than round-tripping for trivia; re-request only when something
29
+ `blocking:` changed.
30
+ - Big PR arrives anyway? First comment: "split suggestion", not 45 line-notes on code
31
+ that'll be rewritten.
32
+
33
+ ## Team mechanics
34
+
35
+ - **Review SLO on the dashboard** (median time-to-first-review) — what's measured gets
36
+ staffed.
37
+ - Rotate a daily "review goalie" who owns unblocking the queue before their own work.
38
+ - Disagreements past two round-trips move to a 10-minute call; write the resolution back
39
+ into the PR (the thread is the record).
40
+ - Merge is the author's job once approved (or auto-merge/queue) — approved-but-unmerged PRs
41
+ rot against main.
42
+
43
+ ## Anti-patterns, named
44
+
45
+ LGTM-stamping (approval without evidence of reading — ask one substantive question per
46
+ review as a personal rule) · drive-by rewrites in review comments (open your own follow-up
47
+ PR) · review as status hierarchy (junior reviews senior code; fresh eyes are the point) ·
48
+ the 47-comment style war (fix the linter config, apologize, move on).
@@ -0,0 +1,52 @@
1
+ # Branching Models in Detail
2
+
3
+ ## Trunk-based (continuous deploy)
4
+
5
+ ```
6
+ main ──●──●──●──●──●──●──► every merge deployable; deploy = promote latest green main
7
+ \feat-a (hours)
8
+ ●──● → PR → squash → main
9
+ ```
10
+
11
+ - Unfinished work ships **dark** behind flags — integration happens daily even when release
12
+ doesn't.
13
+ - A **merge queue** (GitHub merge queue / Bors-style) serializes merges and tests each
14
+ against the true post-merge state — eliminates "two green PRs, red main" races; adopt it
15
+ once merges/day > ~10.
16
+ - Broken main = full stop: auto-revert the offending merge (bot or on-call) rather than
17
+ fix-forward under pressure; the author re-lands calmly.
18
+
19
+ ## Release-branch overlay (cadence shipping)
20
+
21
+ ```
22
+ main ──●──●──●──●──●──●──►
23
+ \release/1.24 ──●(cp)──●(cp)──tag 1.24.0──tag 1.24.1
24
+ ```
25
+
26
+ - Cut from main at code-freeze; the branch only receives **cherry-picks** of fixes that
27
+ landed on main first (main-first is the invariant that prevents regressions in 1.25).
28
+ - Tag builds from the release branch; the tag, not the branch tip, is what shipped.
29
+ - Delete the branch when the version leaves support; tags are permanent.
30
+
31
+ ## Hotfix path (works in both models)
32
+
33
+ 1. Branch from the **shipped tag** (not main — main has moved).
34
+ 2. Fix, PR, tag `1.24.2` from the hotfix branch, ship.
35
+ 3. **Forward-port to main immediately** — the #1 hotfix failure is the fix missing from the
36
+ next regular release. A required "forward-ported? link" field in the hotfix PR template
37
+ is cheap insurance.
38
+
39
+ ## Multi-major support (enterprise/on-prem)
40
+
41
+ Long-lived `release/2.x`, `release/3.x` lines. Every fix: main first, then cherry-pick down
42
+ each supported line it applies to (automate with a cherry-pick bot + per-line labels).
43
+ Support-matrix discipline: each line has an EOL date published; EOL means the branch goes
44
+ read-only. The cost of each supported line is roughly a part-time engineer — price support
45
+ contracts accordingly.
46
+
47
+ ## Migration notes (git-flow → trunk-based)
48
+
49
+ Teams rarely regret the direction; the sequence that works: (1) merge queue + required
50
+ checks on main, (2) flags for the two in-flight epics, (3) shrink PR-size norms via review
51
+ culture, (4) delete `develop` — it's by then a stale mirror. Do (4) last; deleting develop
52
+ first just moves the long-lived-branch problem to feature branches.
@@ -0,0 +1,44 @@
1
+ # History Hygiene
2
+
3
+ History is a debugging tool and an audit trail; hygiene is what keeps `bisect`, `blame`, and
4
+ `revert` usable at 3 a.m.
5
+
6
+ ## The rules
7
+
8
+ - **Never rewrite pushed shared history.** `push --force` on main/release erases teammates'
9
+ reference points and CI provenance. Personal branches: force-push freely *before* review
10
+ starts; after review begins, prefer `--force-with-lease` (refuses if someone else pushed)
11
+ and only to your own branch.
12
+ - **Revert forward.** A bad merge on main gets `git revert -m 1 <merge>` (or revert of the
13
+ squash commit) — a new commit that undoes it. History stays true: the mistake happened,
14
+ the fix happened.
15
+ - **Atomic commits with why-messages.** Each commit builds and tests green (keeps bisect
16
+ honest); message body explains *why*, the diff already shows *what*
17
+ (`conventional-commits` for the format).
18
+ - Separate **mechanical churn from logic**: formatting/rename-only commits isolated (and
19
+ listed in `.git-blame-ignore-revs` so blame skips them — one config line saves years of
20
+ "blame says the formatter wrote everything").
21
+
22
+ ## Bisect discipline
23
+
24
+ `git bisect run ./test.sh` finds the breaking commit in log₂(n) steps — but only if commits
25
+ build independently (atomic rule above) and main is linear-ish (squash/rebase merges). A
26
+ history of "wip", "fix", "fix2" turns bisect from minutes into an afternoon of manual
27
+ skipping. This is the practical argument that wins the squash-merge debate.
28
+
29
+ ## Recovering from disasters
30
+
31
+ - Deleted branch / botched rebase: `git reflog` — every HEAD position for ~90 days; branch
32
+ from the lost SHA. Nothing pushed is ever really lost within the window.
33
+ - Committed secret: rotate the secret FIRST (history cleaning is not containment — clones
34
+ and CI logs exist), then scrub with `git filter-repo` and force-push with the whole
35
+ team coordinated. Treat as an incident (`secrets-management`), not a git trick.
36
+ - Wrong-branch commit: `git cherry-pick` it where it belongs, `git reset --keep` where it
37
+ doesn't (before push) or revert (after).
38
+
39
+ ## Large repos / large files
40
+
41
+ Binary assets and datasets: LFS from day one — retrofitting LFS after 2GB of PSDs are in
42
+ history requires a full rewrite event. Generated artifacts never get committed (CI rebuilds
43
+ them); a `check-branch-hygiene` finding of build outputs in git is a config bug in
44
+ `.gitignore`, fix at the root.
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ // Repo hygiene audit: stale branches, oversized in-flight work, non-linear
3
+ // history, and tracked build artifacts. Read-only. Run inside any git repo:
4
+ // node scripts/check-branch-hygiene.mjs [repo-path]
5
+ import { execFileSync } from 'node:child_process';
6
+
7
+ const repo = process.argv[2] ?? process.cwd();
8
+ const git = (...args) => {
9
+ try { return execFileSync('git', ['-C', repo, ...args], { encoding: 'utf8' }).trim(); }
10
+ catch { return ''; }
11
+ };
12
+
13
+ if (!git('rev-parse', '--is-inside-work-tree')) {
14
+ console.error(`Not a git repo: ${repo}`);
15
+ process.exit(1);
16
+ }
17
+
18
+ const findings = [];
19
+ const DAY = 86_400_000;
20
+ const main = git('symbolic-ref', 'refs/remotes/origin/HEAD').split('/').pop() ||
21
+ (git('rev-parse', '--verify', 'main') ? 'main' : 'master');
22
+
23
+ // 1. Stale local branches (> 14 days since last commit, not merged into main)
24
+ const branches = git('for-each-ref', 'refs/heads', '--format=%(refname:short)|%(committerdate:iso8601)')
25
+ .split('\n').filter(Boolean).map((l) => { const [name, date] = l.split('|'); return { name, date: new Date(date) }; });
26
+ for (const b of branches) {
27
+ if (b.name === main) continue;
28
+ const ageDays = Math.floor((Date.now() - b.date) / DAY);
29
+ const merged = git('branch', '--merged', main).includes(b.name);
30
+ if (merged && b.name !== main) findings.push(`merged-but-undeleted branch: ${b.name} — delete it`);
31
+ else if (ageDays > 14) findings.push(`stale branch: ${b.name} (${ageDays}d old) — rebase & land in slices, or delete`);
32
+ else if (ageDays > 2) findings.push(`aging branch: ${b.name} (${ageDays}d) — branch-age rule is <2 days`);
33
+ }
34
+
35
+ // 2. Oversized undelivered work on current branch vs main
36
+ const current = git('rev-parse', '--abbrev-ref', 'HEAD');
37
+ if (current && current !== main) {
38
+ const stat = git('diff', '--shortstat', `${main}...HEAD`);
39
+ const changed = [...stat.matchAll(/(\d+) (insertion|deletion)/g)].reduce((s, m) => s + Number(m[1]), 0);
40
+ if (changed > 400) findings.push(`current branch carries ${changed} changed lines vs ${main} — split (≤400/PR)`);
41
+ }
42
+
43
+ // 3. Non-linear history in recent main (merge commits other than PR merges pattern)
44
+ const merges = git('log', main, '--merges', '--oneline', '-n', '200').split('\n').filter(Boolean);
45
+ if (merges.length > 50) findings.push(`${merges.length}/200 recent ${main} commits are merge commits — consider squash/linear policy`);
46
+
47
+ // 4. Tracked files that look like build artifacts or secrets-adjacent
48
+ const tracked = git('ls-files').split('\n');
49
+ const artifactRe = /^(dist|build|out|node_modules)\/|\.(log|tmp)$/;
50
+ const secretRe = /(^|\/)\.env(\.|$)|id_rsa|\.pem$/;
51
+ const artifacts = tracked.filter((f) => artifactRe.test(f)).slice(0, 5);
52
+ const secretish = tracked.filter((f) => secretRe.test(f) && !f.endsWith('.example')).slice(0, 5);
53
+ if (artifacts.length) findings.push(`build artifacts tracked: ${artifacts.join(', ')} — .gitignore + git rm --cached`);
54
+ if (secretish.length) findings.push(`SECRET-SHAPED tracked files: ${secretish.join(', ')} — rotate + scrub (see history-hygiene.md)`);
55
+
56
+ // Report
57
+ if (findings.length === 0) {
58
+ console.log(`Hygiene clean: ${branches.length} branches, ${main} linear-enough, no artifacts tracked.`);
59
+ } else {
60
+ console.log(`Hygiene findings (${findings.length}):\n` + findings.map((f) => ` - ${f}`).join('\n'));
61
+ }
62
+ process.exit(secretish.length ? 1 : 0); // only secret-shaped files fail the check hard
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: owasp-top10
3
+ description: A deep prevention reference for the OWASP Top 10 web risks — broken access control, injection, crypto failures, insecure design, SSRF and more — with vulnerable-vs-fixed code, edge cases, and a runnable naive-vulnerability scanner.
4
+ type: skill
5
+ version: 2.0.0
6
+ updated: 2026-06-28
7
+ ---
8
+ # OWASP Top 10 Prevention
9
+
10
+ Most real-world breaches exploit a short, well-known list of weaknesses. This package is the deep
11
+ reference: each category gets its root cause, the default defense, and a vulnerable-vs-fixed example.
12
+ Category deep-dives live in `references/`, side-by-side fixes in `examples/`, and a runnable heuristic
13
+ scanner in `scripts/`.
14
+
15
+ > Based on the OWASP Top 10 (2021). The list shifts over time, but the underlying defenses are durable.
16
+
17
+ ## The list (and the one-line defense for each)
18
+
19
+ | # | Category | Default defense |
20
+ |---|---|---|
21
+ | A01 | **Broken Access Control** | Enforce authorization server-side on every action; deny by default; check ownership (stop IDOR). |
22
+ | A02 | **Cryptographic Failures** | TLS in transit; encrypt sensitive data at rest; hash passwords with argon2/bcrypt; never roll your own crypto. |
23
+ | A03 | **Injection** (SQL/cmd/XSS) | Parameterize queries; context-aware output encoding; never concatenate untrusted input. |
24
+ | A04 | **Insecure Design** | Threat-model before building; secure-by-design defaults; abuse-case thinking. |
25
+ | A05 | **Security Misconfiguration** | Harden defaults; disable debug in prod; least-privilege; remove unused features. |
26
+ | A06 | **Vulnerable Components** | Inventory dependencies; patch on a schedule; scan for CVEs (see `vuln-scanner` agent). |
27
+ | A07 | **Auth Failures** | Strong session handling, MFA, rate-limit logins, no credential stuffing surface (see `secure-auth`). |
28
+ | A08 | **Software & Data Integrity** | Verify signatures; secure CI/CD; don't deserialize untrusted data. |
29
+ | A09 | **Logging & Monitoring Failures** | Log security events, alert on them, don't log secrets (see `audit-logging`). |
30
+ | A10 | **SSRF** | Allow-list outbound destinations; validate/resolve URLs; block internal ranges. |
31
+
32
+ ## The two that cause the most damage
33
+
34
+ ### A01 — Broken Access Control (the #1 risk)
35
+ The bug: the server checks *authentication* (who you are) but not *authorization* (whether you may do
36
+ this specific thing). Classic IDOR — changing an ID in the URL to read someone else's data.
37
+
38
+ ```js
39
+ // VULNERABLE: any logged-in user can read any invoice by guessing an id
40
+ app.get('/invoices/:id', auth, async (req, res) => {
41
+ const invoice = await db.getInvoice(req.params.id);
42
+ res.json(invoice);
43
+ });
44
+
45
+ // FIXED: authorize against ownership, deny by default
46
+ app.get('/invoices/:id', auth, async (req, res) => {
47
+ const invoice = await db.getInvoice(req.params.id);
48
+ if (!invoice || invoice.ownerId !== req.user.id) return res.status(404).end(); // 404 hides existence
49
+ res.json(invoice);
50
+ });
51
+ ```
52
+ Deep-dive: `references/access-control.md`.
53
+
54
+ ### A03 — Injection
55
+ The bug: untrusted input is interpreted as code/query/markup. Defense is structural separation of code
56
+ from data.
57
+
58
+ ```js
59
+ // VULNERABLE: SQL injection
60
+ db.query(`SELECT * FROM users WHERE email = '${input}'`);
61
+
62
+ // FIXED: parameterized query — driver treats input strictly as data
63
+ db.query('SELECT * FROM users WHERE email = $1', [input]);
64
+ ```
65
+ SQL, command, and XSS variants with fixes: `references/injection.md` and `examples/sql-injection-fix.md`,
66
+ `examples/xss-fix.md`.
67
+
68
+ ## A worked SSRF case (A10)
69
+
70
+ ```js
71
+ // VULNERABLE: fetches any URL the user supplies -> attacker hits internal metadata service
72
+ const data = await fetch(req.query.url);
73
+
74
+ // FIXED: allow-list hosts and block internal ranges
75
+ const url = new URL(req.query.url);
76
+ if (!ALLOWED_HOSTS.has(url.hostname)) return res.status(400).json({ error: 'host not allowed' });
77
+ // ...plus resolve DNS and reject private IP ranges (169.254/16, 10/8, 127/8) to stop rebinding
78
+ ```
79
+ Detail and the private-range checks: `references/ssrf-and-design.md`.
80
+
81
+ ## Edge cases & gotchas
82
+
83
+ - **Blocklists fail; allow-lists work.** Trying to block "bad" input (e.g. stripping `<script>`) is
84
+ whack-a-mole — encode for the output context instead, and allow-list what's permitted.
85
+ - **404 vs 403 to avoid existence leakage.** For unauthorized access to a resource whose very existence
86
+ is sensitive, return `404`, not `403`, so attackers can't enumerate.
87
+ - **Mass assignment.** Binding request bodies straight to models lets attackers set fields like
88
+ `isAdmin`. Allow-list bindable fields.
89
+ - **Second-order injection.** Stored input that's safe on the way in can be unsafe when later used in a
90
+ different context (e.g. a stored value concatenated into a query). Defend at every sink.
91
+ - **Defense in depth.** No single control is enough — combine input validation, parameterization,
92
+ output encoding, authz checks, and monitoring.
93
+
94
+ ## When the "fix" isn't enough
95
+
96
+ Input sanitization alone is not a substitute for parameterization/encoding — it's a fragile add-on.
97
+ And security review (this skill + the `security-auditor` agent) catches code-level bugs, but design-level
98
+ flaws (A04) need **threat modeling up front** (see the `threat-modeler` agent) — you can't audit your
99
+ way out of an insecure design.
100
+
101
+ ## Files in this package
102
+
103
+ - `references/access-control.md` — A01 in depth: authz patterns, IDOR, mass assignment
104
+ - `references/injection.md` — A03: SQL/command/XSS with defenses per context
105
+ - `references/crypto-failures.md` — A02: hashing, encryption, key handling
106
+ - `references/ssrf-and-design.md` — A10 + A04: SSRF defense and secure design
107
+ - `examples/sql-injection-fix.md` — vulnerable vs parameterized, with edge cases
108
+ - `examples/xss-fix.md` — output encoding and safe rendering
109
+ - `scripts/scan-injection.mjs` — runnable heuristic scanner for naive injection patterns (selftest passes)
110
+
111
+ Pairs with the `security-auditor` agent, the `threat-modeler` agent, and the `secure-auth` and
112
+ `secrets-management` skills.
@@ -0,0 +1,33 @@
1
+ # Example: SQL Injection — Vulnerable vs Fixed
2
+
3
+ ## Vulnerable
4
+ ```js
5
+ // User-controlled `email` concatenated directly into SQL
6
+ app.post('/login', (req, res) => {
7
+ const { email, password } = req.body;
8
+ const row = db.query(
9
+ `SELECT * FROM users WHERE email = '${email}' AND password = '${password}'`
10
+ );
11
+ // input email = "' OR '1'='1' --" -> returns the first user, bypassing auth
12
+ });
13
+ ```
14
+
15
+ ## Fixed
16
+ ```js
17
+ app.post('/login', async (req, res) => {
18
+ const { email, password } = req.body;
19
+ const row = await db.query(
20
+ 'SELECT id, password_hash FROM users WHERE email = $1',
21
+ [email] // bound parameter — treated strictly as data
22
+ );
23
+ if (!row || !(await argon2.verify(row.password_hash, password))) {
24
+ return res.status(401).json({ error: { code: 'unauthorized', message: 'Invalid credentials' } });
25
+ }
26
+ });
27
+ ```
28
+
29
+ ## What changed & edge cases
30
+ - **Parameterized query** — the driver sends the SQL and the data separately, so injected SQL can't execute.
31
+ - **No password in SQL** — verify a hash, never compare plaintext passwords in the query.
32
+ - **Generic error** — don't reveal whether the email or the password was wrong (avoids user enumeration).
33
+ - **Second-order:** even values you stored earlier must be parameterized when reused in a query.
@@ -0,0 +1,27 @@
1
+ # Example: XSS — Vulnerable vs Fixed
2
+
3
+ ## Vulnerable (DOM XSS)
4
+ ```js
5
+ // Renders untrusted comment as HTML -> <img src=x onerror=stealCookies()> executes
6
+ commentEl.innerHTML = comment.text;
7
+ ```
8
+
9
+ ## Fixed
10
+ ```js
11
+ // Assign as text — the browser never parses it as HTML
12
+ commentEl.textContent = comment.text;
13
+ ```
14
+
15
+ ## Fixed (when you must render rich HTML)
16
+ ```js
17
+ import DOMPurify from 'dompurify';
18
+ commentEl.innerHTML = DOMPurify.sanitize(comment.html); // vetted sanitizer, allow-list of tags
19
+ ```
20
+
21
+ ## Framework note & edge cases
22
+ - React/Vue auto-escape by default — the risk is the escape hatch (`dangerouslySetInnerHTML`, `v-html`).
23
+ - **Encode for the context:** HTML body vs attribute vs URL vs inline JS each need different encoding.
24
+ `textContent` handles the body case; a value placed into an `href` needs URL validation
25
+ (`javascript:` URLs are an XSS vector).
26
+ - **Don't regex-strip tags** — it's bypassable. Use a maintained sanitizer or encode for output.
27
+ - Pair with a **Content-Security-Policy** as defense-in-depth so injected scripts won't run.