sentinelayer-cli 0.6.2 → 0.8.1
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 +1009 -996
- package/bin/create-sentinelayer.js +5 -5
- package/bin/sentinelayer-cli.js +4 -4
- package/bin/sl.js +5 -5
- package/package.json +64 -63
- package/src/agents/ai-governance/index.js +12 -0
- package/src/agents/ai-governance/tools/base.js +171 -0
- package/src/agents/ai-governance/tools/eval-regression.js +47 -0
- package/src/agents/ai-governance/tools/hitl-audit.js +81 -0
- package/src/agents/ai-governance/tools/index.js +52 -0
- package/src/agents/ai-governance/tools/prompt-drift.js +42 -0
- package/src/agents/ai-governance/tools/provenance-check.js +69 -0
- package/src/agents/backend/index.js +12 -0
- package/src/agents/backend/tools/base.js +189 -0
- package/src/agents/backend/tools/circuit-breaker-check.js +123 -0
- package/src/agents/backend/tools/idempotency-audit.js +105 -0
- package/src/agents/backend/tools/index.js +87 -0
- package/src/agents/backend/tools/retry-audit.js +132 -0
- package/src/agents/backend/tools/timeout-audit.js +144 -0
- package/src/agents/code-quality/index.js +12 -0
- package/src/agents/code-quality/tools/base.js +159 -0
- package/src/agents/code-quality/tools/complexity-measure.js +197 -0
- package/src/agents/code-quality/tools/coupling-analysis.js +81 -0
- package/src/agents/code-quality/tools/cycle-detect.js +49 -0
- package/src/agents/code-quality/tools/dep-graph.js +196 -0
- package/src/agents/code-quality/tools/index.js +89 -0
- package/src/agents/data-layer/index.js +12 -0
- package/src/agents/data-layer/tools/base.js +181 -0
- package/src/agents/data-layer/tools/index-audit.js +165 -0
- package/src/agents/data-layer/tools/index.js +83 -0
- package/src/agents/data-layer/tools/migration-scan.js +135 -0
- package/src/agents/data-layer/tools/query-explain.js +120 -0
- package/src/agents/data-layer/tools/tenancy-scan.js +166 -0
- package/src/agents/documentation/index.js +12 -0
- package/src/agents/documentation/tools/api-diff.js +91 -0
- package/src/agents/documentation/tools/base.js +151 -0
- package/src/agents/documentation/tools/dead-link-check.js +58 -0
- package/src/agents/documentation/tools/docstring-coverage.js +78 -0
- package/src/agents/documentation/tools/index.js +52 -0
- package/src/agents/documentation/tools/readme-freshness.js +61 -0
- package/src/agents/envelope/fix-cycle.js +45 -0
- package/src/agents/envelope/index.js +31 -0
- package/src/agents/envelope/loop.js +150 -0
- package/src/agents/envelope/pulse.js +18 -0
- package/src/agents/envelope/stream.js +40 -0
- package/src/agents/infrastructure/index.js +12 -0
- package/src/agents/infrastructure/tools/base.js +171 -0
- package/src/agents/infrastructure/tools/checkov-run.js +32 -0
- package/src/agents/infrastructure/tools/drift-detect.js +59 -0
- package/src/agents/infrastructure/tools/iam-least-priv-check.js +78 -0
- package/src/agents/infrastructure/tools/index.js +52 -0
- package/src/agents/infrastructure/tools/tflint-run.js +31 -0
- package/src/agents/jules/config/definition.js +160 -160
- package/src/agents/jules/config/system-prompt.js +182 -182
- package/src/agents/jules/error-intake.js +51 -51
- package/src/agents/jules/fix-cycle.js +17 -17
- package/src/agents/jules/loop.js +460 -450
- package/src/agents/jules/pulse.js +10 -10
- package/src/agents/jules/stream.js +187 -186
- package/src/agents/jules/swarm/file-scanner.js +74 -74
- package/src/agents/jules/swarm/index.js +11 -11
- package/src/agents/jules/swarm/orchestrator.js +362 -362
- package/src/agents/jules/swarm/pattern-hunter.js +123 -123
- package/src/agents/jules/swarm/sub-agent.js +315 -309
- package/src/agents/jules/tools/aidenid-email.js +189 -189
- package/src/agents/jules/tools/auth-audit.js +1708 -1691
- package/src/agents/jules/tools/dispatch.js +340 -335
- package/src/agents/jules/tools/file-edit.js +2 -2
- package/src/agents/jules/tools/file-read.js +2 -2
- package/src/agents/jules/tools/frontend-analyze.js +570 -570
- package/src/agents/jules/tools/glob.js +2 -2
- package/src/agents/jules/tools/grep.js +2 -2
- package/src/agents/jules/tools/index.js +29 -29
- package/src/agents/jules/tools/path-guards.js +2 -2
- package/src/agents/jules/tools/runtime-audit.js +507 -507
- package/src/agents/jules/tools/shell.js +2 -2
- package/src/agents/jules/tools/url-policy.js +100 -100
- package/src/agents/mode.js +113 -0
- package/src/agents/observability/index.js +12 -0
- package/src/agents/observability/tools/alert-audit.js +39 -0
- package/src/agents/observability/tools/base.js +181 -0
- package/src/agents/observability/tools/dashboard-gap.js +42 -0
- package/src/agents/observability/tools/index.js +54 -0
- package/src/agents/observability/tools/log-schema-check.js +74 -0
- package/src/agents/observability/tools/span-coverage.js +74 -0
- package/src/agents/persona-visuals.js +102 -61
- package/src/agents/release/index.js +12 -0
- package/src/agents/release/tools/base.js +181 -0
- package/src/agents/release/tools/changelog-diff.js +86 -0
- package/src/agents/release/tools/feature-flag-audit.js +126 -0
- package/src/agents/release/tools/index.js +61 -0
- package/src/agents/release/tools/rollback-verify.js +129 -0
- package/src/agents/release/tools/semver-check.js +109 -0
- package/src/agents/reliability/index.js +12 -0
- package/src/agents/reliability/tools/backpressure-check.js +129 -0
- package/src/agents/reliability/tools/base.js +181 -0
- package/src/agents/reliability/tools/chaos-probe.js +109 -0
- package/src/agents/reliability/tools/graceful-degradation-check.js +114 -0
- package/src/agents/reliability/tools/health-check-audit.js +111 -0
- package/src/agents/reliability/tools/index.js +87 -0
- package/src/agents/run-persona.js +109 -0
- package/src/agents/security/index.js +12 -0
- package/src/agents/security/tools/authz-audit.js +134 -0
- package/src/agents/security/tools/base.js +190 -0
- package/src/agents/security/tools/crypto-review.js +175 -0
- package/src/agents/security/tools/index.js +97 -0
- package/src/agents/security/tools/sast-scan.js +175 -0
- package/src/agents/security/tools/secrets-scan.js +216 -0
- package/src/agents/shared-tools/dispatch-core.js +320 -315
- package/src/agents/shared-tools/file-edit.js +180 -180
- package/src/agents/shared-tools/file-read.js +100 -100
- package/src/agents/shared-tools/glob.js +168 -168
- package/src/agents/shared-tools/grep.js +228 -228
- package/src/agents/shared-tools/index.js +46 -46
- package/src/agents/shared-tools/path-guards.js +161 -161
- package/src/agents/shared-tools/shell.js +383 -383
- package/src/agents/supply-chain/index.js +12 -0
- package/src/agents/supply-chain/tools/attestation-check.js +42 -0
- package/src/agents/supply-chain/tools/base.js +151 -0
- package/src/agents/supply-chain/tools/index.js +52 -0
- package/src/agents/supply-chain/tools/lockfile-integrity.js +73 -0
- package/src/agents/supply-chain/tools/package-verify.js +56 -0
- package/src/agents/supply-chain/tools/sbom-diff.js +34 -0
- package/src/agents/testing/index.js +12 -0
- package/src/agents/testing/tools/base.js +202 -0
- package/src/agents/testing/tools/coverage-gap.js +144 -0
- package/src/agents/testing/tools/flake-detect.js +125 -0
- package/src/agents/testing/tools/index.js +85 -0
- package/src/agents/testing/tools/mutation-test.js +143 -0
- package/src/agents/testing/tools/snapshot-diff.js +103 -0
- package/src/ai/aidenid.js +1021 -1009
- package/src/ai/client.js +553 -553
- package/src/ai/domain-target-store.js +268 -268
- package/src/ai/identity-store.js +270 -270
- package/src/ai/proxy.js +137 -137
- package/src/ai/site-store.js +145 -145
- package/src/audit/agents/architecture.js +180 -180
- package/src/audit/agents/compliance.js +179 -179
- package/src/audit/agents/documentation.js +165 -165
- package/src/audit/agents/performance.js +145 -145
- package/src/audit/agents/security.js +215 -215
- package/src/audit/agents/testing.js +172 -172
- package/src/audit/orchestrator.js +557 -557
- package/src/audit/package.js +204 -204
- package/src/audit/registry.js +284 -284
- package/src/audit/replay.js +103 -103
- package/src/auth/gate.js +428 -371
- package/src/auth/http.js +681 -611
- package/src/auth/service.js +1106 -1106
- package/src/auth/session-store.js +813 -813
- package/src/cli.js +257 -252
- package/src/commands/ai/identity-lifecycle.js +1338 -1338
- package/src/commands/ai/provision-governance.js +1272 -1272
- package/src/commands/ai/shared.js +147 -147
- package/src/commands/ai.js +11 -11
- package/src/commands/apply.js +12 -12
- package/src/commands/audit.js +1171 -1166
- package/src/commands/auth.js +419 -419
- package/src/commands/chat.js +184 -191
- package/src/commands/config.js +184 -184
- package/src/commands/cost.js +311 -311
- package/src/commands/daemon/core.js +850 -850
- package/src/commands/daemon/extended.js +1048 -1048
- package/src/commands/daemon/shared.js +213 -213
- package/src/commands/daemon.js +11 -11
- package/src/commands/guide.js +174 -174
- package/src/commands/ingest.js +58 -58
- package/src/commands/init.js +55 -55
- package/src/commands/legacy-args.js +20 -10
- package/src/commands/mcp.js +461 -461
- package/src/commands/omargate.js +63 -29
- package/src/commands/persona.js +65 -20
- package/src/commands/plugin.js +260 -260
- package/src/commands/policy.js +132 -132
- package/src/commands/prompt.js +238 -238
- package/src/commands/review.js +704 -704
- package/src/commands/scan.js +865 -872
- package/src/commands/session.js +1238 -0
- package/src/commands/spec.js +771 -716
- package/src/commands/swarm.js +651 -651
- package/src/commands/telemetry.js +202 -202
- package/src/commands/watch.js +511 -511
- package/src/config/agent-dictionary.js +182 -182
- package/src/config/io.js +56 -56
- package/src/config/paths.js +18 -18
- package/src/config/schema.js +55 -55
- package/src/config/service.js +184 -184
- package/src/coord/events-log.js +141 -0
- package/src/coord/handshake.js +719 -0
- package/src/coord/index.js +35 -0
- package/src/coord/paths.js +84 -0
- package/src/coord/priority.js +62 -0
- package/src/coord/tarjan.js +157 -0
- package/src/cost/budget.js +235 -235
- package/src/cost/history.js +188 -188
- package/src/cost/tokenizer.js +160 -0
- package/src/cost/tracker.js +232 -171
- package/src/daemon/artifact-lineage.js +896 -534
- package/src/daemon/assignment-ledger.js +1083 -770
- package/src/daemon/ast-drift.js +496 -0
- package/src/daemon/ast-parser-layer.js +258 -258
- package/src/daemon/budget-governor.js +633 -633
- package/src/daemon/callgraph-overlay.js +646 -646
- package/src/daemon/error-worker.js +1209 -626
- package/src/daemon/fix-cycle.js +384 -377
- package/src/daemon/hybrid-mapper.js +929 -929
- package/src/daemon/ingest-refresh.js +79 -11
- package/src/daemon/jira-lifecycle.js +767 -632
- package/src/daemon/operator-control.js +657 -657
- package/src/daemon/pulse.js +327 -327
- package/src/daemon/reliability-lane.js +471 -471
- package/src/daemon/scope-engine.js +1068 -0
- package/src/daemon/watchdog.js +971 -971
- package/src/events/schema.js +190 -0
- package/src/guide/generator.js +316 -316
- package/src/ingest/engine.js +933 -918
- package/src/ingest/ownership.js +380 -0
- package/src/interactive/index.js +97 -97
- package/src/legacy-cli.js +3228 -2994
- package/src/mcp/registry.js +695 -695
- package/src/memory/blackboard.js +301 -301
- package/src/memory/retrieval.js +581 -581
- package/src/orchestrator/kai-chen.js +126 -0
- package/src/plugin/manifest.js +553 -553
- package/src/policy/packs.js +144 -144
- package/src/prompt/generator.js +136 -118
- package/src/review/ai-review.js +672 -679
- package/src/review/compliance-pack.js +389 -0
- package/src/review/investor-dd-config.js +54 -0
- package/src/review/investor-dd-file-loop.js +303 -0
- package/src/review/investor-dd-file-router.js +406 -0
- package/src/review/investor-dd-html-report.js +233 -0
- package/src/review/investor-dd-notification.js +120 -0
- package/src/review/investor-dd-orchestrator.js +405 -0
- package/src/review/investor-dd-persona-runner.js +275 -0
- package/src/review/live-validator.js +253 -0
- package/src/review/local-review.js +1351 -1305
- package/src/review/omargate-interactive.js +68 -68
- package/src/review/omargate-orchestrator.js +492 -300
- package/src/review/persona-prompts.js +484 -296
- package/src/review/reconciliation-rules.js +329 -0
- package/src/review/replay.js +235 -235
- package/src/review/report.js +664 -664
- package/src/review/reproducibility-chain.js +136 -0
- package/src/review/scan-modes.js +147 -42
- package/src/review/spec-binding.js +487 -487
- package/src/scaffold/generator.js +67 -67
- package/src/scaffold/templates.js +150 -150
- package/src/scan/generator.js +418 -418
- package/src/scan/gh-secrets.js +107 -107
- package/src/session/agent-registry.js +359 -0
- package/src/session/analytics.js +479 -0
- package/src/session/daemon.js +1396 -0
- package/src/session/file-locks.js +666 -0
- package/src/session/paths.js +37 -0
- package/src/session/recap.js +567 -0
- package/src/session/redact.js +82 -0
- package/src/session/runtime-bridge.js +762 -0
- package/src/session/scoring.js +406 -0
- package/src/session/setup-guides.js +304 -0
- package/src/session/store.js +704 -0
- package/src/session/stream.js +333 -0
- package/src/session/sync.js +753 -0
- package/src/session/tasks.js +1054 -0
- package/src/session/templates.js +188 -0
- package/src/spec/generator.js +619 -519
- package/src/spec/regenerate.js +237 -237
- package/src/spec/templates.js +91 -91
- package/src/swarm/dashboard.js +247 -247
- package/src/swarm/factory.js +363 -363
- package/src/swarm/pentest.js +934 -934
- package/src/swarm/registry.js +419 -419
- package/src/swarm/report.js +158 -158
- package/src/swarm/runtime.js +569 -576
- package/src/swarm/scenario-dsl.js +272 -272
- package/src/telemetry/ledger.js +302 -302
- package/src/telemetry/session-tracker.js +234 -234
- package/src/telemetry/sync.js +203 -203
- package/src/ui/command-hints.js +13 -13
- package/src/ui/markdown.js +220 -220
|
@@ -1,179 +1,179 @@
|
|
|
1
|
-
function normalizeString(value) {
|
|
2
|
-
return String(value || "").trim();
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
function toPosixPath(value) {
|
|
6
|
-
return String(value || "").replace(/\\/g, "/");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function summarizeSeverity(findings = []) {
|
|
10
|
-
const summary = { P0: 0, P1: 0, P2: 0, P3: 0 };
|
|
11
|
-
for (const finding of findings) {
|
|
12
|
-
const severity = normalizeString(finding.severity).toUpperCase();
|
|
13
|
-
if (Object.prototype.hasOwnProperty.call(summary, severity)) {
|
|
14
|
-
summary[severity] += 1;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
summary.blocking = summary.P0 > 0 || summary.P1 > 0;
|
|
18
|
-
return summary;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function classifyControl(finding = {}) {
|
|
22
|
-
const haystack = `${normalizeString(finding.message)} ${normalizeString(finding.ruleId)} ${normalizeString(
|
|
23
|
-
finding.file
|
|
24
|
-
)}`.toLowerCase();
|
|
25
|
-
if (/secret|token|credential|key|jwt/.test(haystack)) {
|
|
26
|
-
return { framework: "SOC2-CC6", control: "Secrets Management", severity: "P1" };
|
|
27
|
-
}
|
|
28
|
-
if (/auth|session|revoke|ttl|role|permission/.test(haystack)) {
|
|
29
|
-
return { framework: "SOC2-CC6", control: "Access Controls", severity: "P2" };
|
|
30
|
-
}
|
|
31
|
-
if (/telemetry|log|trace|audit/.test(haystack)) {
|
|
32
|
-
return { framework: "SOC2-CC7", control: "Auditability", severity: "P2" };
|
|
33
|
-
}
|
|
34
|
-
if (/data|pii|encryption|tls|privacy|retention/.test(haystack)) {
|
|
35
|
-
return { framework: "SOC2-CC8", control: "Data Protection", severity: "P1" };
|
|
36
|
-
}
|
|
37
|
-
if (/workflow|deploy|release|supply|dependency/.test(haystack)) {
|
|
38
|
-
return { framework: "SOC2-CC9", control: "Change Management", severity: "P2" };
|
|
39
|
-
}
|
|
40
|
-
return { framework: "SOC2-CC3", control: "Governance", severity: "P3" };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function buildComplianceFindings({ findings = [], ingest = {} } = {}) {
|
|
44
|
-
const derived = [];
|
|
45
|
-
const scoped = Array.isArray(findings) ? findings : [];
|
|
46
|
-
for (const finding of scoped) {
|
|
47
|
-
const control = classifyControl(finding);
|
|
48
|
-
if (control.severity === "P3" && normalizeString(finding.severity).toUpperCase() === "P3") {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
derived.push({
|
|
52
|
-
...finding,
|
|
53
|
-
severity: normalizeString(finding.severity) ? finding.severity : control.severity,
|
|
54
|
-
complianceFramework: control.framework,
|
|
55
|
-
complianceControl: control.control,
|
|
56
|
-
layer: "compliance",
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const riskSurfaces = Array.isArray(ingest.riskSurfaces) ? ingest.riskSurfaces : [];
|
|
61
|
-
for (const surface of riskSurfaces.slice(0, 20)) {
|
|
62
|
-
const normalizedSurface = normalizeString(surface.surface);
|
|
63
|
-
if (!normalizedSurface) {
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
const representativePath = toPosixPath(surface.filePath || surface.path || ".");
|
|
67
|
-
const exists = derived.some((finding) => toPosixPath(finding.file) === representativePath);
|
|
68
|
-
if (exists) {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
const control =
|
|
72
|
-
normalizedSurface === "secrets"
|
|
73
|
-
? { framework: "SOC2-CC6", control: "Secrets Management", severity: "P1" }
|
|
74
|
-
: { framework: "SOC2-CC7", control: "Auditability", severity: "P2" };
|
|
75
|
-
derived.push({
|
|
76
|
-
severity: control.severity,
|
|
77
|
-
file: representativePath,
|
|
78
|
-
line: 1,
|
|
79
|
-
message: `Compliance risk surface detected for ${normalizedSurface}.`,
|
|
80
|
-
excerpt: `${normalizedSurface} surface observed in ingest`,
|
|
81
|
-
ruleId: "SL-COMP-001",
|
|
82
|
-
suggestedFix: "Document control ownership and enforce deterministic remediation evidence.",
|
|
83
|
-
complianceFramework: control.framework,
|
|
84
|
-
complianceControl: control.control,
|
|
85
|
-
layer: "compliance",
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return derived.slice(0, 120);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function summarizeControls(findings = []) {
|
|
93
|
-
const controlMap = new Map();
|
|
94
|
-
for (const finding of findings) {
|
|
95
|
-
const framework = normalizeString(finding.complianceFramework || "SOC2-CC3");
|
|
96
|
-
const control = normalizeString(finding.complianceControl || "Governance");
|
|
97
|
-
const key = `${framework}::${control}`;
|
|
98
|
-
const existing = controlMap.get(key) || { framework, control, count: 0 };
|
|
99
|
-
existing.count += 1;
|
|
100
|
-
controlMap.set(key, existing);
|
|
101
|
-
}
|
|
102
|
-
return [...controlMap.values()].sort((left, right) => right.count - left.count);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function estimateComplianceScore(summary = {}, controlSummary = []) {
|
|
106
|
-
const penalty =
|
|
107
|
-
Number(summary.P1 || 0) * 8 +
|
|
108
|
-
Number(summary.P2 || 0) * 4 +
|
|
109
|
-
Number(summary.P3 || 0) +
|
|
110
|
-
controlSummary.length;
|
|
111
|
-
return Math.max(0, 100 - Math.min(100, penalty));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function buildRecommendations(summary = {}, controlSummary = []) {
|
|
115
|
-
const recommendations = [];
|
|
116
|
-
if (Number(summary.P1 || 0) > 0) {
|
|
117
|
-
recommendations.push("Close P1 compliance findings before release and attach evidence in run artifacts.");
|
|
118
|
-
}
|
|
119
|
-
if (controlSummary.some((item) => item.framework === "SOC2-CC6")) {
|
|
120
|
-
recommendations.push("Strengthen credential/access controls and verify rotation/revocation procedures.");
|
|
121
|
-
}
|
|
122
|
-
if (controlSummary.some((item) => item.framework === "SOC2-CC7")) {
|
|
123
|
-
recommendations.push("Improve audit telemetry coverage for remediation and production change traces.");
|
|
124
|
-
}
|
|
125
|
-
if (recommendations.length === 0) {
|
|
126
|
-
recommendations.push("Compliance posture is stable; keep continuous evidence capture in each audit run.");
|
|
127
|
-
}
|
|
128
|
-
return recommendations;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export function runComplianceSpecialist({ findings = [], ingest = {} } = {}) {
|
|
132
|
-
const complianceFindings = buildComplianceFindings({
|
|
133
|
-
findings,
|
|
134
|
-
ingest,
|
|
135
|
-
});
|
|
136
|
-
const summary = summarizeSeverity(complianceFindings);
|
|
137
|
-
const controlSummary = summarizeControls(complianceFindings);
|
|
138
|
-
const complianceScore = estimateComplianceScore(summary, controlSummary);
|
|
139
|
-
const confidence = complianceFindings.length > 0 ? Math.max(0.76, 1 - complianceFindings.length * 0.002) : 0.9;
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
schemaVersion: "1.0.0",
|
|
143
|
-
generatedAt: new Date().toISOString(),
|
|
144
|
-
summary: {
|
|
145
|
-
...summary,
|
|
146
|
-
findingCount: complianceFindings.length,
|
|
147
|
-
complianceScore,
|
|
148
|
-
},
|
|
149
|
-
confidence,
|
|
150
|
-
controlSummary,
|
|
151
|
-
recommendations: buildRecommendations(summary, controlSummary),
|
|
152
|
-
findings: complianceFindings,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export function renderComplianceSpecialistMarkdown(report = {}) {
|
|
157
|
-
const controls = (report.controlSummary || [])
|
|
158
|
-
.map((item) => `- ${item.framework} :: ${item.control} (${item.count} findings)`)
|
|
159
|
-
.join("\n");
|
|
160
|
-
const recommendations = (report.recommendations || []).map((item) => `- ${item}`).join("\n");
|
|
161
|
-
|
|
162
|
-
return `# COMPLIANCE_AGENT_REPORT
|
|
163
|
-
|
|
164
|
-
Generated: ${report.generatedAt}
|
|
165
|
-
Compliance score: ${report.summary?.complianceScore ?? 0}/100
|
|
166
|
-
Confidence: ${((report.confidence || 0) * 100).toFixed(0)}%
|
|
167
|
-
|
|
168
|
-
Summary:
|
|
169
|
-
- Findings: P0=${report.summary?.P0 ?? 0} P1=${report.summary?.P1 ?? 0} P2=${report.summary?.P2 ?? 0} P3=${report.summary?.P3 ?? 0}
|
|
170
|
-
- Blocking: ${report.summary?.blocking ? "yes" : "no"}
|
|
171
|
-
- Total findings: ${report.summary?.findingCount ?? 0}
|
|
172
|
-
|
|
173
|
-
Control mapping:
|
|
174
|
-
${controls || "- none"}
|
|
175
|
-
|
|
176
|
-
Recommendations:
|
|
177
|
-
${recommendations || "- none"}
|
|
178
|
-
`;
|
|
179
|
-
}
|
|
1
|
+
function normalizeString(value) {
|
|
2
|
+
return String(value || "").trim();
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function toPosixPath(value) {
|
|
6
|
+
return String(value || "").replace(/\\/g, "/");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function summarizeSeverity(findings = []) {
|
|
10
|
+
const summary = { P0: 0, P1: 0, P2: 0, P3: 0 };
|
|
11
|
+
for (const finding of findings) {
|
|
12
|
+
const severity = normalizeString(finding.severity).toUpperCase();
|
|
13
|
+
if (Object.prototype.hasOwnProperty.call(summary, severity)) {
|
|
14
|
+
summary[severity] += 1;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
summary.blocking = summary.P0 > 0 || summary.P1 > 0;
|
|
18
|
+
return summary;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function classifyControl(finding = {}) {
|
|
22
|
+
const haystack = `${normalizeString(finding.message)} ${normalizeString(finding.ruleId)} ${normalizeString(
|
|
23
|
+
finding.file
|
|
24
|
+
)}`.toLowerCase();
|
|
25
|
+
if (/secret|token|credential|key|jwt/.test(haystack)) {
|
|
26
|
+
return { framework: "SOC2-CC6", control: "Secrets Management", severity: "P1" };
|
|
27
|
+
}
|
|
28
|
+
if (/auth|session|revoke|ttl|role|permission/.test(haystack)) {
|
|
29
|
+
return { framework: "SOC2-CC6", control: "Access Controls", severity: "P2" };
|
|
30
|
+
}
|
|
31
|
+
if (/telemetry|log|trace|audit/.test(haystack)) {
|
|
32
|
+
return { framework: "SOC2-CC7", control: "Auditability", severity: "P2" };
|
|
33
|
+
}
|
|
34
|
+
if (/data|pii|encryption|tls|privacy|retention/.test(haystack)) {
|
|
35
|
+
return { framework: "SOC2-CC8", control: "Data Protection", severity: "P1" };
|
|
36
|
+
}
|
|
37
|
+
if (/workflow|deploy|release|supply|dependency/.test(haystack)) {
|
|
38
|
+
return { framework: "SOC2-CC9", control: "Change Management", severity: "P2" };
|
|
39
|
+
}
|
|
40
|
+
return { framework: "SOC2-CC3", control: "Governance", severity: "P3" };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function buildComplianceFindings({ findings = [], ingest = {} } = {}) {
|
|
44
|
+
const derived = [];
|
|
45
|
+
const scoped = Array.isArray(findings) ? findings : [];
|
|
46
|
+
for (const finding of scoped) {
|
|
47
|
+
const control = classifyControl(finding);
|
|
48
|
+
if (control.severity === "P3" && normalizeString(finding.severity).toUpperCase() === "P3") {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
derived.push({
|
|
52
|
+
...finding,
|
|
53
|
+
severity: normalizeString(finding.severity) ? finding.severity : control.severity,
|
|
54
|
+
complianceFramework: control.framework,
|
|
55
|
+
complianceControl: control.control,
|
|
56
|
+
layer: "compliance",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const riskSurfaces = Array.isArray(ingest.riskSurfaces) ? ingest.riskSurfaces : [];
|
|
61
|
+
for (const surface of riskSurfaces.slice(0, 20)) {
|
|
62
|
+
const normalizedSurface = normalizeString(surface.surface);
|
|
63
|
+
if (!normalizedSurface) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const representativePath = toPosixPath(surface.filePath || surface.path || ".");
|
|
67
|
+
const exists = derived.some((finding) => toPosixPath(finding.file) === representativePath);
|
|
68
|
+
if (exists) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const control =
|
|
72
|
+
normalizedSurface === "secrets"
|
|
73
|
+
? { framework: "SOC2-CC6", control: "Secrets Management", severity: "P1" }
|
|
74
|
+
: { framework: "SOC2-CC7", control: "Auditability", severity: "P2" };
|
|
75
|
+
derived.push({
|
|
76
|
+
severity: control.severity,
|
|
77
|
+
file: representativePath,
|
|
78
|
+
line: 1,
|
|
79
|
+
message: `Compliance risk surface detected for ${normalizedSurface}.`,
|
|
80
|
+
excerpt: `${normalizedSurface} surface observed in ingest`,
|
|
81
|
+
ruleId: "SL-COMP-001",
|
|
82
|
+
suggestedFix: "Document control ownership and enforce deterministic remediation evidence.",
|
|
83
|
+
complianceFramework: control.framework,
|
|
84
|
+
complianceControl: control.control,
|
|
85
|
+
layer: "compliance",
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return derived.slice(0, 120);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function summarizeControls(findings = []) {
|
|
93
|
+
const controlMap = new Map();
|
|
94
|
+
for (const finding of findings) {
|
|
95
|
+
const framework = normalizeString(finding.complianceFramework || "SOC2-CC3");
|
|
96
|
+
const control = normalizeString(finding.complianceControl || "Governance");
|
|
97
|
+
const key = `${framework}::${control}`;
|
|
98
|
+
const existing = controlMap.get(key) || { framework, control, count: 0 };
|
|
99
|
+
existing.count += 1;
|
|
100
|
+
controlMap.set(key, existing);
|
|
101
|
+
}
|
|
102
|
+
return [...controlMap.values()].sort((left, right) => right.count - left.count);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function estimateComplianceScore(summary = {}, controlSummary = []) {
|
|
106
|
+
const penalty =
|
|
107
|
+
Number(summary.P1 || 0) * 8 +
|
|
108
|
+
Number(summary.P2 || 0) * 4 +
|
|
109
|
+
Number(summary.P3 || 0) +
|
|
110
|
+
controlSummary.length;
|
|
111
|
+
return Math.max(0, 100 - Math.min(100, penalty));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function buildRecommendations(summary = {}, controlSummary = []) {
|
|
115
|
+
const recommendations = [];
|
|
116
|
+
if (Number(summary.P1 || 0) > 0) {
|
|
117
|
+
recommendations.push("Close P1 compliance findings before release and attach evidence in run artifacts.");
|
|
118
|
+
}
|
|
119
|
+
if (controlSummary.some((item) => item.framework === "SOC2-CC6")) {
|
|
120
|
+
recommendations.push("Strengthen credential/access controls and verify rotation/revocation procedures.");
|
|
121
|
+
}
|
|
122
|
+
if (controlSummary.some((item) => item.framework === "SOC2-CC7")) {
|
|
123
|
+
recommendations.push("Improve audit telemetry coverage for remediation and production change traces.");
|
|
124
|
+
}
|
|
125
|
+
if (recommendations.length === 0) {
|
|
126
|
+
recommendations.push("Compliance posture is stable; keep continuous evidence capture in each audit run.");
|
|
127
|
+
}
|
|
128
|
+
return recommendations;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function runComplianceSpecialist({ findings = [], ingest = {} } = {}) {
|
|
132
|
+
const complianceFindings = buildComplianceFindings({
|
|
133
|
+
findings,
|
|
134
|
+
ingest,
|
|
135
|
+
});
|
|
136
|
+
const summary = summarizeSeverity(complianceFindings);
|
|
137
|
+
const controlSummary = summarizeControls(complianceFindings);
|
|
138
|
+
const complianceScore = estimateComplianceScore(summary, controlSummary);
|
|
139
|
+
const confidence = complianceFindings.length > 0 ? Math.max(0.76, 1 - complianceFindings.length * 0.002) : 0.9;
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
schemaVersion: "1.0.0",
|
|
143
|
+
generatedAt: new Date().toISOString(),
|
|
144
|
+
summary: {
|
|
145
|
+
...summary,
|
|
146
|
+
findingCount: complianceFindings.length,
|
|
147
|
+
complianceScore,
|
|
148
|
+
},
|
|
149
|
+
confidence,
|
|
150
|
+
controlSummary,
|
|
151
|
+
recommendations: buildRecommendations(summary, controlSummary),
|
|
152
|
+
findings: complianceFindings,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function renderComplianceSpecialistMarkdown(report = {}) {
|
|
157
|
+
const controls = (report.controlSummary || [])
|
|
158
|
+
.map((item) => `- ${item.framework} :: ${item.control} (${item.count} findings)`)
|
|
159
|
+
.join("\n");
|
|
160
|
+
const recommendations = (report.recommendations || []).map((item) => `- ${item}`).join("\n");
|
|
161
|
+
|
|
162
|
+
return `# COMPLIANCE_AGENT_REPORT
|
|
163
|
+
|
|
164
|
+
Generated: ${report.generatedAt}
|
|
165
|
+
Compliance score: ${report.summary?.complianceScore ?? 0}/100
|
|
166
|
+
Confidence: ${((report.confidence || 0) * 100).toFixed(0)}%
|
|
167
|
+
|
|
168
|
+
Summary:
|
|
169
|
+
- Findings: P0=${report.summary?.P0 ?? 0} P1=${report.summary?.P1 ?? 0} P2=${report.summary?.P2 ?? 0} P3=${report.summary?.P3 ?? 0}
|
|
170
|
+
- Blocking: ${report.summary?.blocking ? "yes" : "no"}
|
|
171
|
+
- Total findings: ${report.summary?.findingCount ?? 0}
|
|
172
|
+
|
|
173
|
+
Control mapping:
|
|
174
|
+
${controls || "- none"}
|
|
175
|
+
|
|
176
|
+
Recommendations:
|
|
177
|
+
${recommendations || "- none"}
|
|
178
|
+
`;
|
|
179
|
+
}
|