clean-slop 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.
- package/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +849 -0
- package/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +3244 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +3239 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +2901 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +225 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.js +2877 -0
- package/dist/index.js.map +1 -0
- package/package.json +105 -0
package/README.md
ADDED
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
# clean-slop
|
|
2
|
+
|
|
3
|
+
**A production readiness engine for modern JavaScript and TypeScript projects.**
|
|
4
|
+
|
|
5
|
+
clean-slop answers one question: **should this code be merged into production?**
|
|
6
|
+
|
|
7
|
+
It combines AI-generated code quality analysis, static security analysis, reliability analysis, maintainability analysis, and production readiness checks into a single professional tool with a clear score and actionable output.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -D clean-slop
|
|
11
|
+
npx clean-slop scan
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why clean-slop
|
|
17
|
+
|
|
18
|
+
AI code generation tools produce code that passes tests and compiles cleanly but contains patterns that silently fail in production: empty catch blocks that hide errors, hardcoded secrets that get committed to version control, SQL queries built with string concatenation, debug flags left active, and validation functions that always return true.
|
|
19
|
+
|
|
20
|
+
Standard linters catch syntax errors and style violations. clean-slop catches the patterns that indicate code that was never properly reviewed, never properly secured, and was never actually intended to run in production.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- **22 built-in rules** across 5 categories
|
|
27
|
+
- **Clear production readiness score** (0–100) with letter grade
|
|
28
|
+
- **Multiple output formats**: terminal, JSON, HTML, Markdown, SARIF 2.1.0
|
|
29
|
+
- **GitHub Code Scanning integration** via SARIF upload
|
|
30
|
+
- **Watch mode** for continuous feedback during development
|
|
31
|
+
- **CI-ready exit codes** with configurable thresholds
|
|
32
|
+
- **Plugin architecture** for custom rules
|
|
33
|
+
- **Public API** for programmatic use in build tools and scripts
|
|
34
|
+
- **TypeScript-first** with full type definitions
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# As a dev dependency (recommended)
|
|
42
|
+
npm install -D clean-slop
|
|
43
|
+
|
|
44
|
+
# Global installation
|
|
45
|
+
npm install -g clean-slop
|
|
46
|
+
|
|
47
|
+
# No installation required
|
|
48
|
+
npx clean-slop scan
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Requirements:** Node.js >= 18.0.0
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
**Scan the current directory:**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx clean-slop scan
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Scan a specific directory:**
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx clean-slop scan ./src
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Generate an HTML report:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx clean-slop report --reporter html --output ./reports/clean-slop.html
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**CI gate (exit 1 if not production ready):**
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx clean-slop check
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Initialize a config file:**
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx clean-slop init
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## CLI Reference
|
|
90
|
+
|
|
91
|
+
### `clean-slop scan [directory]`
|
|
92
|
+
|
|
93
|
+
Scan a directory for issues. This is the default command.
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Options:
|
|
97
|
+
-c, --config <path> Path to configuration file
|
|
98
|
+
--reporter <name> Reporter: text, json, html, markdown, sarif [default: text]
|
|
99
|
+
-o, --output <file> Write report to a file instead of stdout
|
|
100
|
+
--fail-threshold <score> Minimum score before exiting with code 1 [default: 70]
|
|
101
|
+
--max-critical <n> Maximum allowed critical issues [default: 0]
|
|
102
|
+
--max-high <n> Maximum allowed high issues
|
|
103
|
+
--no-ai-slop Disable AI slop rules
|
|
104
|
+
--no-security Disable security rules
|
|
105
|
+
--no-reliability Disable reliability rules
|
|
106
|
+
--no-maintainability Disable maintainability rules
|
|
107
|
+
--no-production-readiness Disable production readiness rules
|
|
108
|
+
--verbose Print full issue details including snippets and fixes
|
|
109
|
+
--quiet Only print the score summary
|
|
110
|
+
--ci CI mode: machine-readable output, no color
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Examples:**
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
# Scan src/ with verbose output
|
|
117
|
+
clean-slop scan src --verbose
|
|
118
|
+
|
|
119
|
+
# Scan and fail if any critical issues found
|
|
120
|
+
clean-slop scan --max-critical 0
|
|
121
|
+
|
|
122
|
+
# Output SARIF for GitHub Code Scanning
|
|
123
|
+
clean-slop scan --reporter sarif --output results.sarif
|
|
124
|
+
|
|
125
|
+
# Disable security rules for a legacy scan
|
|
126
|
+
clean-slop scan --no-security
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### `clean-slop check [directory]`
|
|
132
|
+
|
|
133
|
+
Quick pass/fail check for use in CI pipelines. Prints PASS or FAIL with the score.
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Options:
|
|
137
|
+
-c, --config <path> Path to configuration file
|
|
138
|
+
--fail-threshold <score> Minimum passing score [default: 70]
|
|
139
|
+
--max-critical <n> Maximum critical issues allowed [default: 0]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Exit codes:
|
|
143
|
+
- `0` — production ready (score above threshold, critical issues within limit)
|
|
144
|
+
- `1` — not production ready
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `clean-slop watch [directory]`
|
|
149
|
+
|
|
150
|
+
Watch for file changes and re-scan automatically. Useful during active development.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
clean-slop watch src --verbose
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### `clean-slop report [directory]`
|
|
159
|
+
|
|
160
|
+
Generate a report from a fresh scan and write it to a file.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Generate an HTML report
|
|
164
|
+
clean-slop report --reporter html --output ./reports/clean-slop.html
|
|
165
|
+
|
|
166
|
+
# Generate a Markdown report for GitHub PR comments
|
|
167
|
+
clean-slop report --reporter markdown --output ./clean-slop.md
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### `clean-slop doctor`
|
|
173
|
+
|
|
174
|
+
Diagnose the current environment. Reports Node.js version, configuration status, git repository presence, and loaded rules.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
clean-slop doctor
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### `clean-slop init`
|
|
183
|
+
|
|
184
|
+
Generate a `clean-slop.config.js` in the current directory with all options documented.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
clean-slop init
|
|
188
|
+
clean-slop init --force # Overwrite existing config
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Configuration
|
|
194
|
+
|
|
195
|
+
clean-slop uses [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) for configuration discovery. Configuration is loaded from the first match of:
|
|
196
|
+
|
|
197
|
+
- `clean-slop.config.js`
|
|
198
|
+
- `clean-slop.config.ts`
|
|
199
|
+
- `clean-slop.config.mjs`
|
|
200
|
+
- `clean-slop.config.cjs`
|
|
201
|
+
- `.clean-slop.js`
|
|
202
|
+
- `.clean-slop.json`
|
|
203
|
+
- `.clean-slop.yaml`
|
|
204
|
+
- `package.json` (`"clean-slop"` key)
|
|
205
|
+
|
|
206
|
+
### Full Configuration Reference
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
/** @type {import('clean-slop').UserConfig} */
|
|
210
|
+
export default {
|
|
211
|
+
// Glob patterns of files to scan
|
|
212
|
+
include: [
|
|
213
|
+
'**/*.js',
|
|
214
|
+
'**/*.jsx',
|
|
215
|
+
'**/*.ts',
|
|
216
|
+
'**/*.tsx',
|
|
217
|
+
'**/*.mjs',
|
|
218
|
+
'**/*.cjs',
|
|
219
|
+
],
|
|
220
|
+
|
|
221
|
+
// Glob patterns to exclude
|
|
222
|
+
exclude: [
|
|
223
|
+
'**/node_modules/**',
|
|
224
|
+
'**/dist/**',
|
|
225
|
+
'**/build/**',
|
|
226
|
+
'**/.next/**',
|
|
227
|
+
'**/coverage/**',
|
|
228
|
+
'**/*.min.js',
|
|
229
|
+
'**/*.generated.*',
|
|
230
|
+
'**/__generated__/**',
|
|
231
|
+
],
|
|
232
|
+
|
|
233
|
+
// Enable or disable entire rule categories
|
|
234
|
+
categories: {
|
|
235
|
+
'ai-slop': true,
|
|
236
|
+
'security': true,
|
|
237
|
+
'reliability': true,
|
|
238
|
+
'maintainability': true,
|
|
239
|
+
'production-readiness': true,
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
// Per-rule severity overrides
|
|
243
|
+
// Value: 'critical' | 'high' | 'medium' | 'low' | 'info' | 'off'
|
|
244
|
+
rules: {
|
|
245
|
+
// Disable a rule entirely
|
|
246
|
+
'ai-slop/empty-catch': 'off',
|
|
247
|
+
|
|
248
|
+
// Escalate a rule to critical
|
|
249
|
+
'security/hardcoded-secrets': 'critical',
|
|
250
|
+
|
|
251
|
+
// Downgrade a rule severity
|
|
252
|
+
'production-readiness/no-console-log': 'info',
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
// Minimum overall score before CI exits with code 1
|
|
256
|
+
failThreshold: 70,
|
|
257
|
+
|
|
258
|
+
// Maximum issues per severity (scan fails if exceeded)
|
|
259
|
+
maxIssues: {
|
|
260
|
+
critical: 0, // Zero critical issues allowed
|
|
261
|
+
high: 5,
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
// Reporter: 'text' | 'json' | 'html' | 'markdown' | 'sarif'
|
|
265
|
+
reporter: 'text',
|
|
266
|
+
|
|
267
|
+
// Output file path (null = stdout)
|
|
268
|
+
output: null,
|
|
269
|
+
|
|
270
|
+
// Verbose output (show snippets, fixes, docs links)
|
|
271
|
+
verbose: false,
|
|
272
|
+
|
|
273
|
+
// Additional ignore patterns (on top of .gitignore)
|
|
274
|
+
ignorePatterns: ['src/legacy/**'],
|
|
275
|
+
|
|
276
|
+
// Plugins to load
|
|
277
|
+
plugins: [],
|
|
278
|
+
};
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Rule Reference
|
|
284
|
+
|
|
285
|
+
### AI Slop (`ai-slop`)
|
|
286
|
+
|
|
287
|
+
Rules that detect patterns characteristic of unreviewed AI-generated code.
|
|
288
|
+
|
|
289
|
+
| Rule ID | Severity | Description |
|
|
290
|
+
|---------|----------|-------------|
|
|
291
|
+
| `ai-slop/empty-catch` | high | Catch blocks that silently swallow errors |
|
|
292
|
+
| `ai-slop/todo-implementation` | high | TODO/FIXME comments and placeholder throw statements |
|
|
293
|
+
| `ai-slop/giant-function` | medium | Functions exceeding 80 lines |
|
|
294
|
+
| `ai-slop/excessive-nesting` | medium | Control flow nesting deeper than 4 levels |
|
|
295
|
+
| `ai-slop/fake-validation` | high | Validation functions that unconditionally return true |
|
|
296
|
+
| `ai-slop/high-complexity` | medium | Cyclomatic complexity exceeding 10 |
|
|
297
|
+
| `ai-slop/dead-code` | medium | Unreachable code after return/throw/break/continue |
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### Security (`security`)
|
|
302
|
+
|
|
303
|
+
Rules that detect common vulnerability patterns.
|
|
304
|
+
|
|
305
|
+
| Rule ID | Severity | Description |
|
|
306
|
+
|---------|----------|-------------|
|
|
307
|
+
| `security/unsafe-eval` | critical | Use of eval() and new Function() |
|
|
308
|
+
| `security/hardcoded-secrets` | critical | API keys, passwords, tokens in source |
|
|
309
|
+
| `security/sql-injection` | critical | SQL built with string concatenation or template literals |
|
|
310
|
+
| `security/command-injection` | critical | child_process calls with dynamic arguments |
|
|
311
|
+
| `security/path-traversal` | critical | File system operations with dynamic paths |
|
|
312
|
+
| `security/prototype-pollution` | high | Dynamic property assignment and unsafe merge |
|
|
313
|
+
| `security/weak-crypto` | high | MD5, SHA1, ECB mode, Math.random() for secrets |
|
|
314
|
+
| `security/dangerous-cors` | high | Wildcard CORS, insecure cookie configuration |
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
### Reliability (`reliability`)
|
|
319
|
+
|
|
320
|
+
Rules that detect code likely to fail under load or in production conditions.
|
|
321
|
+
|
|
322
|
+
| Rule ID | Severity | Description |
|
|
323
|
+
|---------|----------|-------------|
|
|
324
|
+
| `reliability/unhandled-promise` | high | Fire-and-forget async calls with no error handling |
|
|
325
|
+
| `reliability/missing-await` | high | Async functions returning un-awaited Promises |
|
|
326
|
+
| `reliability/infinite-loop` | high | while(true) and for(;;) with no exit condition |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### Maintainability (`maintainability`)
|
|
331
|
+
|
|
332
|
+
Rules that identify structural problems affecting long-term code health.
|
|
333
|
+
|
|
334
|
+
| Rule ID | Severity | Description |
|
|
335
|
+
|---------|----------|-------------|
|
|
336
|
+
| `maintainability/giant-file` | medium | Source files exceeding 400 lines |
|
|
337
|
+
| `maintainability/circular-imports` | medium | Import patterns that commonly cause circular dependencies |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### Production Readiness (`production-readiness`)
|
|
342
|
+
|
|
343
|
+
Rules that detect development artifacts left in production code.
|
|
344
|
+
|
|
345
|
+
| Rule ID | Severity | Description |
|
|
346
|
+
|---------|----------|-------------|
|
|
347
|
+
| `production-readiness/no-console-log` | low | console.log and debug console methods |
|
|
348
|
+
| `production-readiness/no-localhost-urls` | medium | Localhost URLs, debug flags, mock implementations |
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Output Formats
|
|
353
|
+
|
|
354
|
+
### Text (default)
|
|
355
|
+
|
|
356
|
+
Color-coded terminal output with file grouping, severity labels, and optional verbose mode.
|
|
357
|
+
|
|
358
|
+
### JSON
|
|
359
|
+
|
|
360
|
+
Machine-readable full scan result. Includes every issue, score breakdown, file list, config, and metadata.
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
clean-slop scan --reporter json --output scan.json
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### HTML
|
|
367
|
+
|
|
368
|
+
Self-contained single-file interactive report with filtering by severity. Suitable for CI artifacts and sharing with non-technical stakeholders.
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
clean-slop report --reporter html --output ./reports/scan.html
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Markdown
|
|
375
|
+
|
|
376
|
+
GitHub-flavored Markdown report suitable for posting as a PR comment or including in CI artifact summaries.
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
clean-slop report --reporter markdown --output ./clean-slop.md
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### SARIF 2.1.0
|
|
383
|
+
|
|
384
|
+
Static Analysis Results Interchange Format. Compatible with GitHub Code Scanning, Azure DevOps, and VS Code SARIF Viewer.
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
clean-slop scan --reporter sarif --output results.sarif
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## JavaScript / TypeScript API
|
|
393
|
+
|
|
394
|
+
clean-slop exposes a full programmatic API for integration with build tools, scripts, and other tooling.
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import { scanDirectory, loadConfig, generateReport } from 'clean-slop';
|
|
398
|
+
|
|
399
|
+
// Simple usage
|
|
400
|
+
const result = await scanDirectory('./src');
|
|
401
|
+
console.log(`Score: ${result.score.overall}/100`);
|
|
402
|
+
console.log(`Issues: ${result.issues.length}`);
|
|
403
|
+
|
|
404
|
+
// With configuration
|
|
405
|
+
const config = await loadConfig(process.cwd());
|
|
406
|
+
const result = await scanDirectory('./src', {
|
|
407
|
+
categories: { security: true },
|
|
408
|
+
failThreshold: 80,
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// Generate a report
|
|
412
|
+
const html = generateReport(result, 'html');
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### API Reference
|
|
416
|
+
|
|
417
|
+
#### `scanDirectory(directory, config?)`
|
|
418
|
+
|
|
419
|
+
Scan a directory and return a `ScanResult`.
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
async function scanDirectory(
|
|
423
|
+
directory: string,
|
|
424
|
+
config?: UserConfig
|
|
425
|
+
): Promise<ScanResult>
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
#### `loadConfig(cwd, configPath?)`
|
|
429
|
+
|
|
430
|
+
Load and resolve configuration from the filesystem.
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
async function loadConfig(
|
|
434
|
+
cwd: string,
|
|
435
|
+
configPath?: string
|
|
436
|
+
): Promise<ResolvedConfig>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### `generateReport(result, reporter)`
|
|
440
|
+
|
|
441
|
+
Generate a report string from a scan result.
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
function generateReport(
|
|
445
|
+
result: ScanResult,
|
|
446
|
+
reporter: 'text' | 'json' | 'html' | 'markdown' | 'sarif'
|
|
447
|
+
): string
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## CI/CD Integration
|
|
453
|
+
|
|
454
|
+
### GitHub Actions
|
|
455
|
+
|
|
456
|
+
Add clean-slop as a required check in your CI pipeline:
|
|
457
|
+
|
|
458
|
+
```yaml
|
|
459
|
+
# .github/workflows/quality.yml
|
|
460
|
+
name: Code Quality
|
|
461
|
+
|
|
462
|
+
on: [push, pull_request]
|
|
463
|
+
|
|
464
|
+
jobs:
|
|
465
|
+
clean-slop:
|
|
466
|
+
name: Production Readiness Check
|
|
467
|
+
runs-on: ubuntu-latest
|
|
468
|
+
|
|
469
|
+
steps:
|
|
470
|
+
- uses: actions/checkout@v4
|
|
471
|
+
|
|
472
|
+
- uses: actions/setup-node@v4
|
|
473
|
+
with:
|
|
474
|
+
node-version: 20
|
|
475
|
+
|
|
476
|
+
- run: npm ci
|
|
477
|
+
|
|
478
|
+
- name: Scan with clean-slop
|
|
479
|
+
run: |
|
|
480
|
+
npx clean-slop scan src \
|
|
481
|
+
--reporter sarif \
|
|
482
|
+
--output clean-slop-results.sarif \
|
|
483
|
+
--fail-threshold 70 \
|
|
484
|
+
--max-critical 0
|
|
485
|
+
|
|
486
|
+
- name: Upload to GitHub Code Scanning
|
|
487
|
+
if: always()
|
|
488
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
489
|
+
with:
|
|
490
|
+
sarif_file: clean-slop-results.sarif
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### npm scripts
|
|
494
|
+
|
|
495
|
+
```json
|
|
496
|
+
{
|
|
497
|
+
"scripts": {
|
|
498
|
+
"quality": "clean-slop scan src",
|
|
499
|
+
"quality:ci": "clean-slop check src --fail-threshold 70",
|
|
500
|
+
"quality:report": "clean-slop report --reporter html --output reports/quality.html"
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Pre-commit hook
|
|
506
|
+
|
|
507
|
+
Using [husky](https://typicode.github.io/husky/):
|
|
508
|
+
|
|
509
|
+
```bash
|
|
510
|
+
npx husky add .husky/pre-commit "npx clean-slop check src --fail-threshold 60"
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## Plugin Development
|
|
516
|
+
|
|
517
|
+
clean-slop supports custom plugins that add new rules.
|
|
518
|
+
|
|
519
|
+
### Creating a Plugin
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
import type { Plugin, Rule, RuleContext } from 'clean-slop';
|
|
523
|
+
|
|
524
|
+
const myRule: Rule = {
|
|
525
|
+
meta: {
|
|
526
|
+
id: 'my-plugin/no-deprecated-api',
|
|
527
|
+
name: 'No Deprecated API',
|
|
528
|
+
category: 'maintainability',
|
|
529
|
+
severity: 'medium',
|
|
530
|
+
confidence: 'high',
|
|
531
|
+
description: 'Detects usage of deprecated internal APIs.',
|
|
532
|
+
rationale: 'Deprecated APIs will be removed in the next major release.',
|
|
533
|
+
docsUrl: 'https://myteam.dev/docs/rules/no-deprecated-api',
|
|
534
|
+
fixable: false,
|
|
535
|
+
},
|
|
536
|
+
|
|
537
|
+
create(context: RuleContext) {
|
|
538
|
+
// Use the traverse utility or work with context.ast directly
|
|
539
|
+
const ast = context.ast;
|
|
540
|
+
|
|
541
|
+
// Report an issue
|
|
542
|
+
context.report({
|
|
543
|
+
message: 'Usage of deprecated API detected.',
|
|
544
|
+
explanation: 'The legacyClient API will be removed in v3.0.',
|
|
545
|
+
impact: 'This call will throw at runtime after the upgrade.',
|
|
546
|
+
location: {
|
|
547
|
+
file: context.filePath,
|
|
548
|
+
line: 10,
|
|
549
|
+
column: 0,
|
|
550
|
+
},
|
|
551
|
+
fix: {
|
|
552
|
+
description: 'Replace legacyClient with modernClient.',
|
|
553
|
+
code: "import { modernClient } from '@myorg/client';",
|
|
554
|
+
},
|
|
555
|
+
});
|
|
556
|
+
},
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
const plugin: Plugin = {
|
|
560
|
+
name: 'my-plugin',
|
|
561
|
+
version: '1.0.0',
|
|
562
|
+
rules: [myRule],
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
export default plugin;
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Registering a Plugin
|
|
569
|
+
|
|
570
|
+
```javascript
|
|
571
|
+
// clean-slop.config.js
|
|
572
|
+
export default {
|
|
573
|
+
plugins: ['./my-plugin.js', 'clean-slop-plugin-nestjs'],
|
|
574
|
+
};
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## Architecture Overview
|
|
580
|
+
|
|
581
|
+
```
|
|
582
|
+
clean-slop/
|
|
583
|
+
├── src/
|
|
584
|
+
│ ├── cli/ # Commander-based CLI and command implementations
|
|
585
|
+
│ │ ├── bin.ts # Entry point (#!/usr/bin/env node)
|
|
586
|
+
│ │ ├── index.ts # Command registration
|
|
587
|
+
│ │ └── commands/ # scan, check, watch, report, doctor, init
|
|
588
|
+
│ ├── config/ # cosmiconfig loader and config resolution
|
|
589
|
+
│ ├── parsers/ # @typescript-eslint/typescript-estree AST parser
|
|
590
|
+
│ ├── rules/ # Rule engine and all built-in rules
|
|
591
|
+
│ │ ├── engine.ts # RuleEngine class
|
|
592
|
+
│ │ ├── index.ts # BUILT_IN_RULES registry
|
|
593
|
+
│ │ ├── ai-slop/ # AI slop detection rules
|
|
594
|
+
│ │ ├── security/ # Security rules
|
|
595
|
+
│ │ ├── reliability/ # Reliability rules
|
|
596
|
+
│ │ ├── maintainability/ # Maintainability rules
|
|
597
|
+
│ │ └── production-readiness/ # Production readiness rules
|
|
598
|
+
│ ├── scanners/ # File discovery and orchestration
|
|
599
|
+
│ ├── reporters/ # text, json, html, markdown, sarif reporters
|
|
600
|
+
│ ├── utils/ # AST traversal, constants, shared utilities
|
|
601
|
+
│ ├── types.ts # All shared TypeScript interfaces
|
|
602
|
+
│ ├── version.ts # Package version constant
|
|
603
|
+
│ └── index.ts # Public API exports
|
|
604
|
+
├── tests/
|
|
605
|
+
│ ├── unit/ # Per-rule unit tests
|
|
606
|
+
│ ├── integration/ # Full scan pipeline tests
|
|
607
|
+
│ └── fixtures/ # Deliberately bad code for testing
|
|
608
|
+
└── .github/workflows/ # CI and release automation
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
**Data flow:**
|
|
612
|
+
|
|
613
|
+
1. CLI parses arguments → loads config
|
|
614
|
+
2. Scanner discovers files matching include/exclude globs
|
|
615
|
+
3. Parser converts each file to an AST using `@typescript-eslint/typescript-estree`
|
|
616
|
+
4. Rule engine iterates rules, calls `rule.create(context)` for each file
|
|
617
|
+
5. Rules call `context.report()` to record issues
|
|
618
|
+
6. Scanner computes per-category scores and overall score
|
|
619
|
+
7. Reporter generates output in the requested format
|
|
620
|
+
8. CLI exits with appropriate code based on score and maxIssues thresholds
|
|
621
|
+
|
|
622
|
+
---
|
|
623
|
+
|
|
624
|
+
## Security Philosophy
|
|
625
|
+
|
|
626
|
+
clean-slop treats security as a first-class concern. The security rule category is always enabled by default and cannot be silently bypassed.
|
|
627
|
+
|
|
628
|
+
Key principles:
|
|
629
|
+
|
|
630
|
+
**Detect at the pattern level.** Most static analysis requires full data-flow tracking, which is expensive and complex. clean-slop detects high-signal structural patterns that reliably indicate vulnerability classes even without full data-flow.
|
|
631
|
+
|
|
632
|
+
**Report false positives, not false negatives.** When a pattern is ambiguous, clean-slop reports it with an appropriate confidence level rather than silently ignoring it. A false positive in a security tool is a minor annoyance. A false negative is a breach.
|
|
633
|
+
|
|
634
|
+
**Explain why it matters.** Every security issue includes an `impact` field that explains what an attacker can do if the issue is exploited. Security issues are not academic.
|
|
635
|
+
|
|
636
|
+
**Never disable critical rules in config.** The `failThreshold` and `maxIssues` configuration allows teams to tune the gate, but rules themselves can only be downgraded or turned off explicitly by ID in configuration. There is no way to globally disable security checks.
|
|
637
|
+
|
|
638
|
+
---
|
|
639
|
+
|
|
640
|
+
## AI Slop Philosophy
|
|
641
|
+
|
|
642
|
+
AI code generation tools are productivity multipliers. They are also pattern completion engines that produce syntactically correct, test-passable code without any understanding of production requirements.
|
|
643
|
+
|
|
644
|
+
The AI slop category detects specific patterns that AI generators produce systematically:
|
|
645
|
+
|
|
646
|
+
- **Empty catch blocks** — the generator handles the error path syntactically but not semantically. The exception vanishes.
|
|
647
|
+
- **Fake validation** — the generator names the function `validateEmail` to make the code look complete, but the body is `return true`.
|
|
648
|
+
- **TODO/placeholder throws** — the generator creates the skeleton of a feature and marks everything unimplemented. The feature is never implemented.
|
|
649
|
+
- **Giant functions** — the generator places all logic in a single function without decomposing it into maintainable units.
|
|
650
|
+
- **High complexity** — the generator combines multiple responsibilities into one function, creating code with too many paths to test.
|
|
651
|
+
|
|
652
|
+
clean-slop does not penalize AI-assisted development. It penalizes AI-generated code that was never reviewed.
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## Contributing
|
|
657
|
+
|
|
658
|
+
Contributions are welcome. The project is structured so that adding a new rule requires only creating a single file in the appropriate category directory and adding the import to `src/rules/index.ts`.
|
|
659
|
+
|
|
660
|
+
### Development Setup
|
|
661
|
+
|
|
662
|
+
```bash
|
|
663
|
+
git clone https://github.com/clean-slop/clean-slop
|
|
664
|
+
cd clean-slop
|
|
665
|
+
npm install
|
|
666
|
+
npm run build
|
|
667
|
+
npm test
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Adding a Rule
|
|
671
|
+
|
|
672
|
+
1. Create `src/rules/<category>/<rule-name>.ts`
|
|
673
|
+
2. Implement the `Rule` interface (see existing rules for examples)
|
|
674
|
+
3. Add the import and export to `src/rules/index.ts`
|
|
675
|
+
4. Add unit tests to `tests/unit/`
|
|
676
|
+
5. Add a fixture case to `tests/fixtures/` if needed
|
|
677
|
+
|
|
678
|
+
### Rule Implementation Template
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
import type { Rule } from '../../types.js';
|
|
682
|
+
import { traverse, getLocation } from '../../utils/ast.js';
|
|
683
|
+
import type { ASTNode } from '../../utils/ast.js';
|
|
684
|
+
|
|
685
|
+
const rule: Rule = {
|
|
686
|
+
meta: {
|
|
687
|
+
id: 'category/rule-name',
|
|
688
|
+
name: 'Human Readable Rule Name',
|
|
689
|
+
category: 'security', // ai-slop | security | reliability | maintainability | production-readiness
|
|
690
|
+
severity: 'high',
|
|
691
|
+
confidence: 'high',
|
|
692
|
+
description: 'One sentence description.',
|
|
693
|
+
rationale: 'Why this matters and what it indicates.',
|
|
694
|
+
docsUrl: 'https://clean-slop.dev/docs/rules/category/rule-name',
|
|
695
|
+
fixable: false,
|
|
696
|
+
},
|
|
697
|
+
|
|
698
|
+
create(context) {
|
|
699
|
+
traverse(context.ast, {
|
|
700
|
+
CallExpression(node: ASTNode) {
|
|
701
|
+
// Detection logic here
|
|
702
|
+
context.report({
|
|
703
|
+
message: 'Short description of what was found.',
|
|
704
|
+
explanation: 'Full explanation of the issue.',
|
|
705
|
+
impact: 'What happens in production if this is not fixed.',
|
|
706
|
+
location: getLocation(node, context.filePath),
|
|
707
|
+
fix: {
|
|
708
|
+
description: 'How to fix this.',
|
|
709
|
+
code: '// Example fix code',
|
|
710
|
+
},
|
|
711
|
+
});
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
},
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
export default rule;
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### Testing Guide
|
|
721
|
+
|
|
722
|
+
```bash
|
|
723
|
+
# Run all tests
|
|
724
|
+
npm test
|
|
725
|
+
|
|
726
|
+
# Run tests in watch mode
|
|
727
|
+
npm run test:watch
|
|
728
|
+
|
|
729
|
+
# Run with coverage
|
|
730
|
+
npm run test:coverage
|
|
731
|
+
|
|
732
|
+
# Run a specific test file
|
|
733
|
+
npx vitest run tests/unit/security-rules.test.ts
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### Commit Convention
|
|
737
|
+
|
|
738
|
+
This project follows [Conventional Commits](https://www.conventionalcommits.org/):
|
|
739
|
+
|
|
740
|
+
```
|
|
741
|
+
feat: add new rule security/jwt-none-algorithm
|
|
742
|
+
fix: correct false positive in ai-slop/fake-validation
|
|
743
|
+
docs: update CLI reference for watch command
|
|
744
|
+
test: add coverage for path-traversal rule
|
|
745
|
+
refactor: extract AST traversal utilities
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Release Guide
|
|
751
|
+
|
|
752
|
+
Releases are automated via GitHub Actions on tag push.
|
|
753
|
+
|
|
754
|
+
```bash
|
|
755
|
+
# Bump version
|
|
756
|
+
npm version patch # 1.0.0 → 1.0.1
|
|
757
|
+
npm version minor # 1.0.0 → 1.1.0
|
|
758
|
+
npm version major # 1.0.0 → 2.0.0
|
|
759
|
+
|
|
760
|
+
# Push with tag
|
|
761
|
+
git push origin main --follow-tags
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
The release workflow will:
|
|
765
|
+
1. Run tests
|
|
766
|
+
2. Build the package
|
|
767
|
+
3. Publish to npm with provenance
|
|
768
|
+
4. Create a GitHub Release with auto-generated release notes
|
|
769
|
+
|
|
770
|
+
---
|
|
771
|
+
|
|
772
|
+
## Troubleshooting
|
|
773
|
+
|
|
774
|
+
**Parse errors on valid files**
|
|
775
|
+
|
|
776
|
+
clean-slop uses `@typescript-eslint/typescript-estree` for parsing. Experimental syntax (decorators, certain JSX patterns) may require a `tsconfig.json`. Run `clean-slop doctor` to verify the environment.
|
|
777
|
+
|
|
778
|
+
**False positives in generated code**
|
|
779
|
+
|
|
780
|
+
Add generated files to the `exclude` array in configuration:
|
|
781
|
+
|
|
782
|
+
```javascript
|
|
783
|
+
exclude: ['**/__generated__/**', '**/*.generated.ts', '**/graphql-types.ts'],
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
**Score is lower than expected**
|
|
787
|
+
|
|
788
|
+
Run with `--verbose` to see the full explanation for each issue. Check which category is pulling the score down and use `--no-<category>` flags or per-rule `'off'` configuration to tune the results.
|
|
789
|
+
|
|
790
|
+
**CI exits with code 1**
|
|
791
|
+
|
|
792
|
+
The process exits with code 1 when the score is below `failThreshold` or when `maxIssues` limits are exceeded. Run `clean-slop scan --verbose` locally to see exactly which issues are causing the failure.
|
|
793
|
+
|
|
794
|
+
---
|
|
795
|
+
|
|
796
|
+
## FAQ
|
|
797
|
+
|
|
798
|
+
**Does clean-slop replace ESLint?**
|
|
799
|
+
|
|
800
|
+
No. ESLint and clean-slop serve different purposes. ESLint is a style and correctness linter. clean-slop analyzes production readiness patterns, security vulnerabilities, and AI-generated code quality. They are complementary.
|
|
801
|
+
|
|
802
|
+
**Can I use clean-slop with JavaScript (not TypeScript)?**
|
|
803
|
+
|
|
804
|
+
Yes. clean-slop supports plain `.js`, `.jsx`, `.mjs`, and `.cjs` files.
|
|
805
|
+
|
|
806
|
+
**Does clean-slop modify my code?**
|
|
807
|
+
|
|
808
|
+
No. clean-slop is a read-only analysis tool. It reports issues and suggests fixes but never modifies files. The `fix` field in each issue contains suggested remediation, but applying it is always a manual action.
|
|
809
|
+
|
|
810
|
+
**What is the performance profile?**
|
|
811
|
+
|
|
812
|
+
On a typical 50,000 line TypeScript project, clean-slop completes a full scan in 2–5 seconds on modern hardware.
|
|
813
|
+
|
|
814
|
+
**How is the score calculated?**
|
|
815
|
+
|
|
816
|
+
Each category starts at 100. Issues deduct points based on severity: critical (-20), high (-10), medium (-4), low (-1). Each category score is floored at 0. The overall score is the average of all 5 category scores.
|
|
817
|
+
|
|
818
|
+
**Can teams add custom rules?**
|
|
819
|
+
|
|
820
|
+
Yes, via the plugin system. See the Plugin Development section above.
|
|
821
|
+
|
|
822
|
+
---
|
|
823
|
+
|
|
824
|
+
## Roadmap
|
|
825
|
+
|
|
826
|
+
- [ ] Additional security rules: JWT algorithm validation, ReDoS detection, insecure deserialization
|
|
827
|
+
- [ ] React-specific rules: missing key props, unsafe innerHTML, useEffect cleanup
|
|
828
|
+
- [ ] Next.js rules: server-side data exposure, missing authentication on API routes
|
|
829
|
+
- [ ] NestJS rules: missing guards, exposed internal routes
|
|
830
|
+
- [ ] Dependency health analysis (known vulnerabilities via OSV)
|
|
831
|
+
- [ ] Duplicate code detection (AST-based similarity)
|
|
832
|
+
- [ ] VS Code extension
|
|
833
|
+
- [ ] GitHub App for automated PR comments
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
837
|
+
## License
|
|
838
|
+
|
|
839
|
+
MIT — see [LICENSE](./LICENSE)
|
|
840
|
+
|
|
841
|
+
---
|
|
842
|
+
|
|
843
|
+
## Code of Conduct
|
|
844
|
+
|
|
845
|
+
This project follows the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct. Be respectful, constructive, and professional in all interactions.
|
|
846
|
+
|
|
847
|
+
---
|
|
848
|
+
|
|
849
|
+
*clean-slop is built for teams that ship production software and need confidence that what they merge is actually ready for production.*
|