@lhi/tdd-audit 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/index.js +4 -3
- package/lib/badge.js +12 -5
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/prompts/auto-audit.md +109 -0
- package/prompts/hardening-phase.md +91 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @lhi/tdd-audit
|
|
2
2
|
[](https://www.npmjs.com/package/@lhi/tdd-audit) <!-- tdd-audit-badge -->
|
|
3
3
|
|
|
4
|
-
> **v1.
|
|
4
|
+
> **v1.15.0** — Security skill installer for **Claude Code, Gemini CLI, Cursor, Codex, and OpenCode**. Patches vulnerabilities using a Red-Green-Refactor exploit-test protocol — prove the hole exists, apply the fix, prove it's closed. Enforces ≥ 95% test coverage, README badge, and SECURITY.md on every audit.
|
|
5
5
|
|
|
6
6
|
## Install
|
|
7
7
|
|
package/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const {
|
|
|
12
12
|
printFindings,
|
|
13
13
|
} = require('./lib/scanner');
|
|
14
14
|
const { toJson, toSarif, toText } = require('./lib/reporter');
|
|
15
|
-
const { writeInitConfig } = require('./lib/config');
|
|
15
|
+
const { writeInitConfig, loadConfig, parseCliOverrides } = require('./lib/config');
|
|
16
16
|
const { badgeLine, injectBadge } = require('./lib/badge');
|
|
17
17
|
|
|
18
18
|
const args = process.argv.slice(2);
|
|
@@ -35,6 +35,7 @@ const outputFormat = args.includes('--json') ? 'json'
|
|
|
35
35
|
const agentBaseDir = isLocal ? process.cwd() : os.homedir();
|
|
36
36
|
const agentDirName = isClaude ? '.claude' : '.agents';
|
|
37
37
|
const projectDir = process.cwd();
|
|
38
|
+
const config = loadConfig(projectDir, parseCliOverrides(args));
|
|
38
39
|
|
|
39
40
|
const targetSkillDir = path.join(agentBaseDir, agentDirName, 'skills', 'tdd-remediation');
|
|
40
41
|
const targetWorkflowDir = isClaude
|
|
@@ -88,7 +89,7 @@ if (scanOnly) {
|
|
|
88
89
|
process.stdout.write('\n');
|
|
89
90
|
printFindings(findings, exempted);
|
|
90
91
|
}
|
|
91
|
-
injectBadge(projectDir, badgeLine(findings));
|
|
92
|
+
injectBadge(projectDir, badgeLine(findings, config.tdd_site));
|
|
92
93
|
process.exit(0);
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -245,7 +246,7 @@ if (!skipScan) {
|
|
|
245
246
|
const findings = quickScan(projectDir);
|
|
246
247
|
process.stdout.write('\n');
|
|
247
248
|
printFindings(findings);
|
|
248
|
-
const badge = badgeLine(findings);
|
|
249
|
+
const badge = badgeLine(findings, config.tdd_site);
|
|
249
250
|
injectBadge(projectDir, badge);
|
|
250
251
|
console.log('✅ README badge updated');
|
|
251
252
|
}
|
package/lib/badge.js
CHANGED
|
@@ -17,10 +17,16 @@ const NPM_URL = 'https://www.npmjs.com/package/@lhi/tdd-audit';
|
|
|
17
17
|
*
|
|
18
18
|
* likelyFalsePositive findings (test fixtures) are excluded from the count.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* The badge links to `siteUrl` when provided (set via `tdd_site` in
|
|
21
|
+
* .tdd-audit.json). When absent — including all skill-mode invocations where
|
|
22
|
+
* no config file exists — the link falls back to the @lhi/tdd-audit npm page
|
|
23
|
+
* so readers always know where the security tooling came from.
|
|
24
|
+
*
|
|
25
|
+
* @param {Array} findings - findings array returned by quickScan()
|
|
26
|
+
* @param {string} [siteUrl] - optional override link (from config.tdd_site)
|
|
27
|
+
* @returns {string} - single-line markdown badge ending with \n
|
|
22
28
|
*/
|
|
23
|
-
function badgeLine(findings) {
|
|
29
|
+
function badgeLine(findings, siteUrl) {
|
|
24
30
|
// Exclude test-file findings and likely false positives — badge reflects production code only
|
|
25
31
|
const real = (findings || []).filter(f => !f.likelyFalsePositive && !f.inTestFile);
|
|
26
32
|
const criticals = real.filter(f => f.severity === 'CRITICAL').length;
|
|
@@ -38,10 +44,11 @@ function badgeLine(findings) {
|
|
|
38
44
|
color = 'brightgreen';
|
|
39
45
|
}
|
|
40
46
|
|
|
41
|
-
const badgeUrl
|
|
47
|
+
const badgeUrl = `https://img.shields.io/badge/tdd--audit-${message}-${color}`;
|
|
48
|
+
const targetUrl = (siteUrl && siteUrl.trim()) ? siteUrl.trim() : NPM_URL;
|
|
42
49
|
// Embed the marker as a hidden HTML comment after the badge so injectBadge()
|
|
43
50
|
// can locate and replace the line on subsequent runs.
|
|
44
|
-
return `[](${
|
|
51
|
+
return `[](${targetUrl}) <!-- ${BADGE_MARKER} -->\n`;
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
/**
|
package/lib/config.js
CHANGED
|
@@ -17,6 +17,7 @@ const DEFAULTS = {
|
|
|
17
17
|
apiKeyEnv: null, // env var name to read the key from
|
|
18
18
|
serverApiKey: null, // key required on REST API calls
|
|
19
19
|
trustProxy: false, // trust X-Forwarded-For for rate limiting
|
|
20
|
+
tdd_site: null, // custom URL for the README badge link; falls back to npm page
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
// Provider-specific defaults for `tdd-audit init --provider <name>`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lhi/tdd-audit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "Security skill installer for Claude Code, Gemini CLI, Cursor, Codex, and OpenCode. Patches vulnerabilities using a Red-Green-Refactor exploit-test protocol.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/prompts/auto-audit.md
CHANGED
|
@@ -400,6 +400,115 @@ After all vulnerabilities are addressed, output a final **Remediation Summary**:
|
|
|
400
400
|
|
|
401
401
|
---
|
|
402
402
|
|
|
403
|
+
## Phase 4: Coverage Gate (≥ 95%)
|
|
404
|
+
|
|
405
|
+
After all vulnerabilities are patched and the hardening checklist is complete, measure test coverage and drive it to **≥ 95% line and branch coverage**.
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
# Node.js / Jest
|
|
409
|
+
npx jest --coverage --coverageReporters=text
|
|
410
|
+
|
|
411
|
+
# Python
|
|
412
|
+
pytest --cov=. --cov-report=term-missing
|
|
413
|
+
|
|
414
|
+
# Go
|
|
415
|
+
go test ./... -coverprofile=coverage.out && go tool cover -func=coverage.out
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
1. Run the coverage report.
|
|
419
|
+
2. Identify every uncovered line or branch.
|
|
420
|
+
3. For each gap: write a test (Red — must fail without the code path), confirm it passes (Green), re-run coverage.
|
|
421
|
+
4. Repeat until the overall line **and** branch coverage both reach ≥ 95%.
|
|
422
|
+
5. If a file is intentionally excluded (e.g., generated code, migration stubs), add it to the coverage exclusion config and note the reason.
|
|
423
|
+
|
|
424
|
+
Do **not** write empty or trivially-true tests to inflate numbers. Every test must assert real behavior.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Phase 5: Badge README
|
|
429
|
+
|
|
430
|
+
Once coverage is ≥ 95%, add a coverage badge to `README.md`.
|
|
431
|
+
|
|
432
|
+
- If `README.md` does not exist, create a minimal one with the project name and badge.
|
|
433
|
+
- The badge must appear at the **top of the file**, before any other content.
|
|
434
|
+
- Use a static Shields.io badge that reflects the actual measured value:
|
|
435
|
+
|
|
436
|
+
```markdown
|
|
437
|
+

|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Colour tiers:**
|
|
441
|
+
|
|
442
|
+
| Coverage | Colour |
|
|
443
|
+
|---|---|
|
|
444
|
+
| ≥ 90% | `brightgreen` |
|
|
445
|
+
| 75–89% | `yellow` |
|
|
446
|
+
| < 75% | `red` |
|
|
447
|
+
|
|
448
|
+
Adjust the percentage in the badge URL to match the real number (e.g., `97%25` for 97%).
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Phase 6: SECURITY.md
|
|
453
|
+
|
|
454
|
+
Check whether a `SECURITY.md` exists at the repo root.
|
|
455
|
+
|
|
456
|
+
- **If it exists** — do not overwrite it. Read it and confirm it has a vulnerability reporting contact. If missing, append one.
|
|
457
|
+
- **If it does not exist** — create it following the GitHub Security Advisory format:
|
|
458
|
+
|
|
459
|
+
```markdown
|
|
460
|
+
# Security Policy
|
|
461
|
+
|
|
462
|
+
## Supported Versions
|
|
463
|
+
|
|
464
|
+
| Version | Supported |
|
|
465
|
+
|---|---|
|
|
466
|
+
| latest | ✅ |
|
|
467
|
+
| < latest | ❌ |
|
|
468
|
+
|
|
469
|
+
## Reporting a Vulnerability
|
|
470
|
+
|
|
471
|
+
Please **do not** open a public GitHub issue for security vulnerabilities.
|
|
472
|
+
|
|
473
|
+
Report vulnerabilities privately via:
|
|
474
|
+
- **GitHub**: Use [GitHub's private vulnerability reporting](../../security/advisories/new)
|
|
475
|
+
- **Email**: security@example.com *(replace with project contact)*
|
|
476
|
+
|
|
477
|
+
Expect acknowledgement within **48 hours** and a patch or mitigation plan within **14 days** for verified HIGH/CRITICAL issues. Reporters are credited in release notes unless anonymity is requested.
|
|
478
|
+
|
|
479
|
+
## Security Hardening
|
|
480
|
+
|
|
481
|
+
This repository is maintained with the following controls:
|
|
482
|
+
|
|
483
|
+
- HTTP security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)
|
|
484
|
+
- Rate limiting on all state-mutating and authentication routes
|
|
485
|
+
- Dependencies audited on every CI run (`npm audit --audit-level=high`)
|
|
486
|
+
- No secrets committed to git history (verified with gitleaks / trufflehog)
|
|
487
|
+
- ≥ 95% test coverage enforced via CI coverage gate
|
|
488
|
+
- Vulnerabilities remediated using a Red-Green-Refactor exploit-test protocol
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Replace placeholder email and version table with the project's real information.
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## Final Report
|
|
496
|
+
|
|
497
|
+
After Phases 4–6 complete, append to the Remediation Summary:
|
|
498
|
+
|
|
499
|
+
```
|
|
500
|
+
## Coverage & Documentation
|
|
501
|
+
|
|
502
|
+
| Item | Status | Detail |
|
|
503
|
+
|---|---|---|
|
|
504
|
+
| Line coverage | ✅ | 96.4% |
|
|
505
|
+
| Branch coverage | ✅ | 95.1% |
|
|
506
|
+
| README badge | ✅ | Updated to 96% (brightgreen) |
|
|
507
|
+
| SECURITY.md | ✅ | Created at repo root |
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
403
512
|
## Agentic AI Security (ASI01–ASI10)
|
|
404
513
|
|
|
405
514
|
When the project contains AI agent code, MCP configurations, CLAUDE.md files, or tool-calling patterns, also scan for agentic-specific vulnerabilities. These can be harder to spot than traditional web vulns but carry severe consequences (data exfiltration via tool abuse, agent hijacking, supply chain via MCP).
|
|
@@ -321,6 +321,94 @@ If this project contains AI agent code, MCP configurations, or CLAUDE.md files,
|
|
|
321
321
|
|
|
322
322
|
---
|
|
323
323
|
|
|
324
|
+
## 4l. Coverage Gate (≥ 95%)
|
|
325
|
+
|
|
326
|
+
After hardening is complete, measure test coverage and drive it to **≥ 95% line and branch coverage** before closing the audit.
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# Node.js / Jest
|
|
330
|
+
npx jest --coverage --coverageReporters=text
|
|
331
|
+
|
|
332
|
+
# Python
|
|
333
|
+
pytest --cov=. --cov-report=term-missing
|
|
334
|
+
|
|
335
|
+
# Go
|
|
336
|
+
go test ./... -coverprofile=coverage.out && go tool cover -func=coverage.out
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
1. Run the coverage report and note every uncovered line or branch.
|
|
340
|
+
2. For each gap: write a failing test (Red), make it pass (Green), re-run coverage.
|
|
341
|
+
3. Repeat until line **and** branch coverage both reach ≥ 95%.
|
|
342
|
+
4. Files that are intentionally excluded (generated code, migration stubs) must be listed in the coverage config with a reason.
|
|
343
|
+
|
|
344
|
+
Do **not** write trivially-true tests to inflate numbers — every test must assert real behavior.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## 4m. Badge README
|
|
349
|
+
|
|
350
|
+
Once coverage is ≥ 95%, add (or update) a coverage badge in `README.md`. If no `README.md` exists, create a minimal one.
|
|
351
|
+
|
|
352
|
+
The badge must appear at the **top of the file**, before any other content:
|
|
353
|
+
|
|
354
|
+
```markdown
|
|
355
|
+

|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Colour tiers:**
|
|
359
|
+
|
|
360
|
+
| Coverage | Colour |
|
|
361
|
+
|---|---|
|
|
362
|
+
| ≥ 90% | `brightgreen` |
|
|
363
|
+
| 75–89% | `yellow` |
|
|
364
|
+
| < 75% | `red` |
|
|
365
|
+
|
|
366
|
+
Adjust the percentage to match the actual measured value (e.g., `97%25` for 97%). Do not overwrite other existing badges — add the coverage badge as the first badge on the line.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## 4n. SECURITY.md
|
|
371
|
+
|
|
372
|
+
Check whether a `SECURITY.md` exists at the repo root. **Do not overwrite an existing file.**
|
|
373
|
+
|
|
374
|
+
If absent, create one following the GitHub Security Advisory format:
|
|
375
|
+
|
|
376
|
+
```markdown
|
|
377
|
+
# Security Policy
|
|
378
|
+
|
|
379
|
+
## Supported Versions
|
|
380
|
+
|
|
381
|
+
| Version | Supported |
|
|
382
|
+
|---|---|
|
|
383
|
+
| latest | ✅ |
|
|
384
|
+
| < latest | ❌ |
|
|
385
|
+
|
|
386
|
+
## Reporting a Vulnerability
|
|
387
|
+
|
|
388
|
+
Please **do not** open a public GitHub issue for security vulnerabilities.
|
|
389
|
+
|
|
390
|
+
Report privately via:
|
|
391
|
+
- **GitHub**: Use [GitHub's private vulnerability reporting](../../security/advisories/new)
|
|
392
|
+
- **Email**: security@example.com *(replace with project contact)*
|
|
393
|
+
|
|
394
|
+
Expect acknowledgement within **48 hours** and a patch or mitigation plan within **14 days** for verified HIGH/CRITICAL issues. Reporters are credited in release notes unless anonymity is requested.
|
|
395
|
+
|
|
396
|
+
## Security Hardening
|
|
397
|
+
|
|
398
|
+
This repository is maintained with the following controls:
|
|
399
|
+
|
|
400
|
+
- HTTP security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)
|
|
401
|
+
- Rate limiting on all state-mutating and authentication routes
|
|
402
|
+
- Dependencies audited on every CI run (`npm audit --audit-level=high`)
|
|
403
|
+
- No secrets committed to git history (verified with gitleaks / trufflehog)
|
|
404
|
+
- ≥ 95% test coverage enforced via CI coverage gate
|
|
405
|
+
- Vulnerabilities remediated using a Red-Green-Refactor exploit-test protocol
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Replace placeholder email and version table with the project's real information.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
324
412
|
## 4k. Hardening Verification Checklist
|
|
325
413
|
|
|
326
414
|
After Phase 4, confirm all of the following:
|
|
@@ -341,3 +429,6 @@ After Phase 4, confirm all of the following:
|
|
|
341
429
|
- [ ] `CLAUDE.md` in version control and reviewed; no user-supplied content
|
|
342
430
|
- [ ] MCP servers pinned to exact versions or local installs
|
|
343
431
|
- [ ] Agent tool permissions scoped to minimum required
|
|
432
|
+
- [ ] Test coverage ≥ 95% line and branch (4l)
|
|
433
|
+
- [ ] `README.md` has a coverage badge at the top reflecting the actual % (4m)
|
|
434
|
+
- [ ] `SECURITY.md` exists at repo root with a private vulnerability reporting contact (4n)
|