@xenos1996/usat 1.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 (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +335 -0
  3. package/USAT.md +596 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +438 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config.d.ts +7 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +72 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/detect/index.d.ts +58 -0
  13. package/dist/detect/index.d.ts.map +1 -0
  14. package/dist/detect/index.js +329 -0
  15. package/dist/detect/index.js.map +1 -0
  16. package/dist/engine/audit.d.ts +21 -0
  17. package/dist/engine/audit.d.ts.map +1 -0
  18. package/dist/engine/audit.js +295 -0
  19. package/dist/engine/audit.js.map +1 -0
  20. package/dist/engine/diff.d.ts +24 -0
  21. package/dist/engine/diff.d.ts.map +1 -0
  22. package/dist/engine/diff.js +136 -0
  23. package/dist/engine/diff.js.map +1 -0
  24. package/dist/engine/evaluate.d.ts +19 -0
  25. package/dist/engine/evaluate.d.ts.map +1 -0
  26. package/dist/engine/evaluate.js +377 -0
  27. package/dist/engine/evaluate.js.map +1 -0
  28. package/dist/engine/gate.d.ts +19 -0
  29. package/dist/engine/gate.d.ts.map +1 -0
  30. package/dist/engine/gate.js +47 -0
  31. package/dist/engine/gate.js.map +1 -0
  32. package/dist/engine/loader.d.ts +22 -0
  33. package/dist/engine/loader.d.ts.map +1 -0
  34. package/dist/engine/loader.js +360 -0
  35. package/dist/engine/loader.js.map +1 -0
  36. package/dist/engine/maturity.d.ts +20 -0
  37. package/dist/engine/maturity.d.ts.map +1 -0
  38. package/dist/engine/maturity.js +157 -0
  39. package/dist/engine/maturity.js.map +1 -0
  40. package/dist/engine/score.d.ts +19 -0
  41. package/dist/engine/score.d.ts.map +1 -0
  42. package/dist/engine/score.js +141 -0
  43. package/dist/engine/score.js.map +1 -0
  44. package/dist/engine/sections.d.ts +14 -0
  45. package/dist/engine/sections.d.ts.map +1 -0
  46. package/dist/engine/sections.js +50 -0
  47. package/dist/engine/sections.js.map +1 -0
  48. package/dist/index.d.ts +23 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +17 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/report/markdown.d.ts +16 -0
  53. package/dist/report/markdown.d.ts.map +1 -0
  54. package/dist/report/markdown.js +488 -0
  55. package/dist/report/markdown.js.map +1 -0
  56. package/dist/types.d.ts +282 -0
  57. package/dist/types.d.ts.map +1 -0
  58. package/dist/types.js +16 -0
  59. package/dist/types.js.map +1 -0
  60. package/dist/util/glob.d.ts +11 -0
  61. package/dist/util/glob.d.ts.map +1 -0
  62. package/dist/util/glob.js +86 -0
  63. package/dist/util/glob.js.map +1 -0
  64. package/dist/util/project.d.ts +72 -0
  65. package/dist/util/project.d.ts.map +1 -0
  66. package/dist/util/project.js +586 -0
  67. package/dist/util/project.js.map +1 -0
  68. package/dist/util/yaml.d.ts +28 -0
  69. package/dist/util/yaml.d.ts.map +1 -0
  70. package/dist/util/yaml.js +48 -0
  71. package/dist/util/yaml.js.map +1 -0
  72. package/docs/ARCHITECTURE.md +119 -0
  73. package/docs/README.md +27 -0
  74. package/docs/adr/0001-record-architecture-decisions.md +35 -0
  75. package/docs/adr/0002-typescript-engine-over-python.md +49 -0
  76. package/docs/adr/0003-rules-are-data-not-code.md +50 -0
  77. package/docs/adr/0004-markdown-only-output.md +41 -0
  78. package/docs/adr/0005-maturity-dampens-severity.md +56 -0
  79. package/docs/adr/0006-severity-status-two-axes.md +48 -0
  80. package/docs/adr/0007-suppressions-are-visible-and-expiring.md +46 -0
  81. package/docs/adr/0008-report-trailer-and-diff.md +48 -0
  82. package/docs/adr/0009-fail-closed-on-malformed-input.md +56 -0
  83. package/docs/adr/0010-detector-design.md +54 -0
  84. package/docs/adr/0011-coexist-with-deep-scanners.md +52 -0
  85. package/docs/adr/README.md +32 -0
  86. package/docs/agent-integration.md +129 -0
  87. package/docs/ci-integration.md +163 -0
  88. package/docs/concepts.md +196 -0
  89. package/docs/configuration.md +105 -0
  90. package/docs/detectors.md +186 -0
  91. package/docs/getting-started.md +99 -0
  92. package/docs/maturity-profiles.md +156 -0
  93. package/docs/reference/api.md +193 -0
  94. package/docs/reference/cli.md +412 -0
  95. package/docs/rule-packs.md +278 -0
  96. package/docs/standards-mapping.md +171 -0
  97. package/package.json +96 -0
  98. package/rules/core/architecture.yaml +190 -0
  99. package/rules/core/cicd.yaml +212 -0
  100. package/rules/core/code-quality.yaml +261 -0
  101. package/rules/core/dependencies.yaml +132 -0
  102. package/rules/core/documentation.yaml +119 -0
  103. package/rules/core/future-readiness.yaml +91 -0
  104. package/rules/core/release.yaml +131 -0
  105. package/rules/core/repo.yaml +303 -0
  106. package/rules/core/security.yaml +494 -0
  107. package/rules/core/supply-chain.yaml +357 -0
  108. package/rules/core/testing.yaml +260 -0
  109. package/rules/detectors.yaml +2255 -0
  110. package/rules/index.yaml +41 -0
  111. package/rules/profiles/maturity.yaml +135 -0
  112. package/rules/stacks/ai-era.yaml +193 -0
  113. package/rules/stacks/api-backend.yaml +121 -0
  114. package/rules/stacks/cli.yaml +105 -0
  115. package/rules/stacks/compliance.yaml +157 -0
  116. package/rules/stacks/containers.yaml +124 -0
  117. package/rules/stacks/data.yaml +165 -0
  118. package/rules/stacks/go.yaml +134 -0
  119. package/rules/stacks/iac.yaml +128 -0
  120. package/rules/stacks/jvm.yaml +150 -0
  121. package/rules/stacks/ml-ai.yaml +140 -0
  122. package/rules/stacks/mobile.yaml +121 -0
  123. package/rules/stacks/node-typescript.yaml +166 -0
  124. package/rules/stacks/python.yaml +175 -0
  125. package/rules/stacks/rust.yaml +129 -0
  126. package/rules/stacks/solidity.yaml +139 -0
  127. package/rules/stacks/web-frontend.yaml +159 -0
  128. package/templates/AGENTS.audit.md +135 -0
  129. package/templates/AUDIT_REPORT.md +155 -0
@@ -0,0 +1,190 @@
1
+ id: core/architecture
2
+ title: Architecture & Design
3
+ section: S4
4
+ section_title: Architecture & Design
5
+ description: >
6
+ Structure, boundaries, and the decisions behind them. Mostly judgement —
7
+ USAT automates the parts that show up as files and flags the rest for
8
+ review rather than pretending a regex can measure coupling.
9
+ version: '1.0'
10
+
11
+ rules:
12
+ - id: ARCH-001
13
+ title: Architecture is documented
14
+ section: S4
15
+ section_title: Architecture & Design
16
+ severity: MEDIUM
17
+ class: documentation
18
+ applies_when:
19
+ not: { fact: 'maturity:prototype' }
20
+ check:
21
+ kind: any_file
22
+ patterns:
23
+ [
24
+ 'ARCHITECTURE.md',
25
+ 'docs/ARCHITECTURE.md',
26
+ 'docs/architecture/**',
27
+ 'docs/design/**',
28
+ 'docs/overview.md',
29
+ ]
30
+ why: 'Undocumented architecture is whatever the last person to touch it believed.'
31
+ remediation: 'One page: components, data flow, external dependencies, and the three decisions a newcomer would question.'
32
+ references: ['arc42', 'C4-Model']
33
+
34
+ - id: ARCH-002
35
+ title: Architecture decisions are recorded (ADRs)
36
+ section: S4
37
+ section_title: Architecture & Design
38
+ severity: LOW
39
+ class: documentation
40
+ applies_when:
41
+ not: { fact: 'maturity:prototype' }
42
+ check:
43
+ kind: any_file
44
+ patterns:
45
+ ['**/adr-*.md', '**/ADR-*.md', 'docs/adrs/**', 'docs/adr/**', 'docs/decisions/**', 'adr/**']
46
+ why: 'Six months from now nobody will remember why Postgres won over Mongo, and someone will relitigate it.'
47
+ remediation: 'Keep short ADRs in docs/adrs: context, decision, consequences. One markdown file per decision.'
48
+ references: ['ADR-Nygard']
49
+
50
+ - id: ARCH-003
51
+ title: No god files
52
+ section: S4
53
+ section_title: Architecture & Design
54
+ severity: MEDIUM
55
+ class: maintainability
56
+ check:
57
+ kind: file_lines_max
58
+ patterns:
59
+ [
60
+ 'src/**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb,php,cs}',
61
+ 'app/**/*.{ts,tsx,js,jsx,py,go,rs,java,kt}',
62
+ 'lib/**/*.{ts,tsx,js,jsx,py,go,rs}',
63
+ 'pkg/**/*.go',
64
+ 'internal/**/*.go',
65
+ ]
66
+ max_lines: 800
67
+ why: 'A file nobody can hold in their head is a file nobody changes safely.'
68
+ remediation: 'Split by responsibility: extract the data access, the policy, or the formatting into its own module.'
69
+ references: ['Anti-pattern:God-Object', 'ISO-5055']
70
+
71
+ - id: ARCH-004
72
+ title: Layers are separated (transport / domain / data)
73
+ section: S4
74
+ section_title: Architecture & Design
75
+ severity: MEDIUM
76
+ class: maintainability
77
+ applies_when:
78
+ any:
79
+ - { fact: 'platform:server' }
80
+ - { fact: 'project:api' }
81
+ - { fact: 'has:database' }
82
+ check: { kind: manual }
83
+ why: >-
84
+ Business logic mixed into HTTP handlers cannot be tested, reused, or moved — and every new transport duplicates it.
85
+ evidence: 'Directory layout or file:line showing HTTP handlers delegating to a domain/service layer rather than querying the DB inline.'
86
+ remediation: 'Handlers parse and authorise; services hold business rules; repositories own persistence. No SQL in a controller.'
87
+ references: ['Clean-Architecture', 'Hexagonal-Architecture']
88
+
89
+ - id: ARCH-005
90
+ title: No circular dependencies between modules
91
+ section: S4
92
+ section_title: Architecture & Design
93
+ severity: HIGH
94
+ class: maintainability
95
+ depths: [deep]
96
+ check:
97
+ kind: command
98
+ run: '! (command -v npx >/dev/null && npx --yes dpdm@latest --exit-code circular:1 "src/**/*.ts" 2>/dev/null | grep -qi circular)'
99
+ expect_exit: 0
100
+ why: 'Cycles make modules untestable in isolation and turn every build order into a guess.'
101
+ evidence: 'Output of dpdm / madge --circular / dependency-cruiser, or a manual import-graph review.'
102
+ remediation: 'Break the cycle with an interface, an event, or by extracting the shared type into a leaf module.'
103
+ references: ['Anti-pattern:Circular-Dependency']
104
+
105
+ - id: ARCH-006
106
+ title: Module boundaries are enforced by tooling
107
+ section: S4
108
+ section_title: Architecture & Design
109
+ severity: LOW
110
+ class: maintainability
111
+ applies_when: { fact: 'project:monorepo' }
112
+ check:
113
+ kind: grep_present
114
+ pattern: '(enforce-module-boundaries|no-restricted-imports|dependency-cruiser|import/no-cycle|@nx/enforce-module-boundaries|boundaries/)'
115
+ include:
116
+ [
117
+ '**/.eslintrc*',
118
+ 'eslint.config.*',
119
+ '.dependency-cruiser.*',
120
+ 'nx.json',
121
+ 'project.json',
122
+ '**/tsconfig*.json',
123
+ ]
124
+ flags: i
125
+ why: 'Boundaries that are not enforced decay within one sprint of the first deadline.'
126
+ remediation: 'Add nx enforce-module-boundaries or eslint no-restricted-imports between packages/layers.'
127
+ references: ['Nx', 'dependency-cruiser']
128
+
129
+ - id: ARCH-007
130
+ title: Configuration is externalised
131
+ section: S4
132
+ section_title: Architecture & Design
133
+ severity: MEDIUM
134
+ class: operations
135
+ check:
136
+ kind: grep_absent
137
+ pattern: '(process\.env\.[A-Z_]+\s*\|\|\s*[''"](?:prod|production|https?://)|\b(?:DATABASE_URL|API_URL|REDIS_URL)\s*[:=]\s*[''"](?:postgres|mysql|mongodb|redis|https?)://(?!localhost|127\.0\.0\.1))'
138
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb,php}']
139
+ exclude: ['**/*.test.*', '**/*.spec.*']
140
+ flags: i
141
+ why: 'A hardcoded production URL means the only way to run staging is to edit source.'
142
+ remediation: 'Read every environment-specific value from configuration; keep defaults that are safe for local dev.'
143
+ references: ['12-Factor:Config', 'ASVS-14.1.3']
144
+
145
+ - id: ARCH-008
146
+ title: Side effects are isolated and testable
147
+ section: S4
148
+ section_title: Architecture & Design
149
+ severity: LOW
150
+ class: maintainability
151
+ check: { kind: manual }
152
+ why: >-
153
+ Side effects called inline cannot be tested without the network, the clock, or the database. That is why tests get slow and flaky.
154
+ evidence: 'Examples of I/O (network, disk, clock, randomness) being injected or wrapped rather than called inline from business logic.'
155
+ remediation: 'Inject the clock, the HTTP client, and the repository; keep pure functions pure.'
156
+ references: ['Functional-Core-Imperative-Shell']
157
+
158
+ - id: ARCH-009
159
+ title: Single points of failure are identified
160
+ section: S4
161
+ section_title: Architecture & Design
162
+ severity: MEDIUM
163
+ class: operations
164
+ applies_when:
165
+ any:
166
+ - { fact: 'maturity:production' }
167
+ - { fact: 'maturity:beta' }
168
+ check: { kind: manual }
169
+ why: >-
170
+ Availability incidents are almost always an SPOF somebody already knew about. Writing it down is what turns it into a project.
171
+ evidence: 'A list of SPOFs (single DB, single region, single queue, single vendor) and the mitigation for each.'
172
+ remediation: 'For each SPOF: replica, failover, or an explicitly accepted risk with a documented recovery time.'
173
+ references: ['AWS-Well-Architected:Reliability']
174
+
175
+ - id: ARCH-010
176
+ title: Async work is offloaded to a queue
177
+ section: S4
178
+ section_title: Architecture & Design
179
+ severity: LOW
180
+ class: performance
181
+ applies_when: { fact: 'platform:server' }
182
+ check:
183
+ kind: grep_present
184
+ pattern: '(bullmq|bull|amqplib|kafkajs|sqs|nats|temporal|celery|rq|sidekiq|taskiq|dramatiq|asynq)'
185
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,rb}']
186
+ exclude: ['**/*.test.*']
187
+ flags: i
188
+ why: 'Anything slow inside a request handler is a timeout waiting for a busy day.'
189
+ remediation: 'Move email, image processing, webhooks, and report generation onto a queue with retries and a DLQ.'
190
+ references: ['12-Factor:Processes']
@@ -0,0 +1,212 @@
1
+ id: core/cicd
2
+ title: CI/CD, Infrastructure & Observability
3
+ section: S8
4
+ section_title: CI/CD, Infrastructure & Observability
5
+ description: >
6
+ How code becomes running software, and how you find out when it breaks.
7
+ Heavily informed by the OpenSSF Scorecard and DORA's delivery metrics.
8
+ version: '1.0'
9
+
10
+ rules:
11
+ - id: CICD-001
12
+ title: A CI pipeline exists
13
+ section: S8
14
+ section_title: CI/CD, Infrastructure & Observability
15
+ severity: HIGH
16
+ class: operations
17
+ check:
18
+ kind: any_file
19
+ patterns:
20
+ - '.github/workflows/*.yml'
21
+ - '.github/workflows/*.yaml'
22
+ - '.gitlab-ci.yml'
23
+ - 'Jenkinsfile'
24
+ - '.circleci/config.yml'
25
+ - '.buildkite/**'
26
+ - 'azure-pipelines.yml'
27
+ - '.drone.yml'
28
+ - 'bitbucket-pipelines.yml'
29
+ why: 'Manual release steps work exactly until the person who knows them is on holiday.'
30
+ remediation: 'Add a minimal pipeline first: install → lint → test → build. Expand from there.'
31
+ references: ['OpenSSF-Scorecard:CI-Tests', 'DORA']
32
+
33
+ - id: CICD-002
34
+ title: CI runs lint, test, and build
35
+ section: S8
36
+ section_title: CI/CD, Infrastructure & Observability
37
+ severity: MEDIUM
38
+ class: operations
39
+ applies_when: { fact: 'has:ci' }
40
+ check: { kind: manual }
41
+ evidence: 'The workflow file: which of lint / typecheck / test / build run on pull_request?'
42
+ why: 'A pipeline that only builds is a compiler with a dashboard.'
43
+ remediation: 'Add steps in fail-fast order: lint (5s) → typecheck → unit → build → integration.'
44
+ references: ['OpenSSF-Scorecard:CI-Tests', 'DORA']
45
+
46
+ - id: CICD-003
47
+ title: Deployment is automated
48
+ section: S8
49
+ section_title: CI/CD, Infrastructure & Observability
50
+ severity: HIGH
51
+ class: operations
52
+ applies_when:
53
+ any:
54
+ - { fact: 'maturity:production' }
55
+ - { fact: 'maturity:beta' }
56
+ check: { kind: manual }
57
+ evidence: 'The path from merged commit to production: is there a human typing commands into a server?'
58
+ why: 'Manual deploys are unrepeatable, unauditable, and always happen at the worst possible time.'
59
+ remediation: 'Automate deploy from a tagged commit or main-branch push with an approval step if governance requires one.'
60
+ references: ['DORA:Deployment-Frequency', 'NIST-SSDF-PO.5']
61
+
62
+ - id: CICD-004
63
+ title: A rollback path exists and has been exercised
64
+ section: S8
65
+ section_title: CI/CD, Infrastructure & Observability
66
+ severity: HIGH
67
+ class: operations
68
+ applies_when:
69
+ any:
70
+ - { fact: 'maturity:production' }
71
+ - { fact: 'maturity:beta' }
72
+ check: { kind: manual }
73
+ evidence: 'Documented rollback command/action, and the date it was last actually used (successfully).'
74
+ why: 'An untested rollback is a second outage with extra panic.'
75
+ remediation: 'Make rollback a one-command operation; rehearse it; record the last successful rollback date.'
76
+ references: ['DORA:Time-to-Restore', 'NIST-SSDF-RV.3']
77
+
78
+ - id: CICD-005
79
+ title: Separate environments exist
80
+ section: S8
81
+ section_title: CI/CD, Infrastructure & Observability
82
+ severity: MEDIUM
83
+ class: operations
84
+ applies_when:
85
+ not: { fact: 'maturity:prototype' }
86
+ check: { kind: manual }
87
+ evidence: 'dev / staging / production configuration, and confirmation that dev cannot reach production data.'
88
+ why: 'Testing in production is a slogan, not a strategy.'
89
+ remediation: 'At minimum: local + staging + production, with separate credentials and datasets per environment.'
90
+ references: ['NIST-SSDF-PO.5', 'ASVS-14.1.3']
91
+
92
+ - id: CICD-006
93
+ title: Infrastructure is defined as code
94
+ section: S8
95
+ section_title: CI/CD, Infrastructure & Observability
96
+ severity: MEDIUM
97
+ class: operations
98
+ applies_when:
99
+ not: { fact: 'maturity:prototype' }
100
+ check:
101
+ kind: any_file
102
+ patterns:
103
+ [
104
+ '**/*.tf',
105
+ '**/*.tfvars',
106
+ 'pulumi/**',
107
+ '**/Pulumi.*.yaml',
108
+ 'cdk.json',
109
+ '**/*.cdk.ts',
110
+ 'ansible/**',
111
+ '**/playbook*.yml',
112
+ 'k8s/**/*.yaml',
113
+ 'manifests/**/*.yaml',
114
+ 'charts/**/Chart.yaml',
115
+ 'docker-compose*.yml',
116
+ 'compose.yaml',
117
+ 'serverless.yml',
118
+ 'Dockerfile*',
119
+ ]
120
+ why: 'Infrastructure that only exists in a console cannot be reviewed, diffed, or rebuilt after an incident.'
121
+ remediation: 'Move environments into Terraform/Pulumi/CDK (or at least declarative compose + helm manifests).'
122
+ references: ['NIST-SSDF-PO.5']
123
+
124
+ - id: CICD-007
125
+ title: Health check endpoints exist
126
+ section: S8
127
+ section_title: CI/CD, Infrastructure & Observability
128
+ severity: MEDIUM
129
+ class: operations
130
+ applies_when: { fact: 'platform:server' }
131
+ check:
132
+ kind: grep_present
133
+ pattern: '(/(health|healthz|readyz|livez|ready|live|status|ping)[''"`\s]|healthCheck|health_check|app\.get\(\s*[''"]/health)'
134
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb,php,yml,yaml}']
135
+ exclude: ['**/*.test.*', '**/*.spec.*', '**/node_modules/**']
136
+ flags: i
137
+ why: 'Without /health and /ready, orchestrators cannot tell a booting service from a dead one.'
138
+ remediation: 'Expose /health (liveness) and /ready (dependencies reachable); wire them into the orchestrator and the LB.'
139
+ references: ['K8s-Probes', 'OpenSSF-Scorecard']
140
+
141
+ - id: CICD-008
142
+ title: Error tracking / APM is configured
143
+ section: S8
144
+ section_title: CI/CD, Infrastructure & Observability
145
+ severity: MEDIUM
146
+ class: operations
147
+ applies_when:
148
+ not: { fact: 'maturity:prototype' }
149
+ check:
150
+ kind: grep_present
151
+ pattern: '(sentry|opentelemetry|datadog|newrelic|new-relic|rollbar|bugsnag|honeycomb|grafana|prometheus|betterstack|axiom)'
152
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb,yml,yaml,json,toml}']
153
+ exclude: ['**/node_modules/**', '**/*.test.*']
154
+ flags: i
155
+ why: 'Your users will find the bugs. The only question is whether they tell you.'
156
+ remediation: 'Add Sentry (or equivalent) with source maps and release tracking; alert on new error types.'
157
+ references: ['DORA:Monitoring', 'OpenTelemetry']
158
+
159
+ - id: CICD-009
160
+ title: Alerting is configured for critical failures
161
+ section: S8
162
+ section_title: CI/CD, Infrastructure & Observability
163
+ severity: MEDIUM
164
+ class: operations
165
+ applies_when: { fact: 'maturity:production' }
166
+ check: { kind: manual }
167
+ evidence: 'Alert rules, their thresholds, and who gets paged. Bonus: the last time one fired and what happened.'
168
+ why: 'Monitoring without alerting is a dashboard nobody opens until after the outage.'
169
+ remediation: 'Alert on symptoms users feel (error rate, latency, saturation), not on every CPU blip.'
170
+ references: ['Google-SRE:Monitoring', 'DORA']
171
+
172
+ - id: CICD-010
173
+ title: Backups exist AND restores have been tested
174
+ section: S8
175
+ section_title: CI/CD, Infrastructure & Observability
176
+ severity: HIGH
177
+ class: operations
178
+ applies_when:
179
+ any:
180
+ - { fact: 'has:database' }
181
+ - { fact: 'maturity:production' }
182
+ check: { kind: manual }
183
+ evidence: 'Backup schedule, retention, encryption at rest, and — critically — the date of the last successful restore drill.'
184
+ why: 'Nobody has ever been fired for having backups. Plenty of teams have died from never testing the restore.'
185
+ remediation: 'Automate backups, encrypt them, store them off-site, and run a restore drill quarterly with a recorded RTO.'
186
+ references: ['NIST-SSDF-RV.3', 'CIS-Control-11']
187
+
188
+ - id: CICD-011
189
+ title: A disaster recovery plan exists
190
+ section: S8
191
+ section_title: CI/CD, Infrastructure & Observability
192
+ severity: MEDIUM
193
+ class: operations
194
+ applies_when: { fact: 'maturity:production' }
195
+ check: { kind: manual }
196
+ evidence: 'Documented RTO/RPO, the failover procedure, and who is authorised to declare a disaster.'
197
+ why: 'At 3am, the plan is the only thing between you and ad-hoc database surgery.'
198
+ remediation: 'Write a one-page DR runbook: trigger, failover steps, rollback, comms template, and owner.'
199
+ references: ['NIST-SSDF-RV.3', 'AWS-Well-Architected:Reliability']
200
+
201
+ - id: CICD-012
202
+ title: Observability covers the golden signals
203
+ section: S8
204
+ section_title: CI/CD, Infrastructure & Observability
205
+ severity: LOW
206
+ class: operations
207
+ applies_when: { fact: 'maturity:production' }
208
+ check: { kind: manual }
209
+ evidence: 'A dashboard or metric set covering latency, traffic, errors, and saturation for the primary service.'
210
+ why: 'Four signals answer "is it broken, how bad, and where" in under five minutes.'
211
+ remediation: 'Instrument RED/USE metrics; put them on one dashboard linked from the runbook.'
212
+ references: ['Google-SRE:Golden-Signals']
@@ -0,0 +1,261 @@
1
+ id: core/code-quality
2
+ title: Code Quality
3
+ section: S5
4
+ section_title: Code Quality
5
+ description: >
6
+ Linting, typing, error handling, and logging hygiene. These are the rules
7
+ an agent should be able to settle without asking a human — most of them are
8
+ answered by looking for a config file.
9
+ version: '1.0'
10
+
11
+ rules:
12
+ - id: CQ-001
13
+ title: A linter is configured
14
+ section: S5
15
+ section_title: Code Quality
16
+ severity: MEDIUM
17
+ class: maintainability
18
+ check:
19
+ kind: any_file
20
+ patterns:
21
+ - '.eslintrc*'
22
+ - 'eslint.config.*'
23
+ - 'biome.json*'
24
+ - '.ruff.toml'
25
+ - 'ruff.toml'
26
+ - '.flake8'
27
+ - 'setup.cfg'
28
+ - '.pylintrc'
29
+ - 'pyproject.toml'
30
+ - '.golangci*'
31
+ - 'clippy.toml'
32
+ - '.rustfmt.toml'
33
+ - 'rustfmt.toml'
34
+ - '.rubocop.yml'
35
+ - 'phpcs.xml*'
36
+ - 'detekt.yml'
37
+ - '.swiftlint.yml'
38
+ why: 'Style arguments in review are a tax on every pull request. Automate them and argue about design instead.'
39
+ remediation: 'Add the standard linter for your stack, start with its recommended config, fix what it finds.'
40
+ references: ['NIST-SSDF-PW.7']
41
+
42
+ - id: CQ-002
43
+ title: A formatter is configured
44
+ section: S5
45
+ section_title: Code Quality
46
+ severity: LOW
47
+ class: style
48
+ check:
49
+ kind: any_file
50
+ patterns:
51
+ [
52
+ '.prettierrc*',
53
+ 'prettier.config.*',
54
+ 'biome.json*',
55
+ '.editorconfig',
56
+ '.rustfmt.toml',
57
+ 'rustfmt.toml',
58
+ '.clang-format',
59
+ 'pyproject.toml',
60
+ '.gofmt*',
61
+ ]
62
+ why: 'Formatting diffs hide real changes. Let a tool own it.'
63
+ remediation: 'Prettier/Black/gofmt/rustfmt — pick the default config and stop discussing it.'
64
+ references: ['NIST-SSDF-PW.7']
65
+
66
+ - id: CQ-003
67
+ title: Type checking is enabled and strict
68
+ section: S5
69
+ section_title: Code Quality
70
+ severity: MEDIUM
71
+ class: correctness
72
+ applies_when:
73
+ any:
74
+ - { fact: 'lang:typescript' }
75
+ - { fact: 'lang:python' }
76
+ check:
77
+ kind: grep_present
78
+ pattern: '("strict"\s*:\s*true|strict\s*=\s*true|\[tool\.mypy\]|\[tool\.pyright\]|noImplicitAny|disallow_untyped_defs)'
79
+ include:
80
+ [
81
+ 'tsconfig.json',
82
+ 'tsconfig.*.json',
83
+ 'pyproject.toml',
84
+ 'setup.cfg',
85
+ 'mypy.ini',
86
+ '.mypy.ini',
87
+ 'pyrightconfig.json',
88
+ ]
89
+ flags: i
90
+ why: 'Types are the cheapest tests you will ever write. Lenient mode is types with the batteries removed.'
91
+ remediation: 'TypeScript: "strict": true. Python: mypy or pyright with strict settings on new modules.'
92
+ references: ['ISO-5055']
93
+
94
+ - id: CQ-004
95
+ title: Type escapes are not used as a default
96
+ section: S5
97
+ section_title: Code Quality
98
+ severity: LOW
99
+ class: maintainability
100
+ applies_when: { fact: 'lang:typescript' }
101
+ check:
102
+ kind: grep_absent
103
+ pattern: '(@ts-ignore|@ts-expect-error|:\s*any\b|\bas any\b|as unknown as)'
104
+ include: ['**/*.{ts,tsx}']
105
+ exclude: ['**/*.test.*', '**/*.spec.*', '**/*.d.ts']
106
+ why: 'Every `any` is a place the type system was told to stop helping. A few are fine; a pattern is a problem.'
107
+ remediation: 'Type the boundary properly, or narrow with a type guard. Delete stale @ts-ignore comments.'
108
+ references: ['ISO-5055']
109
+
110
+ - id: CQ-005
111
+ title: Errors are handled, not swallowed
112
+ section: S5
113
+ section_title: Code Quality
114
+ severity: HIGH
115
+ class: correctness
116
+ check:
117
+ kind: grep_absent
118
+ pattern: '(catch\s*\(\s*\w*\s*\)\s*\{\s*\}|except\s*:\s*(pass|\.\.\.)\s*$|catch\s*\{\s*\}|rescue\s*\n\s*end)'
119
+ include: ['**/*.{ts,tsx,js,jsx,mjs,cjs,py,go,rs,java,kt,rb,php,cs}']
120
+ exclude: ['**/*.test.*', '**/*.spec.*']
121
+ flags: i
122
+ why: 'An empty catch block converts a failure into a mystery. The bug report you get six weeks later will be useless.'
123
+ remediation: 'Log with context and either handle it or re-throw. If it is genuinely ignorable, say why in a comment.'
124
+ references: ['CWE-390', 'ASVS-7.4.1']
125
+
126
+ - id: CQ-006
127
+ title: There is a central error handler
128
+ section: S5
129
+ section_title: Code Quality
130
+ severity: MEDIUM
131
+ class: correctness
132
+ applies_when:
133
+ any:
134
+ - { fact: 'platform:server' }
135
+ - { fact: 'platform:web' }
136
+ check:
137
+ kind: grep_present
138
+ pattern: '(ErrorBoundary|errorHandler|error_handler|@ControllerAdvice|ExceptionHandler|app\.use\(\s*\(\s*err|onerror|useErrorBoundary|Sentry\.(captureException|init))'
139
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb,php}']
140
+ exclude: ['**/*.test.*', '**/*.spec.*']
141
+ why: 'Without a top-level handler, an unhandled rejection is a white screen or a dropped request.'
142
+ remediation: 'Add a framework-level error handler and an ErrorBoundary (React); report to your error tracker.'
143
+ references: ['ASVS-7.4.1']
144
+
145
+ - id: CQ-007
146
+ title: Logging is structured and levelled
147
+ section: S5
148
+ section_title: Code Quality
149
+ severity: LOW
150
+ class: operations
151
+ applies_when:
152
+ any:
153
+ - { fact: 'platform:server' }
154
+ - { fact: 'project:cli' }
155
+ check:
156
+ kind: manual
157
+ why: >-
158
+ Unstructured logs cannot be queried, alerted on, or correlated. At 3am, grep is not a strategy.
159
+ evidence: 'Sample log output: JSON or key=value, with DEBUG/INFO/WARN/ERROR used consistently.'
160
+ remediation: 'Emit JSON logs with a timestamp, level, message, and structured fields. Never log a bare concatenated string.'
161
+ references: ['OpenTelemetry-Logs', 'ASVS-7.1.1']
162
+
163
+ - id: CQ-008
164
+ title: Requests carry a correlation/trace ID
165
+ section: S5
166
+ section_title: Code Quality
167
+ severity: LOW
168
+ class: operations
169
+ applies_when: { fact: 'platform:server' }
170
+ check:
171
+ kind: grep_present
172
+ pattern: '(correlation[_-]?id|request[_-]?id|trace[_-]?id|x-request-id|traceId|requestId|traceContext)'
173
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt}']
174
+ exclude: ['**/*.test.*', '**/*.spec.*']
175
+ flags: i
176
+ why: 'Without a request ID, debugging a production incident means grepping 40 million lines and praying.'
177
+ remediation: 'Generate an ID per request, put it in every log line and in the response header.'
178
+ references: ['OpenTelemetry', 'W3C-Trace-Context']
179
+
180
+ - id: CQ-009
181
+ title: Debug statements are not left in production paths
182
+ section: S5
183
+ section_title: Code Quality
184
+ severity: LOW
185
+ class: style
186
+ applies_when:
187
+ not: { fact: 'project:cli' }
188
+ check:
189
+ kind: grep_absent
190
+ pattern: '(console\.(log|debug|info)\s*\(|print\s*\(\s*[''"]DEBUG|pdb\.set_trace|debugger\s*;|var_dump\s*\()'
191
+ include: ['**/*.{ts,tsx,js,jsx,mjs,cjs,py,php,rb,go,rs,java,kt}']
192
+ exclude: ['**/*.test.*', '**/*.spec.*', '**/scripts/**', '**/tools/**', '**/debug/**']
193
+ why: 'Stray debug output is noise at best and a data leak at worst.'
194
+ remediation: 'Use the project logger, or delete the line. Add a lint rule to keep it out.'
195
+ references: ['CWE-532']
196
+
197
+ - id: CQ-010
198
+ title: TODO/FIXME debt is tracked, not just annotated
199
+ section: S5
200
+ section_title: Code Quality
201
+ severity: LOW
202
+ class: maintainability
203
+ check:
204
+ kind: grep_wrong
205
+ pattern: '(TODO|FIXME|XXX|HACK|WORKAROUND)\b'
206
+ include: ['**/*.{ts,tsx,js,jsx,py,go,rs,java,kt,rb,php,cs,yml,yaml}']
207
+ exclude: ['**/*.md', '**/docs/**', '**/node_modules/**']
208
+ why: 'A TODO with no owner and no ticket is a lie the codebase tells itself.'
209
+ remediation: 'Convert each one to a tracked issue with a link in the comment, or delete it if it no longer applies.'
210
+
211
+ - id: CQ-011
212
+ title: Functions do one thing
213
+ section: S5
214
+ section_title: Code Quality
215
+ severity: LOW
216
+ class: maintainability
217
+ depths: [deep]
218
+ check: { kind: manual }
219
+ why: >-
220
+ A function that needs "and" to describe is two functions. Long functions hide branches nobody tests.
221
+ evidence: 'Three representative functions over ~60 lines: can each be described in one sentence?'
222
+ remediation: 'Extract until each function reads as a single step at the current level of abstraction.'
223
+ references: ['Clean-Code', 'ISO-5055']
224
+
225
+ - id: CQ-012
226
+ title: Duplicated logic has been consolidated
227
+ section: S5
228
+ section_title: Code Quality
229
+ severity: MEDIUM
230
+ class: maintainability
231
+ depths: [deep]
232
+ check: { kind: manual }
233
+ evidence: 'Output of a duplication checker (jscpd, PMD CPD, sonar) — and the top three duplicates by size.'
234
+ why: 'Every copy is a place a bug fix will not reach.'
235
+ remediation: 'Extract the shared logic; accept duplication only when the two copies are expected to diverge.'
236
+ references: ['ISO-5055', 'Anti-pattern:Shotgun-Surgery']
237
+
238
+ - id: CQ-013
239
+ title: Complexity is measured
240
+ section: S5
241
+ section_title: Code Quality
242
+ severity: FUTURE
243
+ class: maintainability
244
+ depths: [deep]
245
+ check:
246
+ kind: grep_present
247
+ pattern: '(complexity|cyclomatic|radon|gocyclo|cognitive)'
248
+ include:
249
+ [
250
+ '**/.eslintrc*',
251
+ 'eslint.config.*',
252
+ 'pyproject.toml',
253
+ '.ruff.toml',
254
+ 'setup.cfg',
255
+ '.golangci*',
256
+ 'sonar-project.properties',
257
+ ]
258
+ flags: i
259
+ why: 'You cannot argue about complexity without a number.'
260
+ remediation: 'Enable an eslint complexity rule (≤10) or radon/gocyclo; report rather than hard-fail at first.'
261
+ references: ['ISO-5055']