@xenos1996/usa 2.0.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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +335 -0
  3. package/USA.md +597 -0
  4. package/dist/bootstrap/catalog.d.ts +46 -0
  5. package/dist/bootstrap/catalog.d.ts.map +1 -0
  6. package/dist/bootstrap/catalog.js +312 -0
  7. package/dist/bootstrap/catalog.js.map +1 -0
  8. package/dist/bootstrap/index.d.ts +36 -0
  9. package/dist/bootstrap/index.d.ts.map +1 -0
  10. package/dist/bootstrap/index.js +177 -0
  11. package/dist/bootstrap/index.js.map +1 -0
  12. package/dist/cli.d.ts +5 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +706 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/config.d.ts +7 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +88 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/detect/index.d.ts +58 -0
  21. package/dist/detect/index.d.ts.map +1 -0
  22. package/dist/detect/index.js +329 -0
  23. package/dist/detect/index.js.map +1 -0
  24. package/dist/engine/audit.d.ts +32 -0
  25. package/dist/engine/audit.d.ts.map +1 -0
  26. package/dist/engine/audit.js +366 -0
  27. package/dist/engine/audit.js.map +1 -0
  28. package/dist/engine/diff.d.ts +24 -0
  29. package/dist/engine/diff.d.ts.map +1 -0
  30. package/dist/engine/diff.js +136 -0
  31. package/dist/engine/diff.js.map +1 -0
  32. package/dist/engine/evaluate.d.ts +19 -0
  33. package/dist/engine/evaluate.d.ts.map +1 -0
  34. package/dist/engine/evaluate.js +377 -0
  35. package/dist/engine/evaluate.js.map +1 -0
  36. package/dist/engine/gate.d.ts +19 -0
  37. package/dist/engine/gate.d.ts.map +1 -0
  38. package/dist/engine/gate.js +47 -0
  39. package/dist/engine/gate.js.map +1 -0
  40. package/dist/engine/loader.d.ts +37 -0
  41. package/dist/engine/loader.d.ts.map +1 -0
  42. package/dist/engine/loader.js +388 -0
  43. package/dist/engine/loader.js.map +1 -0
  44. package/dist/engine/maturity.d.ts +20 -0
  45. package/dist/engine/maturity.d.ts.map +1 -0
  46. package/dist/engine/maturity.js +157 -0
  47. package/dist/engine/maturity.js.map +1 -0
  48. package/dist/engine/score.d.ts +19 -0
  49. package/dist/engine/score.d.ts.map +1 -0
  50. package/dist/engine/score.js +141 -0
  51. package/dist/engine/score.js.map +1 -0
  52. package/dist/engine/sections.d.ts +14 -0
  53. package/dist/engine/sections.d.ts.map +1 -0
  54. package/dist/engine/sections.js +50 -0
  55. package/dist/engine/sections.js.map +1 -0
  56. package/dist/evolution/benchmark.d.ts +12 -0
  57. package/dist/evolution/benchmark.d.ts.map +1 -0
  58. package/dist/evolution/benchmark.js +107 -0
  59. package/dist/evolution/benchmark.js.map +1 -0
  60. package/dist/evolution/capability.d.ts +22 -0
  61. package/dist/evolution/capability.d.ts.map +1 -0
  62. package/dist/evolution/capability.js +69 -0
  63. package/dist/evolution/capability.js.map +1 -0
  64. package/dist/evolution/coverage.d.ts +15 -0
  65. package/dist/evolution/coverage.d.ts.map +1 -0
  66. package/dist/evolution/coverage.js +65 -0
  67. package/dist/evolution/coverage.js.map +1 -0
  68. package/dist/evolution/gap.d.ts +10 -0
  69. package/dist/evolution/gap.d.ts.map +1 -0
  70. package/dist/evolution/gap.js +52 -0
  71. package/dist/evolution/gap.js.map +1 -0
  72. package/dist/evolution/propose.d.ts +50 -0
  73. package/dist/evolution/propose.d.ts.map +1 -0
  74. package/dist/evolution/propose.js +188 -0
  75. package/dist/evolution/propose.js.map +1 -0
  76. package/dist/evolution/queue.d.ts +64 -0
  77. package/dist/evolution/queue.d.ts.map +1 -0
  78. package/dist/evolution/queue.js +192 -0
  79. package/dist/evolution/queue.js.map +1 -0
  80. package/dist/evolution/release.d.ts +11 -0
  81. package/dist/evolution/release.d.ts.map +1 -0
  82. package/dist/evolution/release.js +55 -0
  83. package/dist/evolution/release.js.map +1 -0
  84. package/dist/evolution/run.d.ts +88 -0
  85. package/dist/evolution/run.d.ts.map +1 -0
  86. package/dist/evolution/run.js +258 -0
  87. package/dist/evolution/run.js.map +1 -0
  88. package/dist/evolution/schedule.d.ts +59 -0
  89. package/dist/evolution/schedule.d.ts.map +1 -0
  90. package/dist/evolution/schedule.js +77 -0
  91. package/dist/evolution/schedule.js.map +1 -0
  92. package/dist/evolution/types.d.ts +174 -0
  93. package/dist/evolution/types.d.ts.map +1 -0
  94. package/dist/evolution/types.js +8 -0
  95. package/dist/evolution/types.js.map +1 -0
  96. package/dist/index.d.ts +36 -0
  97. package/dist/index.d.ts.map +1 -0
  98. package/dist/index.js +30 -0
  99. package/dist/index.js.map +1 -0
  100. package/dist/learn/index.d.ts +27 -0
  101. package/dist/learn/index.d.ts.map +1 -0
  102. package/dist/learn/index.js +196 -0
  103. package/dist/learn/index.js.map +1 -0
  104. package/dist/report/markdown.d.ts +16 -0
  105. package/dist/report/markdown.d.ts.map +1 -0
  106. package/dist/report/markdown.js +488 -0
  107. package/dist/report/markdown.js.map +1 -0
  108. package/dist/snapshot/index.d.ts +55 -0
  109. package/dist/snapshot/index.d.ts.map +1 -0
  110. package/dist/snapshot/index.js +76 -0
  111. package/dist/snapshot/index.js.map +1 -0
  112. package/dist/store/index.d.ts +31 -0
  113. package/dist/store/index.d.ts.map +1 -0
  114. package/dist/store/index.js +69 -0
  115. package/dist/store/index.js.map +1 -0
  116. package/dist/types.d.ts +287 -0
  117. package/dist/types.d.ts.map +1 -0
  118. package/dist/types.js +16 -0
  119. package/dist/types.js.map +1 -0
  120. package/dist/util/glob.d.ts +11 -0
  121. package/dist/util/glob.d.ts.map +1 -0
  122. package/dist/util/glob.js +86 -0
  123. package/dist/util/glob.js.map +1 -0
  124. package/dist/util/project.d.ts +90 -0
  125. package/dist/util/project.d.ts.map +1 -0
  126. package/dist/util/project.js +636 -0
  127. package/dist/util/project.js.map +1 -0
  128. package/dist/util/yaml.d.ts +28 -0
  129. package/dist/util/yaml.d.ts.map +1 -0
  130. package/dist/util/yaml.js +48 -0
  131. package/dist/util/yaml.js.map +1 -0
  132. package/package.json +94 -0
  133. package/rules/core/architecture.yaml +190 -0
  134. package/rules/core/cicd.yaml +212 -0
  135. package/rules/core/code-quality.yaml +261 -0
  136. package/rules/core/dependencies.yaml +132 -0
  137. package/rules/core/documentation.yaml +119 -0
  138. package/rules/core/future-readiness.yaml +91 -0
  139. package/rules/core/release.yaml +131 -0
  140. package/rules/core/repo.yaml +313 -0
  141. package/rules/core/security.yaml +496 -0
  142. package/rules/core/supply-chain.yaml +357 -0
  143. package/rules/core/testing.yaml +266 -0
  144. package/rules/detectors.yaml +2028 -0
  145. package/rules/index.yaml +42 -0
  146. package/rules/profiles/maturity.yaml +135 -0
  147. package/rules/stacks/ai-era.yaml +193 -0
  148. package/rules/stacks/api-backend.yaml +121 -0
  149. package/rules/stacks/cli.yaml +105 -0
  150. package/rules/stacks/compliance.yaml +157 -0
  151. package/rules/stacks/containers.yaml +124 -0
  152. package/rules/stacks/data.yaml +165 -0
  153. package/rules/stacks/go.yaml +134 -0
  154. package/rules/stacks/iac.yaml +128 -0
  155. package/rules/stacks/jvm.yaml +150 -0
  156. package/rules/stacks/ml-ai.yaml +140 -0
  157. package/rules/stacks/mobile.yaml +121 -0
  158. package/rules/stacks/node-typescript.yaml +166 -0
  159. package/rules/stacks/python.yaml +175 -0
  160. package/rules/stacks/rust.yaml +129 -0
  161. package/rules/stacks/solidity.yaml +139 -0
  162. package/rules/stacks/swift.yaml +100 -0
  163. package/rules/stacks/web-frontend.yaml +159 -0
