@lhi/tdd-audit 1.18.0 → 1.20.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 +181 -106
- package/docs/configuration.md +236 -0
- package/lib/auditor.js +1 -0
- package/lib/badge.js +22 -2
- package/lib/config.js +38 -1
- package/lib/github.js +1 -1
- package/lib/reporter.js +18 -3
- package/package.json +1 -1
- package/prompts/auto-audit.md +193 -6
- package/prompts/security-test-patterns.md +522 -0
package/lib/badge.js
CHANGED
|
@@ -8,6 +8,24 @@ const BADGE_MARKER = 'tdd-audit-badge';
|
|
|
8
8
|
|
|
9
9
|
const NPM_URL = 'https://www.npmjs.com/package/@lhi/tdd-audit';
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Validate that a URL uses http: or https:. Returns the URL if safe, NPM_URL otherwise.
|
|
13
|
+
* Prevents javascript:, data:, file:, and protocol-relative URLs from landing in
|
|
14
|
+
* badge links or SARIF output.
|
|
15
|
+
* @param {string} raw
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function safeSiteUrl(raw) {
|
|
19
|
+
if (!raw || !raw.trim()) return NPM_URL;
|
|
20
|
+
try {
|
|
21
|
+
const parsed = new URL(raw.trim());
|
|
22
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return NPM_URL;
|
|
23
|
+
return raw.trim();
|
|
24
|
+
} catch {
|
|
25
|
+
return NPM_URL;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
11
29
|
/**
|
|
12
30
|
* Build a shields.io badge markdown line reflecting actual scan results.
|
|
13
31
|
*
|
|
@@ -48,11 +66,13 @@ function badgeLine(findings, siteUrl, label) {
|
|
|
48
66
|
color = 'brightgreen';
|
|
49
67
|
}
|
|
50
68
|
|
|
51
|
-
const
|
|
69
|
+
const rawLabel = (label && label.trim()) ? label.trim() : 'tdd-audit';
|
|
70
|
+
// Strip markdown link-breaking characters before embedding in alt text or URL
|
|
71
|
+
const badgeLabel = rawLabel.replace(/[[\]()]/g, '');
|
|
52
72
|
// Encode the label for use in a shields.io URL (spaces → %20, hyphens → --)
|
|
53
73
|
const encodedLabel = badgeLabel.replace(/ /g, '%20').replace(/-/g, '--');
|
|
54
74
|
const badgeUrl = `https://img.shields.io/badge/${encodedLabel}-${message}-${color}`;
|
|
55
|
-
const targetUrl = (siteUrl
|
|
75
|
+
const targetUrl = safeSiteUrl(siteUrl);
|
|
56
76
|
// Embed the marker as a hidden HTML comment after the badge so injectBadge()
|
|
57
77
|
// can locate and replace the line on subsequent runs.
|
|
58
78
|
return `[](${targetUrl}) <!-- ${BADGE_MARKER} -->\n`;
|
package/lib/config.js
CHANGED
|
@@ -23,6 +23,8 @@ const DEFAULTS = {
|
|
|
23
23
|
org: null, // org name in reports, SECURITY.md, and pattern PRs
|
|
24
24
|
project: null, // project name in reports and pattern contribution branch names
|
|
25
25
|
badge_label: null, // badge label text; defaults to 'tdd-audit'
|
|
26
|
+
security_name: null, // name of the security contact (stamped into SECURITY.md, compliance reports, and webhook payloads)
|
|
27
|
+
security_email: null, // email of the security contact (used as the vulnerability reporting address in SECURITY.md)
|
|
26
28
|
|
|
27
29
|
// Extensibility — both the CLI and the Claude Code skill honour these
|
|
28
30
|
pattern_repos: [], // [{name, url, local_path, namespace}] — RAG-indexed at startup
|
|
@@ -30,6 +32,33 @@ const DEFAULTS = {
|
|
|
30
32
|
extra_repos: [], // [{url, local_path}] — cloned/pulled for reference
|
|
31
33
|
mcp_services: [], // [{name, cwd, command, args}] — started before first agent turn
|
|
32
34
|
extra_domains: [], // [{name, prompt_file}] — custom audit domains
|
|
35
|
+
|
|
36
|
+
// Policy as code — org-level severity overrides
|
|
37
|
+
// e.g. { "CORS Wildcard": "CRITICAL", "Sensitive Log": "HIGH" }
|
|
38
|
+
severity_overrides: {},
|
|
39
|
+
|
|
40
|
+
// Notifications — fire on scan complete
|
|
41
|
+
webhook_url: null, // POST findings JSON to this URL on scan complete
|
|
42
|
+
slack_webhook: null, // Slack incoming webhook URL for findings summary
|
|
43
|
+
slack_channel: null, // override default channel for the Slack webhook
|
|
44
|
+
|
|
45
|
+
// Workflow integration
|
|
46
|
+
open_pr: false, // open a GitHub PR per finding instead of committing directly
|
|
47
|
+
github_token: null, // token for PR creation; falls back to GITHUB_TOKEN env var
|
|
48
|
+
github_repo: null, // 'owner/repo' for PR creation; auto-detected from git remote if null
|
|
49
|
+
|
|
50
|
+
// Scheduled / CI modes
|
|
51
|
+
schedule: null, // cron expression — used by external schedulers, not the CLI itself
|
|
52
|
+
pr_mode: false, // lightweight scan only (no agents, no RAG) — designed for CI PR gates
|
|
53
|
+
org_scan: null, // GitHub org name — scan all repos in the org
|
|
54
|
+
|
|
55
|
+
// Output additions
|
|
56
|
+
sbom: false, // generate a CycloneDX SBOM alongside the audit report
|
|
57
|
+
report: false, // generate a human-readable compliance report (PDF/markdown)
|
|
58
|
+
watch: false, // re-scan affected files on change (watch mode)
|
|
59
|
+
|
|
60
|
+
// Secret rotation — when a hardcoded key is found, offer to rotate via provider API
|
|
61
|
+
rotate_secrets: false, // prompt to rotate detected secrets via provider API
|
|
33
62
|
};
|
|
34
63
|
|
|
35
64
|
// Provider-specific defaults for `tdd-audit init --provider <name>`
|
|
@@ -129,7 +158,15 @@ function parseCliOverrides(args) {
|
|
|
129
158
|
const baseUrl = get('--base-url'); if (baseUrl) overrides.baseUrl = baseUrl;
|
|
130
159
|
const format = get('--format'); if (format) overrides.output = format;
|
|
131
160
|
const srvKey = get('--api-key'); if (srvKey) overrides.serverApiKey = srvKey;
|
|
132
|
-
|
|
161
|
+
const threshold = get('--threshold'); if (threshold) overrides.severityThreshold = threshold;
|
|
162
|
+
const org = get('--org'); if (org) overrides.org_scan = org;
|
|
163
|
+
if (args.includes('--json')) overrides.output = 'json';
|
|
164
|
+
if (args.includes('--pr')) overrides.pr_mode = true;
|
|
165
|
+
if (args.includes('--open-pr')) overrides.open_pr = true;
|
|
166
|
+
if (args.includes('--sbom')) overrides.sbom = true;
|
|
167
|
+
if (args.includes('--watch')) overrides.watch = true;
|
|
168
|
+
if (args.includes('--report')) overrides.report = true;
|
|
169
|
+
if (args.includes('--rotate-secrets')) overrides.rotate_secrets = true;
|
|
133
170
|
return overrides;
|
|
134
171
|
}
|
|
135
172
|
|
package/lib/github.js
CHANGED
package/lib/reporter.js
CHANGED
|
@@ -8,16 +8,17 @@ const { version } = require('../package.json');
|
|
|
8
8
|
* Return findings as a structured JSON-serialisable object.
|
|
9
9
|
* @param {Array} findings
|
|
10
10
|
* @param {string[]} [exempted=[]]
|
|
11
|
+
* @param {object} [config={}] - loaded config; security_officer stamped when set
|
|
11
12
|
* @returns {object}
|
|
12
13
|
*/
|
|
13
|
-
function toJson(findings, exempted = []) {
|
|
14
|
+
function toJson(findings, exempted = [], config = {}) {
|
|
14
15
|
const real = findings.filter(f => !f.likelyFalsePositive);
|
|
15
16
|
const noisy = findings.filter(f => f.likelyFalsePositive);
|
|
16
17
|
|
|
17
18
|
const summary = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };
|
|
18
19
|
for (const f of real) summary[f.severity] = (summary[f.severity] || 0) + 1;
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
const envelope = {
|
|
21
22
|
version,
|
|
22
23
|
summary,
|
|
23
24
|
findings: real,
|
|
@@ -25,6 +26,9 @@ function toJson(findings, exempted = []) {
|
|
|
25
26
|
exempted,
|
|
26
27
|
scannedAt: new Date().toISOString(),
|
|
27
28
|
};
|
|
29
|
+
if (config.security_name) envelope.security_name = config.security_name;
|
|
30
|
+
if (config.security_email) envelope.security_email = config.security_email;
|
|
31
|
+
return envelope;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
// ─── SARIF ────────────────────────────────────────────────────────────────────
|
|
@@ -62,6 +66,17 @@ const CWE_MAP = {
|
|
|
62
66
|
|
|
63
67
|
const NPM_URL = 'https://www.npmjs.com/package/@lhi/tdd-audit';
|
|
64
68
|
|
|
69
|
+
function safeSiteUrl(raw) {
|
|
70
|
+
if (!raw || !raw.trim()) return NPM_URL;
|
|
71
|
+
try {
|
|
72
|
+
const parsed = new URL(raw.trim());
|
|
73
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return NPM_URL;
|
|
74
|
+
return raw.trim();
|
|
75
|
+
} catch {
|
|
76
|
+
return NPM_URL;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
65
80
|
/**
|
|
66
81
|
* Return findings as a SARIF 2.1.0 object (GitHub code scanning compatible).
|
|
67
82
|
* @param {Array} findings
|
|
@@ -113,7 +128,7 @@ function toSarif(findings, projectDir = '', config = {}) {
|
|
|
113
128
|
driver: {
|
|
114
129
|
name: config.badge_label || '@lhi/tdd-audit',
|
|
115
130
|
version,
|
|
116
|
-
informationUri: (config.tdd_site
|
|
131
|
+
informationUri: safeSiteUrl(config.tdd_site),
|
|
117
132
|
rules,
|
|
118
133
|
},
|
|
119
134
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lhi/tdd-audit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.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
|
@@ -19,13 +19,124 @@ If the user passes `--scan` or `--scan-only`, requests "audit only", or asks for
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
+
## PR Mode (`--pr`)
|
|
23
|
+
|
|
24
|
+
Lightweight, fast path designed for CI PR gates. When invoked with `--pr`:
|
|
25
|
+
|
|
26
|
+
1. Run Phase 0 static scan only (no AI agents, no RAG queries, no code changes).
|
|
27
|
+
2. Filter findings against `severityThreshold` (default `HIGH`).
|
|
28
|
+
3. Apply any `severity_overrides` from `.tdd-audit.json` before filtering.
|
|
29
|
+
4. If any finding meets or exceeds the threshold: exit non-zero with a summary. Otherwise exit zero.
|
|
30
|
+
|
|
31
|
+
Output format in PR mode:
|
|
32
|
+
```
|
|
33
|
+
tdd-audit PR scan — my-project
|
|
34
|
+
✅ 0 CRITICAL · 0 HIGH (threshold: HIGH) — passed
|
|
35
|
+
```
|
|
36
|
+
or:
|
|
37
|
+
```
|
|
38
|
+
tdd-audit PR scan — my-project
|
|
39
|
+
❌ 1 CRITICAL · 2 HIGH (threshold: HIGH) — blocked
|
|
40
|
+
CRITICAL src/api/admin.js:14 Unguarded admin endpoint
|
|
41
|
+
HIGH src/lib/auth.js:88 JWT algorithm confusion
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Do not start MCP services, pull pattern repos, or run agents in this mode. Speed is the goal.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Org Scan Mode (`--org <github-org>`)
|
|
49
|
+
|
|
50
|
+
Scans all repos in a GitHub org. When invoked with `--org`:
|
|
51
|
+
|
|
52
|
+
1. List all repos in `<github-org>` via `gh repo list <github-org> --limit 200 --json name,sshUrl`.
|
|
53
|
+
2. For each repo: clone to a temp dir (or pull if already present), run `--pr` mode against it.
|
|
54
|
+
3. Collect results and produce a cross-org summary:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
<github-org> security posture — YYYY-MM-DD
|
|
58
|
+
|
|
59
|
+
✅ repo-a 0 critical · 0 high
|
|
60
|
+
⚠️ repo-b 0 critical · 2 high
|
|
61
|
+
🔴 repo-c 1 critical · 4 high
|
|
62
|
+
|
|
63
|
+
N repos scanned · X critical · Y high total
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
4. If `webhook_url` or `slack_webhook` is configured, fire the notification with the aggregate payload.
|
|
67
|
+
5. If `--format report` is also passed, write a full markdown cross-org report.
|
|
68
|
+
|
|
69
|
+
Requires `GITHUB_TOKEN` in the environment with `repo` read scope.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Auto-Fix PR Mode (`--open-pr`)
|
|
74
|
+
|
|
75
|
+
Instead of committing fixes directly to the working branch, open a GitHub PR per confirmed finding. Apply this mode during Phase 1–3 (Remediation Engine):
|
|
76
|
+
|
|
77
|
+
For each finding:
|
|
78
|
+
1. Create a branch: `tdd-audit/<finding-slug>-<YYYYMMDD>` off the default branch.
|
|
79
|
+
2. Apply the Red (exploit test) + Green (patch) commits on that branch.
|
|
80
|
+
3. Open a PR via `gh pr create`:
|
|
81
|
+
- Title: `[tdd-audit] Fix <vulnerability name>: <one-line description>`
|
|
82
|
+
- Body: finding description, exploit test name, patch summary, link to vulnerability pattern.
|
|
83
|
+
4. Do **not** merge — leave the PR for human review.
|
|
84
|
+
5. Print the PR URL after creation.
|
|
85
|
+
|
|
86
|
+
Requires `GITHUB_TOKEN` (env or `github_token` config) and `github_repo` (env or auto-detected from git remote).
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Watch Mode (`--watch`)
|
|
91
|
+
|
|
92
|
+
Re-scan affected files on save. When invoked with `--watch`:
|
|
93
|
+
|
|
94
|
+
1. Complete Phase 0 (full static scan) once at startup.
|
|
95
|
+
2. Start a file watcher on the repo root (excluding `node_modules`, `dist`, `.git`, and paths in `ignore`).
|
|
96
|
+
3. On any file save: re-run Phase 0 static scan for that file only.
|
|
97
|
+
4. Report new or resolved findings immediately in the terminal. Do not run agents or apply fixes.
|
|
98
|
+
5. Continue watching until the process is terminated.
|
|
99
|
+
|
|
100
|
+
Watch mode is for real-time feedback during development. Use `/caller-audit` (or the equivalent skill command) for full agentic remediation.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Notifications
|
|
105
|
+
|
|
106
|
+
After every completed scan (CLI, `--ai`, `POST /scan`):
|
|
107
|
+
|
|
108
|
+
**Webhook** (`webhook_url`): POST the following JSON:
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"project": "<project>",
|
|
112
|
+
"org": "<org>",
|
|
113
|
+
"security_name": "<security_name or omitted if not set>",
|
|
114
|
+
"security_email": "<security_email or omitted if not set>",
|
|
115
|
+
"timestamp": "<ISO 8601>",
|
|
116
|
+
"duration_ms": 4200,
|
|
117
|
+
"summary": { "critical": 1, "high": 3, "medium": 2, "low": 0 },
|
|
118
|
+
"findings": [ ... ]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Slack** (`slack_webhook`): Send a message to `slack_channel` (or the webhook default):
|
|
123
|
+
```
|
|
124
|
+
🔴 tdd-audit — <project>
|
|
125
|
+
1 critical · 3 high · 2 medium
|
|
126
|
+
Run /caller-audit to remediate.
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Send notifications only after Phase 0e (findings are final). Do not send during incremental watch-mode scans.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
22
133
|
## Config Bootstrap (runs before Phase 0 every time)
|
|
23
134
|
|
|
24
135
|
Before scanning, read `.tdd-audit.json` from the repo root if it exists. Store the values — they control branding, extensibility, and session setup for this run.
|
|
25
136
|
|
|
26
137
|
```
|
|
27
138
|
If .tdd-audit.json exists:
|
|
28
|
-
Load: org, project, tdd_site, badge_label,
|
|
139
|
+
Load: org, project, tdd_site, badge_label, security_name, security_email,
|
|
29
140
|
pattern_repos, extra_skill_dirs, extra_repos,
|
|
30
141
|
mcp_services, extra_domains
|
|
31
142
|
If absent:
|
|
@@ -588,6 +699,21 @@ Once coverage is ≥ 95%, add a coverage badge to `README.md`.
|
|
|
588
699
|
|
|
589
700
|
Adjust the percentage in the badge URL to match the real number (e.g., `97%25` for 97%).
|
|
590
701
|
|
|
702
|
+
**Badge label and link defaults:**
|
|
703
|
+
|
|
704
|
+
- If `badge_label` is set in config, use it as the label (e.g., `dc-audit`). Otherwise use `tdd-audit`.
|
|
705
|
+
- If `tdd_site` is set in config, link the badge to that URL. Otherwise link to the `@lhi/tdd-audit` npm page (`https://www.npmjs.com/package/@lhi/tdd-audit`).
|
|
706
|
+
|
|
707
|
+
```markdown
|
|
708
|
+
<!-- default (no config overrides) -->
|
|
709
|
+
[](https://www.npmjs.com/package/@lhi/tdd-audit)
|
|
710
|
+
|
|
711
|
+
<!-- with badge_label and tdd_site set -->
|
|
712
|
+
[](https://security.example.com)
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
The `<!-- tdd-audit-badge -->` HTML comment must follow the badge line so it can be located and updated on subsequent runs.
|
|
716
|
+
|
|
591
717
|
---
|
|
592
718
|
|
|
593
719
|
## Phase 6: SECURITY.md
|
|
@@ -613,7 +739,7 @@ Please **do not** open a public GitHub issue for security vulnerabilities.
|
|
|
613
739
|
|
|
614
740
|
Report vulnerabilities privately via:
|
|
615
741
|
- **GitHub**: Use [GitHub's private vulnerability reporting](../../security/advisories/new)
|
|
616
|
-
- **
|
|
742
|
+
- **Contact**: <if security_name and security_email both set: "Name <email>"; if only email: email; if only name: name; if neither: "security@example.com (replace with project contact)">
|
|
617
743
|
|
|
618
744
|
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.
|
|
619
745
|
|
|
@@ -633,6 +759,63 @@ Replace placeholder email and version table with the project's real information.
|
|
|
633
759
|
|
|
634
760
|
---
|
|
635
761
|
|
|
762
|
+
## Phase 6b: SBOM (`--sbom`)
|
|
763
|
+
|
|
764
|
+
If `sbom: true` in config or `--sbom` flag is passed, generate a [CycloneDX](https://cyclonedx.org/) Software Bill of Materials after the dependency audit:
|
|
765
|
+
|
|
766
|
+
```bash
|
|
767
|
+
# Node.js
|
|
768
|
+
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
|
|
769
|
+
|
|
770
|
+
# Python
|
|
771
|
+
cyclonedx-py --output sbom.json
|
|
772
|
+
|
|
773
|
+
# Go
|
|
774
|
+
cyclonedx-gomod app -output sbom.json
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
Write to `sbom.json` at the project root. Note the path in the Final Report.
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
## Phase 6c: Compliance Report (`--format report`)
|
|
782
|
+
|
|
783
|
+
If `report: true` in config or `--format report` flag is passed, generate a markdown compliance report at `audit-report.md`:
|
|
784
|
+
|
|
785
|
+
```markdown
|
|
786
|
+
# Security Audit Report — <project> — <YYYY-MM-DD>
|
|
787
|
+
|
|
788
|
+
**Org:** <org> **Auditor:** tdd-audit **Security Contact:** <security_name if set, security_email if set, or N/A> **Status:** Passed / Failed
|
|
789
|
+
|
|
790
|
+
## Findings Summary
|
|
791
|
+
| Severity | Count | Status |
|
|
792
|
+
|---|---|---|
|
|
793
|
+
| CRITICAL | 0 | ✅ Remediated |
|
|
794
|
+
| HIGH | 2 | ✅ Remediated |
|
|
795
|
+
| MEDIUM | 1 | ✅ Remediated |
|
|
796
|
+
| LOW | 0 | — |
|
|
797
|
+
|
|
798
|
+
## Fix Evidence
|
|
799
|
+
| Vulnerability | Exploit Test | Patch Commit | Suite |
|
|
800
|
+
|---|---|---|---|
|
|
801
|
+
| JWT algorithm confusion | auth-jwt-alg.test.js | abc1234 | ✅ |
|
|
802
|
+
|
|
803
|
+
## Coverage Gate
|
|
804
|
+
Line: 96.4% ✅ Branch: 95.1% ✅ Threshold: 95%
|
|
805
|
+
|
|
806
|
+
## Hardening Controls Applied
|
|
807
|
+
- Security headers (Helmet / CSP)
|
|
808
|
+
- Rate limiting on auth routes
|
|
809
|
+
- Dependency audit passed
|
|
810
|
+
|
|
811
|
+
## SBOM
|
|
812
|
+
sbom.json (CycloneDX 1.4) — generated <timestamp>
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
Suitable for attaching to SOC 2 audits, ISO 27001 evidence packages, and vendor security questionnaires.
|
|
816
|
+
|
|
817
|
+
---
|
|
818
|
+
|
|
636
819
|
## Final Report
|
|
637
820
|
|
|
638
821
|
After Phases 4–6 complete, append to the Remediation Summary:
|
|
@@ -642,10 +825,14 @@ After Phases 4–6 complete, append to the Remediation Summary:
|
|
|
642
825
|
|
|
643
826
|
| Item | Status | Detail |
|
|
644
827
|
|---|---|---|
|
|
645
|
-
| Line coverage
|
|
646
|
-
| Branch coverage
|
|
647
|
-
| README badge
|
|
648
|
-
| SECURITY.md
|
|
828
|
+
| Line coverage | ✅ | 96.4% |
|
|
829
|
+
| Branch coverage | ✅ | 95.1% |
|
|
830
|
+
| README badge | ✅ | Updated to 96% (brightgreen) |
|
|
831
|
+
| SECURITY.md | ✅ | Created at repo root |
|
|
832
|
+
| SBOM | ✅/⏭ | sbom.json (CycloneDX) generated — or N/A if --sbom not passed |
|
|
833
|
+
| Compliance report | ✅/⏭ | audit-report.md generated — or N/A if --format report not passed |
|
|
834
|
+
| Notifications fired | ✅/⏭ | webhook + Slack — or N/A if not configured |
|
|
835
|
+
| Patterns contributed| ✅/⏭ | N new patterns to <pattern_repo.name> — or "existing patterns verified" |
|
|
649
836
|
```
|
|
650
837
|
|
|
651
838
|
---
|