@@ -0,0 +1,357 @@
1
+ id: core/supply-chain
2
+ title: Supply Chain & Build Provenance
3
+ section: S3
4
+ section_title: Supply Chain & Build Provenance
5
+ description: >
6
+ Promoted to its own section in USA. You can write perfect code and still
7
+ ship someone else's backdoor: these controls cover the path from a
8
+ contributor's editor to the artifact your users run.
9
+ Aligned with SLSA v1.2, NIST SSDF (SP 800-218), and the OpenSSF Scorecard.
10
+ version: '1.0'
11
+
12
+ rules:
13
+ - id: SUP-001
14
+ title: A lockfile is committed
15
+ section: S3
16
+ section_title: Supply Chain & Build Provenance
17
+ severity: HIGH
18
+ class: supply-chain
19
+ check:
20
+ kind: any_file
21
+ patterns:
22
+ - 'package-lock.json'
23
+ - 'yarn.lock'
24
+ - 'pnpm-lock.yaml'
25
+ - 'bun.lockb'
26
+ - 'bun.lock'
27
+ - 'poetry.lock'
28
+ - 'uv.lock'
29
+ - 'pdm.lock'
30
+ - 'Pipfile.lock'
31
+ - 'Cargo.lock'
32
+ - 'go.sum'
33
+ - 'composer.lock'
34
+ - 'Gemfile.lock'
35
+ - 'flake.lock'
36
+ why: 'Without a lockfile every install resolves fresh, so your build is not reproducible and transitive hijacks go unnoticed.'
37
+ remediation: 'Commit the lockfile for your package manager and install with the frozen/immutable flag in CI.'
38
+ references: ['SLSA-Source', 'OpenSSF-Scorecard:Pinned-Dependencies', 'NIST-SSDF-PS.3.2']
39
+
40
+ - id: SUP-002
41
+ title: CI installs with a frozen lockfile
42
+ section: S3
43
+ section_title: Supply Chain & Build Provenance
44
+ severity: MEDIUM
45
+ class: supply-chain
46
+ applies_when: { fact: 'has:ci' }
47
+ check:
48
+ kind: grep_present
49
+ pattern: '(npm ci|npm install --frozen|--frozen-lockfile|--immutable|pip install --require-hashes|pipenv sync|cargo build --locked|--locked)'
50
+ include: ['**/*.{yml,yaml,sh,bash,toml,Makefile,mk,justfile,just}']
51
+ exclude: ['**/node_modules/**']
52
+ flags: i
53
+ why: '`npm install` in CI silently upgrades you. A frozen install fails loudly instead.'
54
+ remediation: 'Use `npm ci` (or `--frozen-lockfile` / `--immutable` / `--locked`) everywhere in CI.'
55
+ references: ['NIST-SSDF-PS.3.2', 'SLSA-Build-L1']
56
+
57
+ - id: SUP-003
58
+ title: Dependency versions are pinned, not floating
59
+ section: S3
60
+ section_title: Supply Chain & Build Provenance
61
+ severity: MEDIUM
62
+ class: supply-chain
63
+ check:
64
+ kind: grep_absent
65
+ # NOTE: every range operator must be listed, not just the `0.0` forms —
66
+ # an earlier revision missed `^1.2.3`, `~1.2`, `>=1.0` and `1.x`, so the
67
+ # most common floating ranges passed as "pinned". Exact versions
68
+ # (`"18.3.1"`) still pass: no alternative matches a bare digit run.
69
+ pattern: ':\s*[''"]?(\*|latest|x|~|\^|>=?|>|<=?|<|\d+\.[xX])[''"]?\s*[,}]'
70
+ include:
71
+ ['package.json', 'bower.json', 'composer.json', 'pyproject.toml', 'requirements*.txt']
72
+ exclude: []
73
+ flags: i
74
+ why: '`*` and `latest` mean a compromised publish lands in your build with no code review.'
75
+ remediation: 'Pin exact versions for applications. Ranges are acceptable for published libraries with a lockfile.'
76
+ references: ['OpenSSF-Scorecard:Pinned-Dependencies', 'NIST-SSDF-PS.3.2']
77
+
78
+ - id: SUP-004
79
+ title: Automated dependency updates are configured
80
+ section: S3
81
+ section_title: Supply Chain & Build Provenance
82
+ severity: MEDIUM
83
+ class: supply-chain
84
+ check:
85
+ kind: any_file
86
+ patterns:
87
+ [
88
+ '.github/dependabot.yml',
89
+ '.gitlab/dependabot.yml',
90
+ 'renovate.json',
91
+ 'renovate.json5',
92
+ '.github/renovate.json',
93
+ '.renovaterc',
94
+ '.renovaterc.json',
95
+ ]
96
+ why: 'The only thing worse than updating dependencies is updating them two years late, all at once.'
97
+ remediation: 'Enable Dependabot or Renovate with grouped PRs and a weekly schedule.'
98
+ references: ['OpenSSF-Scorecard:Dependency-Update-Tool', 'NIST-SSDF-PW.4']
99
+
100
+ - id: SUP-005
101
+ title: Dependency vulnerability scanning runs in CI
102
+ section: S3
103
+ section_title: Supply Chain & Build Provenance
104
+ severity: HIGH
105
+ class: supply-chain
106
+ applies_when: { fact: 'has:ci' }
107
+ check:
108
+ kind: grep_present
109
+ pattern: '(npm audit|pnpm audit|yarn audit|pip-audit|osv-scanner|snyk (test|monitor)|trivy (fs|repo)|grype|dependency-check|govulncheck|cargo audit|bundler-audit)'
110
+ include:
111
+ [
112
+ '.github/workflows/*.yml',
113
+ '.github/workflows/*.yaml',
114
+ '.gitlab-ci.yml',
115
+ 'Jenkinsfile',
116
+ '.circleci/config.yml',
117
+ 'azure-pipelines.yml',
118
+ ]
119
+ flags: i
120
+ why: 'Most breaches in modern stacks arrive through a transitive dependency, not your own code.'
121
+ remediation: 'Add a scanner step that fails on HIGH/CRITICAL advisories; wire it to your advisory source (OSV/GHSA).'
122
+ references: ['OpenSSF-Scorecard:Vulnerabilities', 'NIST-SSDF-RV.1.1', 'SLSA']
123
+
124
+ - id: SUP-006
125
+ title: SAST runs in CI
126
+ section: S3
127
+ section_title: Supply Chain & Build Provenance
128
+ severity: MEDIUM
129
+ class: supply-chain
130
+ applies_when: { fact: 'has:ci' }
131
+ check:
132
+ kind: grep_present
133
+ pattern: '(codeql|semgrep|snyk code|sonar|bandit|gosec|brakeman|clippy-sarif|eslint-plugin-security|spotbugs|detekt)'
134
+ include:
135
+ [
136
+ '.github/workflows/*.yml',
137
+ '.github/workflows/*.yaml',
138
+ '.gitlab-ci.yml',
139
+ 'Jenkinsfile',
140
+ '.circleci/config.yml',
141
+ ]
142
+ flags: i
143
+ why: 'Static analysis catches the bug class a reviewer skips at 5pm on a Friday.'
144
+ remediation: 'Add CodeQL or Semgrep with a ruleset tuned to your stack; block on new high-confidence findings only.'
145
+ references: ['OpenSSF-Scorecard:SAST', 'NIST-SSDF-RV.1.1']
146
+
147
+ - id: SUP-007
148
+ title: Secret scanning runs in CI
149
+ section: S3
150
+ section_title: Supply Chain & Build Provenance
151
+ severity: MEDIUM
152
+ class: supply-chain
153
+ applies_when: { fact: 'has:ci' }
154
+ check:
155
+ kind: grep_present
156
+ pattern: '(gitleaks|trufflehog|detect-secrets|secretlint|git-secrets|secret scanning)'
157
+ include:
158
+ [
159
+ '.github/workflows/*.yml',
160
+ '.github/workflows/*.yaml',
161
+ '.gitlab-ci.yml',
162
+ '.pre-commit-config.yaml',
163
+ ]
164
+ flags: i
165
+ why: 'A pre-commit secret scan is the cheapest control in this entire template.'
166
+ remediation: 'Add gitleaks as a pre-commit hook and a CI job on pull_request.'
167
+ references: ['OpenSSF-Scorecard:Binary-Artifacts', 'NIST-SSDF-PO.3']
168
+
169
+ - id: SUP-008
170
+ title: CI workflows avoid script-injection patterns
171
+ section: S3
172
+ section_title: Supply Chain & Build Provenance
173
+ severity: HIGH
174
+ class: supply-chain
175
+ applies_when: { fact: 'ci:github-actions' }
176
+ check:
177
+ kind: grep_absent
178
+ pattern: '\$\{\{\s*github\.event\.(pull_request|issue|comment|discussion|review)\.[^}]*\}\}'
179
+ include: ['.github/workflows/*.yml', '.github/workflows/*.yaml']
180
+ why: 'Interpolating untrusted event data into a `run:` block is arbitrary code execution on your runner — and on your secrets.'
181
+ remediation: 'Pass event data through `env:` and reference it as a shell variable instead of ${{ }} inside run.'
182
+ references: ['OpenSSF-Scorecard:Dangerous-Workflow', 'CWE-94']
183
+
184
+ - id: SUP-009
185
+ title: Workflows declare least-privilege token permissions
186
+ section: S3
187
+ section_title: Supply Chain & Build Provenance
188
+ severity: MEDIUM
189
+ class: supply-chain
190
+ applies_when: { fact: 'ci:github-actions' }
191
+ check:
192
+ kind: grep_present
193
+ # NOTE: a bare `permissions:` line proves nothing — the grants live on
194
+ # the following lines, which a per-line check cannot see. Only an
195
+ # explicit same-line `read-all`, or a scoped `contents:`/`id-token:` /
196
+ # `pull-requests:` grant, counts as evidence. `write-all` and bare
197
+ # `permissions:` yield MISSING (unverifiable), never PASS.
198
+ pattern: '^\s*permissions\s*:\s*read-all\s*$|^\s{2,}(contents|id-token|pull-requests)\s*:\s*(read|write)\s*$'
199
+ include: ['.github/workflows/*.yml', '.github/workflows/*.yaml']
200
+ why: 'A default GITHUB_TOKEN with write-all turns any compromised action into a supply-chain incident.'
201
+ remediation: 'Set `permissions: contents: read` at the top of each workflow and grant write only where needed.'
202
+ references: ['OpenSSF-Scorecard:Token-Permissions', 'SLSA-Build-L2']
203
+ tags: [github-actions]
204
+
205
+ - id: SUP-010
206
+ title: Third-party actions are pinned to a version or SHA
207
+ section: S3
208
+ section_title: Supply Chain & Build Provenance
209
+ severity: MEDIUM
210
+ class: supply-chain
211
+ applies_when: { fact: 'ci:github-actions' }
212
+ check:
213
+ kind: grep_absent
214
+ pattern: 'uses:\s*[^@\s]+@(main|master|latest)\s*$'
215
+ include: ['.github/workflows/*.yml', '.github/workflows/*.yaml']
216
+ flags: i
217
+ why: '`@main` on a third-party action means their next commit runs with your secrets.'
218
+ remediation: 'Pin to a full commit SHA; enable Dependabot for github-actions to keep them current.'
219
+ references: ['OpenSSF-Scorecard:Pinned-Dependencies']
220
+
221
+ - id: SUP-011
222
+ title: No secrets in CI configuration
223
+ section: S3
224
+ section_title: Supply Chain & Build Provenance
225
+ severity: CRITICAL
226
+ class: supply-chain
227
+ applies_when: { fact: 'has:ci' }
228
+ check:
229
+ kind: grep_absent
230
+ pattern: '(password|passwd|token|secret|api[_-]?key|access[_-]?key)\s*[:=]\s*[''"]?[A-Za-z0-9/+_-]{16,}'
231
+ include:
232
+ [
233
+ '.github/workflows/*.yml',
234
+ '.github/workflows/*.yaml',
235
+ '.gitlab-ci.yml',
236
+ 'Jenkinsfile',
237
+ '.circleci/config.yml',
238
+ 'azure-pipelines.yml',
239
+ '.travis.yml',
240
+ ]
241
+ flags: i
242
+ why: 'Values in workflow files are visible to every contributor and preserved in every fork.'
243
+ remediation: 'Move to repository/environment secrets and reference them as ${{ secrets.NAME }}.'
244
+ references: ['CWE-798', 'OpenSSF-Scorecard:Dangerous-Workflow']
245
+
246
+ - id: SUP-012
247
+ title: Default branch is protected
248
+ section: S3
249
+ section_title: Supply Chain & Build Provenance
250
+ severity: HIGH
251
+ class: supply-chain
252
+ applies_when:
253
+ not: { fact: 'maturity:prototype' }
254
+ check: { kind: manual }
255
+ why: >-
256
+ Without protection, anyone with push access can rewrite history, skip review, and ship untested code straight to main.
257
+ evidence: 'Branch protection settings: required review, required status checks, no force-push, no bypass for admins.'
258
+ remediation: 'Require ≥1 review, dismiss stale approvals, require CI to pass, and block force-push on the default branch.'
259
+ references: ['OpenSSF-Scorecard:Branch-Protection', 'SLSA-Source-L2', 'NIST-SSDF-PO.2']
260
+
261
+ - id: SUP-013
262
+ title: Commits are signed or attested
263
+ section: S3
264
+ section_title: Supply Chain & Build Provenance
265
+ severity: LOW
266
+ class: supply-chain
267
+ applies_when:
268
+ any:
269
+ - { fact: 'maturity:production' }
270
+ - { fact: 'maturity:beta' }
271
+ check:
272
+ kind: grep_present
273
+ pattern: '(actions/attest|sigstore|slsa-framework|gpg-sign|commit\.gpgsign|ssh-sign|gh attestation)'
274
+ include: ['.github/workflows/*.yml', '.github/workflows/*.yaml', '.git/config', '.gitconfig']
275
+ flags: i
276
+ why: 'Unsigned history means anyone with push access can forge a commit attributed to someone else.'
277
+ remediation: 'Enable commit signing, then add build provenance attestation to your release workflow.'
278
+ references: ['SLSA-Build-L2', 'OpenSSF-Scorecard:Signed-Releases']
279
+
280
+ - id: SUP-014
281
+ title: An SBOM is generated for releases
282
+ section: S3
283
+ section_title: Supply Chain & Build Provenance
284
+ severity: LOW
285
+ class: supply-chain
286
+ applies_when:
287
+ any:
288
+ - { fact: 'maturity:production' }
289
+ - { fact: 'maturity:beta' }
290
+ check:
291
+ kind: grep_present
292
+ pattern: '(cyclonedx|spdx|sbom|anchore/sbom-action|syft)'
293
+ include:
294
+ [
295
+ '.github/workflows/*.yml',
296
+ '.github/workflows/*.yaml',
297
+ 'Makefile',
298
+ 'justfile',
299
+ 'Taskfile.yml',
300
+ ]
301
+ exclude: ['**/node_modules/**']
302
+ flags: i
303
+ why: 'When the next Log4Shell drops, the first question is "are we affected?" An SBOM is the answer in seconds.'
304
+ remediation: 'Generate a CycloneDX or SPDX SBOM in CI and publish it with the release.'
305
+ references: ['SLSA', 'NIST-SSDF-PS.3.2', 'EU-CRA-Annex-I']
306
+
307
+ - id: SUP-015
308
+ title: Release artifacts carry provenance attestation
309
+ section: S3
310
+ section_title: Supply Chain & Build Provenance
311
+ severity: FUTURE
312
+ class: supply-chain
313
+ applies_when: { fact: 'maturity:production' }
314
+ check: { kind: manual }
315
+ why: >-
316
+ When an artifact is compromised, provenance is the only thing that answers "was this built by us, from this source?"
317
+ evidence: 'Release workflow producing a SLSA/in-toto attestation, verified at deploy time by consumers.'
318
+ remediation: 'Enable GitHub Artifact Attestations (SLSA Build L2 by default) or npm trusted publishing; verify with slsa-verifier.'
319
+ references: ['SLSA-Build-L2', 'SLSA-v1.2']
320
+
321
+ - id: SUP-016
322
+ title: Container images are scanned before publish
323
+ section: S3
324
+ section_title: Supply Chain & Build Provenance
325
+ severity: MEDIUM
326
+ class: supply-chain
327
+ applies_when: { fact: 'has:containers' }
328
+ check:
329
+ kind: grep_present
330
+ pattern: '(trivy|grype|snyk container|docker scan|anchore|cosign)'
331
+ include:
332
+ [
333
+ '.github/workflows/*.yml',
334
+ '.github/workflows/*.yaml',
335
+ '.gitlab-ci.yml',
336
+ 'Dockerfile*',
337
+ 'Makefile',
338
+ 'justfile',
339
+ ]
340
+ flags: i
341
+ why: 'Base images ship CVEs. Scanning at build time is the last cheap moment to catch them.'
342
+ remediation: 'Add trivy/grype to the image pipeline; fail on HIGH/CRITICAL; sign images with cosign.'
343
+ references: ['SLSA-Build-L2', 'NIST-SSDF-RV.1.1']
344
+
345
+ - id: SUP-017
346
+ title: Build pipeline is reproducible from source
347
+ section: S3
348
+ section_title: Supply Chain & Build Provenance
349
+ severity: FUTURE
350
+ class: supply-chain
351
+ depths: [deep]
352
+ check: { kind: manual }
353
+ why: >-
354
+ A build that cannot be reproduced cannot be verified, and an unverifiable build is an unverifiable supply chain.
355
+ evidence: 'A clean-machine build from a fresh clone produces a byte-identical (or digest-stable) artifact.'
356
+ remediation: 'Pin toolchains, vendor dependencies, remove timestamps, and document the build environment.'
357
+ references: ['SLSA-Build-L3', 'Reproducible-Builds']
@@ -0,0 +1,266 @@
1
+ id: core/testing
2
+ title: Testing & Quality Assurance
3
+ section: S7
4
+ section_title: Testing & Quality Assurance
5
+ description: >
6
+ Coverage is a weak proxy for confidence; USA separates "tests exist",
7
+ "tests run in CI", and "tests actually cover the paths that matter".
8
+ version: '1.0'
9
+
10
+ rules:
11
+ - id: TEST-001
12
+ title: A test suite exists
13
+ section: S7
14
+ section_title: Testing & Quality Assurance
15
+ severity: HIGH
16
+ class: correctness
17
+ check:
18
+ kind: any_file
19
+ patterns:
20
+ - '**/*.test.{ts,tsx,js,jsx,mjs,cjs}'
21
+ - '**/*.spec.{ts,tsx,js,jsx,mjs,cjs}'
22
+ - '**/test_*.py'
23
+ - '**/*_test.py'
24
+ - '**/*_test.go'
25
+ - '**/*_spec.rb'
26
+ - '**/*Test.java'
27
+ - '**/*Test.kt'
28
+ - '**/*Test.php'
29
+ - '**/tests/**/*.rs'
30
+ - '**/__tests__/**'
31
+ - '**/Tests/**/*.swift'
32
+ - '**/*Tests.swift'
33
+ why: 'A project with zero tests has no definition of "working" that a machine can check.'
34
+ remediation: 'Start with the happy path of the main flow and every bug you have already fixed once.'
35
+ references: ['OpenSSF-Scorecard:CI-Tests', 'NIST-SSDF-RV.1.1']
36
+
37
+ - id: TEST-002
38
+ title: Tests run in CI on every pull request
39
+ section: S7
40
+ section_title: Testing & Quality Assurance
41
+ severity: HIGH
42
+ class: operations
43
+ applies_when: { fact: 'has:ci' }
44
+ check:
45
+ kind: grep_present
46
+ pattern: '(npm (run )?test|npm (run )?test:ci|vitest run|jest --ci|pytest|go test|cargo test|swift test|mvn test|gradle test|rspec|phpunit|dotnet test|make test)'
47
+ include:
48
+ [
49
+ '.github/workflows/*.yml',
50
+ '.github/workflows/*.yaml',
51
+ '.gitlab-ci.yml',
52
+ 'Jenkinsfile',
53
+ '.circleci/config.yml',
54
+ 'azure-pipelines.yml',
55
+ '.buildkite/**',
56
+ ]
57
+ flags: i
58
+ why: 'Tests that only run on a laptop are a memoir, not a control.'
59
+ remediation: 'Run the full suite on pull_request and on push to the default branch; block merge on failure.'
60
+ references: ['OpenSSF-Scorecard:CI-Tests', 'NIST-SSDF-PW.7']
61
+
62
+ - id: TEST-003
63
+ title: There is a meaningful number of tests
64
+ section: S7
65
+ section_title: Testing & Quality Assurance
66
+ severity: MEDIUM
67
+ class: correctness
68
+ applies_when: { fact: 'has:tests' }
69
+ check:
70
+ kind: count_min
71
+ patterns:
72
+ - '**/*.test.{ts,tsx,js,jsx,mjs,cjs}'
73
+ - '**/*.spec.{ts,tsx,js,jsx,mjs,cjs}'
74
+ - '**/test_*.py'
75
+ - '**/*_test.py'
76
+ - '**/*_test.go'
77
+ - '**/*_spec.rb'
78
+ - '**/*Test.java'
79
+ min: 5
80
+ why: 'One test file is a gesture. Five is a habit.'
81
+ remediation: 'Target the paths that carry money or data first: auth, payments, persistence, permissions.'
82
+ references: ['OpenSSF-Scorecard:CI-Tests']
83
+
84
+ - id: TEST-004
85
+ title: Coverage is measured
86
+ section: S7
87
+ section_title: Testing & Quality Assurance
88
+ severity: MEDIUM
89
+ class: correctness
90
+ applies_when: { fact: 'has:tests' }
91
+ check:
92
+ kind: grep_present
93
+ pattern: '(--coverage|--cov\b|coverage[_-]?threshold|coverageThreshold|--fail-under|codecov|coveralls|lcov|c8|nyc|go test -cover|tarpaulin|llvm-cov)'
94
+ include:
95
+ [
96
+ 'package.json',
97
+ 'pyproject.toml',
98
+ 'setup.cfg',
99
+ '.coveragerc',
100
+ 'Makefile',
101
+ 'justfile',
102
+ 'Taskfile.yml',
103
+ '.github/workflows/*.yml',
104
+ '.github/workflows/*.yaml',
105
+ 'vitest.config.*',
106
+ 'jest.config.*',
107
+ ]
108
+ flags: i
109
+ why: 'Unmeasured coverage drifts down silently, one "I''ll add tests later" at a time.'
110
+ remediation: 'Turn on coverage reporting; publish the number on every PR so it is visible when it moves.'
111
+ references: ['NIST-SSDF-RV.1.1']
112
+
113
+ - id: TEST-005
114
+ title: Coverage thresholds are enforced
115
+ section: S7
116
+ section_title: Testing & Quality Assurance
117
+ severity: LOW
118
+ class: correctness
119
+ applies_when:
120
+ any:
121
+ - { fact: 'maturity:production' }
122
+ - { fact: 'maturity:beta' }
123
+ check:
124
+ kind: grep_present
125
+ # NOTE: `coverage\s*:\s*\{` covers Vitest-style `coverage: { thresholds:
126
+ # … }` blocks — the earlier `coverage\s*{` (no colon) missed exactly
127
+ # the config form this repo itself uses, so the rule failed USA's own
128
+ # self-audit the week thresholds were added. Keep both alternatives.
129
+ pattern: '(coverageThreshold|failUnder|--fail-under|min-coverage|coverage\s*\{|coverage\s*:\s*\{|\[tool\.coverage\.report\]\s*\n[^\n]*fail_under)'
130
+ include:
131
+ [
132
+ 'package.json',
133
+ 'vitest.config.*',
134
+ 'jest.config.*',
135
+ 'pyproject.toml',
136
+ 'setup.cfg',
137
+ '.coveragerc',
138
+ 'codecov.yml',
139
+ '.codecov.yml',
140
+ 'Cargo.toml',
141
+ ]
142
+ flags: i
143
+ why: "A gate stops the slide. Set it at today's number and ratchet upward."
144
+ remediation: 'Set a floor slightly below current coverage and raise it whenever it is comfortably met.'
145
+ references: ['NIST-SSDF-RV.1.1']
146
+
147
+ - id: TEST-006
148
+ title: Integration tests cover the seams
149
+ section: S7
150
+ section_title: Testing & Quality Assurance
151
+ severity: MEDIUM
152
+ class: correctness
153
+ applies_when:
154
+ any:
155
+ - { fact: 'has:database' }
156
+ - { fact: 'platform:server' }
157
+ - { fact: 'project:api' }
158
+ check: { kind: manual }
159
+ evidence: 'Tests that exercise a real database/queue/HTTP boundary (or a containerised test double) rather than mocking every collaborator.'
160
+ why: 'Unit tests with everything mocked verify your mock, not your integration.'
161
+ remediation: 'Add tests that run against a real Postgres/Redis via testcontainers or a docker-compose test profile.'
162
+ references: ['Testing-Trophy']
163
+
164
+ - id: TEST-007
165
+ title: End-to-end tests cover critical user journeys
166
+ section: S7
167
+ section_title: Testing & Quality Assurance
168
+ severity: MEDIUM
169
+ class: correctness
170
+ applies_when:
171
+ any:
172
+ - { fact: 'platform:web' }
173
+ - { fact: 'platform:mobile' }
174
+ - { fact: 'maturity:production' }
175
+ check:
176
+ kind: any_file
177
+ patterns:
178
+ [
179
+ 'e2e/**',
180
+ 'cypress/**',
181
+ 'playwright.config.*',
182
+ 'tests/e2e/**',
183
+ '**/*.e2e.{ts,js,py}',
184
+ '**/*.cy.{ts,js}',
185
+ '**/spec/features/**',
186
+ ]
187
+ why: 'Unit tests cannot tell you that checkout is broken because a button moved.'
188
+ remediation: 'Three journeys: sign up/log in, the core money path, and the path that would lose data if it failed.'
189
+ references: ['Testing-Trophy']
190
+
191
+ - id: TEST-008
192
+ title: Security-relevant behaviour is tested
193
+ section: S7
194
+ section_title: Testing & Quality Assurance
195
+ severity: MEDIUM
196
+ class: security
197
+ applies_when:
198
+ any:
199
+ - { fact: 'auth:jwt' }
200
+ - { fact: 'auth:session' }
201
+ - { fact: 'auth:oauth' }
202
+ - { fact: 'has:database' }
203
+ check: { kind: manual }
204
+ evidence: "Tests asserting that user A cannot read or modify user B's resources, and that unauthenticated calls are rejected."
205
+ why: 'Authorization regressions are silent: nothing crashes, someone just sees data they should not.'
206
+ remediation: 'Add negative tests for every permission boundary — 401/403 paths and cross-tenant access attempts.'
207
+ references: ['ASVS-4.2.1', 'OWASP-A01:2021']
208
+
209
+ - id: TEST-009
210
+ title: Tests are independent and deterministic
211
+ section: S7
212
+ section_title: Testing & Quality Assurance
213
+ severity: MEDIUM
214
+ class: correctness
215
+ applies_when: { fact: 'has:tests' }
216
+ check: { kind: manual }
217
+ evidence: 'Run the suite in random order and twice in a row. Report failures and any test that depends on wall-clock time or network.'
218
+ why: 'Order-dependent tests are a distributed system with extra steps, and flaky tests train people to ignore red builds.'
219
+ remediation: 'Reset state per test; freeze the clock; seed randomness. Quarantine flaky tests and fix them within a sprint.'
220
+ references: ['Google-Testing-Blog:Flaky']
221
+
222
+ - id: TEST-010
223
+ title: Performance/load tests exist for critical paths
224
+ section: S7
225
+ section_title: Testing & Quality Assurance
226
+ severity: FUTURE
227
+ class: performance
228
+ applies_when:
229
+ any:
230
+ - { fact: 'maturity:production' }
231
+ - { fact: 'maturity:beta' }
232
+ check: { kind: manual }
233
+ evidence: 'A load-test script (k6, Locust, wrk, artillery) and the last recorded p95/p99 for the main endpoint.'
234
+ why: 'You do not know your ceiling until you have hit it.'
235
+ remediation: 'Script the top three endpoints; run them before each release; record the numbers.'
236
+ references: ['ISO-25010']
237
+
238
+ - id: TEST-011
239
+ title: Mutation testing or equivalent
240
+ section: S7
241
+ section_title: Testing & Quality Assurance
242
+ severity: FUTURE
243
+ class: correctness
244
+ depths: [deep]
245
+ check: { kind: manual }
246
+ evidence: 'Astryx/Stryker/mutmut/cargo-mutants score, or a documented decision not to use it.'
247
+ why: 'Coverage tells you which lines ran, not whether the test would have failed if the line were wrong.'
248
+ remediation: 'Run mutation testing on the highest-risk module first.'
249
+ references: ['Mutation-Testing']
250
+
251
+ - id: TEST-012
252
+ title: Test data comes from fixtures or factories
253
+ section: S7
254
+ section_title: Testing & Quality Assurance
255
+ severity: LOW
256
+ class: maintainability
257
+ applies_when: { fact: 'has:tests' }
258
+ check:
259
+ kind: grep_present
260
+ pattern: '(factory|fixture|faker|builder|testcontainers|factories)'
261
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb}']
262
+ exclude: ['**/node_modules/**']
263
+ flags: i
264
+ why: 'Hand-built object literals in 200 tests make every schema change a 200-file migration.'
265
+ remediation: 'Add a factory (fishery, factory_boy, faker) and generate data at the edges of tests.'
266
+ references: ['Testing-Patterns']