@clear-capabilities/agentic-security-scanner 0.145.0 → 0.147.5
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 +266 -0
- package/bin/agentic-security.js +3508 -69
- package/dist/1122.index.js +779 -0
- package/dist/{301.index.js → 1301.index.js} +2 -2
- package/dist/1379.index.js +591 -0
- package/dist/{444.index.js → 1444.index.js} +2 -2
- package/dist/{660.index.js → 1660.index.js} +2 -2
- package/dist/{700.index.js → 1700.index.js} +2 -2
- package/dist/{905.index.js → 1905.index.js} +3 -3
- package/dist/{920.index.js → 1920.index.js} +3 -3
- package/dist/{238.index.js → 2238.index.js} +3 -3
- package/dist/{271.index.js → 2271.index.js} +2 -2
- package/dist/{985.index.js → 2376.index.js} +1260 -340
- package/dist/2432.index.js +793 -0
- package/dist/2659.index.js +93 -0
- package/dist/{826.index.js → 2826.index.js} +2 -2
- package/dist/{830.index.js → 2830.index.js} +2 -2
- package/dist/2923.index.js +298 -0
- package/dist/{1.index.js → 3001.index.js} +5 -5
- package/dist/{117.index.js → 3117.index.js} +3 -3
- package/dist/3180.index.js +379 -0
- package/dist/3276.index.js +117 -0
- package/dist/{415.index.js → 3415.index.js} +2 -2
- package/dist/{499.index.js → 3499.index.js} +2 -2
- package/dist/3518.index.js +450 -0
- package/dist/{526.index.js → 3526.index.js} +5 -5
- package/dist/{736.index.js → 3736.index.js} +4 -4
- package/dist/{839.index.js → 3839.index.js} +4 -4
- package/dist/{113.index.js → 4113.index.js} +5 -5
- package/dist/{265.index.js → 4265.index.js} +2 -2
- package/dist/{384.index.js → 4384.index.js} +3 -3
- package/dist/4547.index.js +268 -0
- package/dist/4863.index.js +422 -0
- package/dist/{970.index.js → 4970.index.js} +2 -2
- package/dist/5051.index.js +841 -0
- package/dist/{144.index.js → 5144.index.js} +5 -5
- package/dist/{333.index.js → 5333.index.js} +3 -3
- package/dist/5343.index.js +185 -0
- package/dist/5350.index.js +866 -0
- package/dist/5561.index.js +436 -0
- package/dist/{637.index.js → 5637.index.js} +3 -3
- package/dist/{449.index.js → 5830.index.js} +2 -2
- package/dist/6626.index.js +532 -0
- package/dist/6662.index.js +297 -0
- package/dist/{675.index.js → 6675.index.js} +5 -5
- package/dist/{730.index.js → 6730.index.js} +6 -6
- package/dist/6829.index.js +225 -0
- package/dist/6944.index.js +130 -0
- package/dist/{178.index.js → 7178.index.js} +3 -3
- package/dist/{227.index.js → 7227.index.js} +2 -2
- package/dist/7310.index.js +520 -0
- package/dist/{552.index.js → 7552.index.js} +4 -4
- package/dist/7709.index.js +78 -0
- package/dist/8218.index.js +160 -0
- package/dist/{476.index.js → 8476.index.js} +4 -4
- package/dist/{513.index.js → 8513.index.js} +5 -5
- package/dist/{520.index.js → 8520.index.js} +2 -2
- package/dist/{718.index.js → 8718.index.js} +2 -2
- package/dist/{752.index.js → 8752.index.js} +2 -2
- package/dist/8846.index.js +100 -0
- package/dist/{435.index.js → 9091.index.js} +560 -189
- package/dist/{207.index.js → 9207.index.js} +2 -2
- package/dist/{220.index.js → 9220.index.js} +2 -2
- package/dist/9390.index.js +163 -0
- package/dist/{503.index.js → 9503.index.js} +2 -2
- package/dist/{801.index.js → 9801.index.js} +2 -2
- package/dist/{824.index.js → 9824.index.js} +2 -2
- package/dist/agentic-security.mjs +16 -16
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/dist/compliance-frameworks/hipaa-security-rule.json +3 -2
- package/dist/frontend/index.html +21 -0
- package/dist/frontend/src/app.js +176 -0
- package/dist/frontend/src/components/evidence-inspector.js +141 -0
- package/dist/frontend/src/components/filter-rail.js +119 -0
- package/dist/frontend/src/components/query-bar.js +126 -0
- package/dist/frontend/src/data/flagship-graph.js +1460 -0
- package/dist/frontend/src/export-entry.js +36 -0
- package/dist/frontend/src/lib/api-client.js +92 -0
- package/dist/frontend/src/lib/contrast.js +34 -0
- package/dist/frontend/src/lib/dom.js +24 -0
- package/dist/frontend/src/lib/escape-html.js +16 -0
- package/dist/frontend/src/lib/flow-path.js +40 -0
- package/dist/frontend/src/lib/focus-controls.js +149 -0
- package/dist/frontend/src/lib/protection-visual.js +46 -0
- package/dist/frontend/src/lib/query-language.js +240 -0
- package/dist/frontend/src/lib/row-filters.js +43 -0
- package/dist/frontend/src/lib/state.js +84 -0
- package/dist/frontend/src/main.js +83 -0
- package/dist/frontend/src/shell.js +184 -0
- package/dist/frontend/src/views/architecture-view.js +798 -0
- package/dist/frontend/src/views/inventory-view.js +292 -0
- package/dist/frontend/src/views/privacy-view.js +172 -0
- package/dist/frontend/src/views/trace-view.js +206 -0
- package/dist/frontend/styles/architecture-view.css +93 -0
- package/dist/frontend/styles/filter-rail.css +34 -0
- package/dist/frontend/styles/inspector.css +69 -0
- package/dist/frontend/styles/inventory-view.css +74 -0
- package/dist/frontend/styles/privacy-view.css +86 -0
- package/dist/frontend/styles/query-bar.css +107 -0
- package/dist/frontend/styles/shell.css +155 -0
- package/dist/frontend/styles/tokens.css +128 -0
- package/dist/frontend/styles/trace-view.css +95 -0
- package/package.json +13 -6
- package/src/dataflow/CLAUDE.md +1 -1
- package/src/dataflow/catalog.js +42 -0
- package/src/dataflow/orm-write-catalog.js +175 -0
- package/src/engine.js +92 -1
- package/src/ir/CLAUDE.md +1 -0
- package/src/ir/chrome-probe.mjs +150 -0
- package/src/ir/parser-js.js +94 -7
- package/src/lineage/CLAUDE.md +1203 -0
- package/src/lineage/DESIGN_DESTINATION_RESOLVER.md +156 -0
- package/src/lineage/DESIGN_GRAPH_BUILDER.md +938 -0
- package/src/lineage/DESIGN_HANDLING_ANALYZER.md +355 -0
- package/src/lineage/DESIGN_INTRAPROCEDURAL.md +628 -0
- package/src/lineage/DESIGN_PATH_PROVENANCE.md +3451 -0
- package/src/lineage/DESIGN_QUEUE_DETAIL.md +120 -0
- package/src/lineage/DESIGN_REGISTRIES.md +880 -0
- package/src/lineage/DESIGN_STORE_DETAIL.md +143 -0
- package/src/lineage/DESIGN_TRANSIT_PROTECTION.md +245 -0
- package/src/lineage/classification.js +56 -0
- package/src/lineage/coverage.js +658 -0
- package/src/lineage/cross-repo-link.js +107 -0
- package/src/lineage/dataflow-graph.schema.json +184 -0
- package/src/lineage/decision-story.js +206 -0
- package/src/lineage/drift-policy.js +279 -0
- package/src/lineage/driver.js +135 -0
- package/src/lineage/engine.js +992 -0
- package/src/lineage/export-briefing.js +628 -0
- package/src/lineage/export-csv.js +62 -0
- package/src/lineage/export-json.js +238 -0
- package/src/lineage/export-privacy.js +258 -0
- package/src/lineage/federation-loader.js +111 -0
- package/src/lineage/field-identity.js +78 -0
- package/src/lineage/fixtures/build-flagship-fixture.mjs +272 -0
- package/src/lineage/fixtures/flagship-graph.json +1453 -0
- package/src/lineage/flow-grade.js +221 -0
- package/src/lineage/governance-edit.js +169 -0
- package/src/lineage/graph-builder.js +1114 -0
- package/src/lineage/graph-diff.js +431 -0
- package/src/lineage/graph-snapshot.js +180 -0
- package/src/lineage/handling-analyzer.js +168 -0
- package/src/lineage/ids.js +349 -0
- package/src/lineage/impact-assessment.js +76 -0
- package/src/lineage/impact-engine.js +268 -0
- package/src/lineage/index.js +281 -0
- package/src/lineage/language-coverage-tiers.js +58 -0
- package/src/lineage/obligation-mapping.js +126 -0
- package/src/lineage/obligation-predicates.js +235 -0
- package/src/lineage/observation-adapters.js +282 -0
- package/src/lineage/observation-correlation.js +622 -0
- package/src/lineage/observation-store.js +497 -0
- package/src/lineage/path-query.js +410 -0
- package/src/lineage/path-store.js +400 -0
- package/src/lineage/protection.js +53 -0
- package/src/lineage/recipient-profile.js +192 -0
- package/src/lineage/recipient-registry.js +394 -0
- package/src/lineage/redact-graph.js +224 -0
- package/src/lineage/remediation.js +417 -0
- package/src/lineage/resolve-destination.js +91 -0
- package/src/lineage/runtime-observation.js +464 -0
- package/src/lineage/scenario-diff.js +84 -0
- package/src/lineage/scenario-engine.js +251 -0
- package/src/lineage/scenario.js +101 -0
- package/src/lineage/schema.js +167 -0
- package/src/lineage/sink-registry.js +427 -0
- package/src/lineage/source-registry.js +357 -0
- package/src/lineage/source-seeding.js +212 -0
- package/src/lineage/summaries.js +590 -0
- package/src/lineage/transform-catalog.js +397 -0
- package/src/lineage/transit-protection.js +150 -0
- package/src/lineage/validate.js +285 -0
- package/src/mcp/CLAUDE.md +7 -1
- package/src/mcp/dataflow-tools.js +160 -0
- package/src/mcp/server.js +1 -1
- package/src/mcp/tools.js +2 -1
- package/src/pipeline/scan-health.js +19 -1
- package/src/posture/CLAUDE.md +19 -0
- package/src/posture/artifact-registry.js +52 -0
- package/src/posture/auditor-walkthrough.js +76 -0
- package/src/posture/compliance-frameworks/hipaa-security-rule.json +3 -2
- package/src/posture/obligation-evidence-pack.js +202 -0
- package/src/posture/remediation-ledger.js +337 -0
- package/src/server/CLAUDE.md +47 -0
- package/src/server/graph-loader.js +141 -0
- package/src/server/http-server.js +325 -0
- package/src/server/routes.js +129 -0
- package/src/server/security.js +111 -0
- package/src/server/static-assets.js +144 -0
- package/src/shared/frontend-root.js +52 -0
- package/dist/11.index.js +0 -353
- package/dist/259.index.js +0 -975
- package/dist/317.index.js +0 -300
- package/dist/609.index.js +0 -741
- package/dist/838.index.js +0 -152
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Data Flow Explorer design tokens (PRD §8.1). Dark is the reference theme.
|
|
3
|
+
* Values are copied verbatim from the PRD — do not adjust without a
|
|
4
|
+
* deliberate, separately-reviewed change.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
:root {
|
|
8
|
+
/* Surfaces */
|
|
9
|
+
--surface-canvas: #061625;
|
|
10
|
+
--surface-panel: #0B1E2F;
|
|
11
|
+
--surface-elevated: #102A40;
|
|
12
|
+
--border-default: #28445A;
|
|
13
|
+
|
|
14
|
+
/* Text */
|
|
15
|
+
--text-primary: #F3F7FA;
|
|
16
|
+
--text-secondary: #9FB3C5;
|
|
17
|
+
|
|
18
|
+
/* Selection / focus */
|
|
19
|
+
--accent-selection: #3DA9FF;
|
|
20
|
+
|
|
21
|
+
/* Protection verdict status */
|
|
22
|
+
--status-protected: #59D17D;
|
|
23
|
+
--status-unprotected: #FF625C;
|
|
24
|
+
--status-unknown: #F5B83D;
|
|
25
|
+
|
|
26
|
+
/* Text color for content painted directly on a status token background
|
|
27
|
+
(e.g. the coverage banner). NOT the same as --text-primary, which is
|
|
28
|
+
sized against --surface-canvas/--surface-panel, not against a status
|
|
29
|
+
color. Verified with lib/contrast.js's contrastRatio(): #061625 on
|
|
30
|
+
dark --status-unknown (#F5B83D) is 10.27:1. See the light-theme block
|
|
31
|
+
below for the light-theme value and its own verified ratio. */
|
|
32
|
+
--status-banner-text: #061625;
|
|
33
|
+
|
|
34
|
+
/* AI processing context */
|
|
35
|
+
--context-ai: #B47AFF;
|
|
36
|
+
|
|
37
|
+
/* Data class overlays */
|
|
38
|
+
--class-pii: #28D1C5;
|
|
39
|
+
--class-phi: #A97BFF;
|
|
40
|
+
--class-pci: #4CA7FF;
|
|
41
|
+
|
|
42
|
+
/* Spacing (8px grid, PRD §7.7) */
|
|
43
|
+
--space-1: 8px;
|
|
44
|
+
--space-2: 16px;
|
|
45
|
+
--space-3: 24px;
|
|
46
|
+
--space-4: 32px;
|
|
47
|
+
|
|
48
|
+
/* Radius / border (PRD §8.2) */
|
|
49
|
+
--radius-default: 8px;
|
|
50
|
+
--border-width: 1px;
|
|
51
|
+
|
|
52
|
+
/* Typography (PRD §8.2) — bundled system stack; never a remote/CDN font */
|
|
53
|
+
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
54
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
55
|
+
--font-size-view-title: 23px;
|
|
56
|
+
--font-size-panel-title: 15px;
|
|
57
|
+
--font-size-node-title: 14px;
|
|
58
|
+
--font-size-body: 13px;
|
|
59
|
+
--font-size-code: 12.5px;
|
|
60
|
+
|
|
61
|
+
/* Motion (PRD §8.2 — focus/topology change only, no ambient animation) */
|
|
62
|
+
--motion-duration: 200ms;
|
|
63
|
+
--motion-duration-reduced: 0ms;
|
|
64
|
+
|
|
65
|
+
/* Shell region sizing (PRD §7.7) */
|
|
66
|
+
--header-height: 56px;
|
|
67
|
+
--view-tabs-height: 44px;
|
|
68
|
+
--left-rail-width: 248px;
|
|
69
|
+
--left-rail-collapsed-width: 56px;
|
|
70
|
+
--right-inspector-width: 360px;
|
|
71
|
+
--context-rail-height: 72px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Light theme — same semantic tokens, WCAG-AA-equivalent contrast (PRD §8.1/§23) */
|
|
75
|
+
:root[data-theme="light"] {
|
|
76
|
+
--surface-canvas: #FFFFFF;
|
|
77
|
+
--surface-panel: #F4F7FA;
|
|
78
|
+
--surface-elevated: #E7EEF3;
|
|
79
|
+
--border-default: #C7D3DC;
|
|
80
|
+
|
|
81
|
+
--text-primary: #0B1E2F;
|
|
82
|
+
--text-secondary: #3E5568;
|
|
83
|
+
|
|
84
|
+
--accent-selection: #1B6FC2;
|
|
85
|
+
|
|
86
|
+
/* status-protected and status-unknown darkened slightly from their
|
|
87
|
+
original values (#1E8A4C, #9A6B00) — Milestone 3, sub-project A11y,
|
|
88
|
+
found via test/tokens-contrast.test.js that both originals failed
|
|
89
|
+
WCAG AA (4.5:1) against --surface-panel (#F4F7FA): 4.07:1 and 4.36:1
|
|
90
|
+
respectively. Verified with lib/contrast.js's contrastRatio() against
|
|
91
|
+
BOTH backgrounds a status color plausibly renders on: --status-
|
|
92
|
+
protected (#1C8047) is 4.97:1 on --surface-canvas / 4.62:1 on
|
|
93
|
+
--surface-panel; --status-unknown (#956700) is 4.98:1 / 4.63:1. Both
|
|
94
|
+
now clear AA with margin (>=4.6) rather than sitting at the exact
|
|
95
|
+
4.50 boundary, which is fragile against hex-rounding. --status-
|
|
96
|
+
unprotected was already compliant (5.26:1 / 4.89:1), unchanged. */
|
|
97
|
+
--status-protected: #1C8047;
|
|
98
|
+
--status-unprotected: #C7362D;
|
|
99
|
+
--status-unknown: #956700;
|
|
100
|
+
|
|
101
|
+
/* Verified with lib/contrast.js's contrastRatio(): #FFFFFF on light
|
|
102
|
+
--status-unknown (#956700) is 4.98:1 (>= 4.5:1 AA). The dark-block
|
|
103
|
+
value (#061625, --surface-canvas's own dark value) is 3.90:1 here --
|
|
104
|
+
below AA -- which is the bug this token pair fixes: shell.css must
|
|
105
|
+
never hardcode dark theme's value and expect it to also work in
|
|
106
|
+
light theme. */
|
|
107
|
+
--status-banner-text: #FFFFFF;
|
|
108
|
+
|
|
109
|
+
--context-ai: #6E38B8;
|
|
110
|
+
|
|
111
|
+
--class-pii: #0E7C73;
|
|
112
|
+
--class-phi: #6E44B8;
|
|
113
|
+
--class-pci: #1C63A8;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@media (prefers-reduced-motion: reduce) {
|
|
117
|
+
:root {
|
|
118
|
+
--motion-duration: var(--motion-duration-reduced);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
body {
|
|
123
|
+
background: var(--surface-canvas);
|
|
124
|
+
color: var(--text-primary);
|
|
125
|
+
font-family: var(--font-family);
|
|
126
|
+
font-size: var(--font-size-body);
|
|
127
|
+
margin: 0;
|
|
128
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
.trace-view {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: var(--space-2);
|
|
5
|
+
max-width: 640px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.trace-step {
|
|
9
|
+
display: flex;
|
|
10
|
+
gap: var(--space-2);
|
|
11
|
+
padding: var(--space-2);
|
|
12
|
+
background: var(--surface-panel);
|
|
13
|
+
border: var(--border-width) solid var(--border-default);
|
|
14
|
+
border-radius: var(--radius-default);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.trace-step-number {
|
|
18
|
+
flex: 0 0 auto;
|
|
19
|
+
width: 24px;
|
|
20
|
+
height: 24px;
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
background: var(--surface-elevated);
|
|
23
|
+
color: var(--text-primary);
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
font-size: var(--font-size-code);
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.trace-step-body {
|
|
32
|
+
flex: 1 1 auto;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.trace-step-kind {
|
|
36
|
+
color: var(--text-secondary);
|
|
37
|
+
font-size: var(--font-size-code);
|
|
38
|
+
text-transform: uppercase;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.trace-step-mapping {
|
|
42
|
+
font-family: var(--font-mono);
|
|
43
|
+
font-size: var(--font-size-code);
|
|
44
|
+
color: var(--text-primary);
|
|
45
|
+
margin: 4px 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.trace-step-node {
|
|
49
|
+
color: var(--text-secondary);
|
|
50
|
+
font-size: var(--font-size-body);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.trace-step-boundary {
|
|
54
|
+
display: inline-block;
|
|
55
|
+
border: 1px solid var(--status-unprotected);
|
|
56
|
+
color: var(--status-unprotected);
|
|
57
|
+
border-radius: var(--radius-default);
|
|
58
|
+
padding: 1px 6px;
|
|
59
|
+
font-size: var(--font-size-code);
|
|
60
|
+
margin-top: 4px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.trace-branch-group {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
gap: var(--space-2);
|
|
67
|
+
padding-left: var(--space-2);
|
|
68
|
+
border-left: 2px solid var(--accent-selection);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.trace-branch-label {
|
|
72
|
+
color: var(--text-secondary);
|
|
73
|
+
font-size: var(--font-size-code);
|
|
74
|
+
text-transform: uppercase;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.trace-alternates {
|
|
78
|
+
margin-top: var(--space-2);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.trace-alternate-item {
|
|
82
|
+
padding: var(--space-1) 0;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
color: var(--text-secondary);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.trace-alternate-item:hover {
|
|
88
|
+
color: var(--text-primary);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.trace-empty {
|
|
92
|
+
color: var(--text-secondary);
|
|
93
|
+
font-style: italic;
|
|
94
|
+
padding: var(--space-2);
|
|
95
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clear-capabilities/agentic-security-scanner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.147.5",
|
|
4
4
|
"description": "Scanner engine for the agentic-security Claude Code plugin — SAST, SCA (function-level reachability + CISA KEV), secrets, IaC, prompt-injection, MCP/agent-tool audit, auth/authZ deep analysis, attack chains, PoC generation, business logic, toxic-combinations scoring, SBOM, pipeline integrity, compliance attestation, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -56,19 +56,21 @@
|
|
|
56
56
|
"lodash-es": "^4.18.1"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
|
-
"build": "ncc build bin/agentic-security.js -o dist --minify -e web-tree-sitter -e tree-sitter-wasms && rm -rf dist/compliance-frameworks && mkdir -p dist/compliance-frameworks && cp src/posture/compliance-frameworks/*.json dist/compliance-frameworks/ && mv dist/index.js dist/agentic-security.mjs && rm -f dist/package.json && chmod +x dist/agentic-security.mjs && node -e \"const fs=require('fs');const p='dist/agentic-security.mjs';const c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!'))fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c);\" && node -e \"const fs=require('fs');const c=require('crypto');const h=c.createHash('sha256').update(fs.readFileSync('dist/agentic-security.mjs')).digest('hex');fs.writeFileSync('dist/agentic-security.mjs.sha256',h+' agentic-security.mjs\\n');\"",
|
|
59
|
+
"build": "ncc build bin/agentic-security.js -o dist --minify -e web-tree-sitter -e tree-sitter-wasms && rm -rf dist/compliance-frameworks && mkdir -p dist/compliance-frameworks && cp src/posture/compliance-frameworks/*.json dist/compliance-frameworks/ && node scripts/copy-frontend.mjs && mv dist/index.js dist/agentic-security.mjs && rm -f dist/package.json && chmod +x dist/agentic-security.mjs && node -e \"const fs=require('fs');const p='dist/agentic-security.mjs';const c=fs.readFileSync(p,'utf8');if(!c.startsWith('#!'))fs.writeFileSync(p,'#!/usr/bin/env node\\n'+c);\" && node -e \"const fs=require('fs');const c=require('crypto');const h=c.createHash('sha256').update(fs.readFileSync('dist/agentic-security.mjs')).digest('hex');fs.writeFileSync('dist/agentic-security.mjs.sha256',h+' agentic-security.mjs\\n');\"",
|
|
60
60
|
"prepare": "node ../scripts/pre-push-gate.mjs --install-hook",
|
|
61
61
|
"prepublishOnly": "npm run build && node ../scripts/sync-scanner-changelog.mjs && node ../scripts/release-check.mjs",
|
|
62
|
-
"test": "node ../scripts/run-unit-tests.mjs && AGENTIC_SECURITY_CPP_DATAFLOW=1 node --test test/cpp-dataflow.test.js && node --experimental-test-module-mocks --test test/fault-injection.test.js && node --experimental-test-module-mocks --test test/detector-fault-injection.test.js && node --experimental-test-module-mocks --test test/detector-fault-injection-k8s-admission.test.js && npm run test:python",
|
|
62
|
+
"test": "node ../scripts/run-unit-tests.mjs && AGENTIC_SECURITY_CPP_DATAFLOW=1 node --test test/cpp-dataflow.test.js && node --experimental-test-module-mocks --test test/fault-injection.test.js && node --experimental-test-module-mocks --test test/detector-fault-injection.test.js && node --experimental-test-module-mocks --test test/detector-fault-injection-k8s-admission.test.js && node --experimental-test-module-mocks --test test/lineage-fault-injection.test.js && npm run test:python",
|
|
63
63
|
"test:python": "node ../scripts/run-python-tests.mjs",
|
|
64
64
|
"test:smoke": "node --test test/smoke.test.js test/demo-app.test.js",
|
|
65
65
|
"test:glob": "node --test test/glob-compat.test.js",
|
|
66
66
|
"test:sast": "node --test test/cpp-hardcoded-secret.test.js test/sibling-guard.test.js test/comment-blindness.test.js test/crypto-specialist.test.js test/llm.test.js test/llm-cost-advisor.test.js test/llm-owasp.test.js test/logic.test.js test/authz.test.js test/model-load.test.js test/prompt-template.test.js test/business-logic.test.js test/python-sinks.test.js test/phase1-detectors.test.js test/phase2-detectors.test.js test/phase3-v3.test.js test/phase7-extensions.test.js test/phase8-extensions.test.js test/new-cwe-detectors.test.js test/file-upload.test.js test/llmsecops-detectors.test.js test/db-taint.test.js test/dart-swift.test.js test/zip-slip-containment-guard.test.js test/redos-anchoring.test.js test/path-guard-validator-call.test.js test/redos-nfa.test.js test/weak-randomness.test.js test/csharp-pipeline.test.js test/post-quantum-crypto.test.js test/web3-advanced.test.js test/cloud-iam-k8s.test.js test/crypto-protocol.test.js test/ml-supply-chain.test.js test/mcp-audit-scan.test.js test/wrong-context-sanitizer.test.js test/sanitizer-context.test.js test/frontend-hygiene.test.js test/csv-injection.test.js test/stored-taint.test.js test/tree-sitter-sinks.test.js test/kotlin-structural.test.js test/ruby-php-structural.test.js test/java-csharp-structural.test.js test/guard-recognition.test.js test/guard-window-identifier-correlation.test.js test/js-python-framework-structural.test.js test/go-structural.test.js test/secret-concat.test.js test/secret-redaction.test.js test/xss-reflected-multilang.test.js test/code-injection-multilang.test.js test/xxe-multilang.test.js test/xpath-injection-multilang.test.js test/gapfill-batch13.test.js test/agent-untrusted-flow.test.js test/api-authz.test.js test/event-entrypoint.test.js test/iac-terraform.test.js test/cross-service.test.js test/rbac-consistency.test.js test/adversarial-robustness.test.js test/secret-entropy.test.js test/comment-strip.test.js test/juliet-path-filter-gate.test.js test/java-bench-shape-opt-in.test.js test/reachability-missing-callgraph-data.test.js test/rate-limit.test.js test/auth-signals.test.js test/convention-deviation.test.js test/resource-exhaustion.test.js test/resource-exhaustion-realworld.test.js test/redirect-toctou.test.js test/redirect-toctou-realworld.test.js test/codegen-sink.test.js test/ownership-authz.test.js test/ownership-authz-realworld.test.js test/t21-precision-audit.test.js test/secrets-coverage.test.js test/prompt-injection-payloads.test.js test/iac-cloud-templates.test.js test/ruby-path-join.test.js test/sast/manifest-line-tracking.test.js",
|
|
67
|
-
"test:posture": "node --test test/git-hardening.test.js test/privacy-framework.test.js test/material-change.test.js test/drift.test.js test/scorecard.test.js test/accuracy-scorecard.test.js test/scorecard-gate.test.js test/predeploy-gate.test.js test/release-check.test.js test/pre-push-gate.test.js test/dependency-currency.test.js test/package-contents-check.test.js test/gate-verdict-cache.test.js test/run-unit-tests.test.js test/release-workflow.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js",
|
|
68
|
-
"test:dataflow": "node --test test/privacy-catalog.test.js test/privacy-deep-walker.test.js test/privacy-deep-e2e.test.js test/container-taint.test.js test/stored-taint-families.test.js test/py-annotation-sources.test.js test/fn-reach.test.js test/deep-taint.test.js test/calibration.test.js test/holdout-eval.test.js test/cross-lang-meta.test.js test/cross-lang-queues.test.js test/phase5-xlang.test.js test/phase5-coverage.test.js test/phase6-taint.test.js test/llm-validator-consistency.test.js test/llm-validator-default-on.test.js test/llm-validator-preset.test.js test/parser-py-cst.test.js test/parser-cs-kt.test.js test/parser-cs-annotations.test.js test/parser-cs-control-flow.test.js test/parser-kt-control-flow.test.js test/parser-js-annotations.test.js test/parser-java-annotations.test.js test/parser-java-control-flow.test.js test/parser-java-calls.test.js test/parser-go.test.js test/parser-php-rb.test.js test/parser-php-control-flow.test.js test/interproc-k2.test.js test/proven-clean.test.js test/backward-default.test.js test/incremental-cache.test.js test/string-regex-lattice.test.js test/closure-capture.test.js test/points-to.test.js test/type-stubs.test.js test/soft-taint.test.js test/ifds.test.js test/symbolic-exec-proof.test.js test/ifds-summary-edges.test.js test/stub-aware-filter.test.js test/cross-repo.test.js test/proof-gate.test.js test/layer-recall.test.js test/java-taint-flow.test.js test/kt-taint-flow.test.js test/sanitizer-typed-flow.test.js test/sanitizer-gate-unit.test.js test/proof-safe.test.js test/collection-taint.test.js test/kcfa-context.test.js test/kcfa-callstring.test.js test/flow-parity.test.js test/callgraph-resolve.test.js test/import-reachability.test.js test/ir-stats.test.js test/parser-cpp.test.js test/parser-js-decorators.test.js test/parser-js-if-else-cfg.test.js test/cpp-integration.test.js test/engine-reconnect.test.js test/phase2-scoping.test.js test/engine-recall.test.js test/catalog-annotation-source.test.js test/catalog-cs-p1.test.js test/catalog-expanded.test.js test/builtin-summaries.test.js test/interproc-mutation-crash.test.js test/mutated-param-taint.test.js test/return-sink-check.test.js test/higher-order-inline-callback.test.js test/interproc-findings-discard.test.js test/runscan-deep-option.test.js test/summary-cache-convergence.test.js test/parser-rb-calls.test.js test/parser-rb-module-level.test.js test/balanced-call.test.js test/destructuring-taint.test.js test/computed-member-taint.test.js test/string-interpolation-taint.test.js test/dataflow-deadcode-severity.test.js test/catalog-dotted-callee-lookup.test.js test/builtin-summary-family-blind-kill.test.js test/deep-mode-annotator-pipeline.test.js test/receiver-type-and-nested-calls.test.js test/member-write-and-loop-taint.test.js test/parser-py-module-level.test.js test/parser-php-module-level.test.js test/r14b-module-level-e2e.test.js test/annotation-taint-engine.test.js test/interproc-nested-call-taint.test.js test/catalog-xpath-injection.test.js test/catalog-ldap-injection.test.js test/catalog-xxe.test.js test/catalog-response-splitting.test.js test/catalog-code-injection.test.js test/parser-rb-control-flow.test.js test/catalog-ruby-p1.test.js test/callee-receiver-taint.test.js test/catalog-command-injection-p4.test.js test/catalog-xss-p4.test.js test/catalog-path-ssrf-p3.test.js test/dataflow/provenance-pipeline-integration.test.js",
|
|
69
|
-
"test:mcp": "node --test test/mcp.test.js test/mcp-protocol-smoke.test.js test/mcp-audit.test.js test/audit-cli.test.js test/mcp-scratchpad.test.js test/mcp-offload.test.js test/sca-upgrade.test.js test/lsp-server.test.js",
|
|
67
|
+
"test:posture": "node --test test/git-hardening.test.js test/privacy-framework.test.js test/material-change.test.js test/drift.test.js test/scorecard.test.js test/accuracy-scorecard.test.js test/scorecard-gate.test.js test/predeploy-gate.test.js test/release-check.test.js test/pre-push-gate.test.js test/dependency-currency.test.js test/package-contents-check.test.js test/gate-verdict-cache.test.js test/run-unit-tests.test.js test/release-workflow.test.js test/independent-population.test.js test/why-missed.test.js test/independent-scoring.test.js test/evidence-bundle.test.js test/obligation-evidence-pack.test.js test/policy-bundle.test.js test/discovery-memory.test.js test/mttr.test.js test/license-policy.test.js test/aibom.test.js test/sbom.test.js test/api-inventory.test.js test/iam-policy.test.js test/container.test.js test/container-runtime.test.js test/image-packages.test.js test/kev.test.js test/dep-confusion.test.js test/sca-deprecated.test.js test/sca-batch.test.js test/composite-risk.test.js test/epss-enrich.test.js test/sca-coverage.test.js test/gradle-deps.test.js test/sca-route-reachable.test.js test/sca-policy.test.js test/sca-verdict.test.js test/install-script.test.js test/sca-linked-findings.test.js test/packs.test.js test/flow-narration.test.js test/regression-test-gen.test.js test/deterministic-fix.test.js test/falsification.test.js test/verification-separation.test.js test/logic-claims.test.js test/attestation.test.js test/verify-attestation-cli.test.js test/comparison.test.js test/determinism-cross-machine.test.js test/fix-honesty-gate.test.js test/model-routing.test.js test/root-cause-sweep.test.js test/entrypoint-inventory.test.js test/relevance.test.js test/untrusted.test.js test/agent-hardening.test.js test/rule-synthesis.test.js test/policy-gate.test.js test/agents-memory.test.js test/cve-lookup.test.js test/cve-alert-daemon.test.js test/fix-verify-loop.test.js test/fix-verify-tests.test.js test/fix-acceptance.test.js test/exploitability-probability.test.js test/history-scan.test.js test/viral-features.test.js test/viral-v074.test.js test/state-dir.test.js test/ignore-pragma.test.js test/license-graph.test.js test/secret-live-check.test.js test/attack-taxonomy.test.js test/triage-memory.test.js test/pr-augment.test.js test/chat-batch2.test.js test/chat-batch3.test.js test/chat-batch4.test.js test/chat-batch5.test.js test/chat-batch6.test.js test/risk-scenario-disclosure.test.js test/egress-policy.test.js test/egress-policy-completeness.test.js test/egress-policy-integration.test.js test/router.test.js test/legacy-alias-redirect.test.js test/cache-economics.test.js test/coverage-report.test.js test/corpus-status.test.js test/provenance.test.js test/secret-history.test.js test/execution-proof.test.js test/fix-metrics.test.js test/corpus-enroll.test.js test/prove-findings.test.js test/corpus-match.test.js test/corpus-provenance.test.js test/learning-quorum.test.js test/llm-cache-integrity.test.js test/proof-artifact.test.js test/providers.test.js test/fleet.test.js test/autopilot.test.js test/autopilot-cli.test.js test/verifier-independence.test.js test/integrity-legacy-key.test.js test/suppression-visibility.test.js test/cost-ceiling.test.js test/local-endpoint.test.js test/model-trust.test.js test/vuln-archaeology.test.js test/scan-checkpoint.test.js test/llm-redact.test.js test/world-class-batch2.test.js test/world-class-modules.test.js test/privacy-ir-adapter.test.js test/privacy-taxonomy.test.js test/privacy-sink-policy.test.js test/privacy-governance.test.js test/privacy-inventory.test.js test/integration-end-to-end.test.js test/streak-cli-wiring.test.js test/stack-playbook.test.js test/machine-output-flag.test.js test/stdout-flush.test.js test/format-determinism.test.js test/only-flag-channels.test.js test/confidence.test.js test/security-trend.test.js test/calibration-drift.test.js test/validator-metrics.test.js test/clustering-ir-taint-line.test.js test/concurrency-cwe.test.js test/compliance-mapping-liveness.test.js test/compliance-severity-threshold.test.js test/compliance-severity-policy.test.js test/compliance-evidence-binding.test.js test/compliance-evidence-signing.test.js test/compliance-file-contains.test.js test/label-isolation.test.js test/evidence-grade-wording.test.js test/llm-model-status.test.js test/egress-policy-constraints.test.js test/egress-redact.test.js test/egress-audit.test.js test/egress-approved-providers.test.js test/family-registry.test.js test/coverage-strength.test.js test/framework-provenance.test.js test/framework-provenance-controlrefs.test.js test/third-party-verification.test.js test/proof-coverage.test.js test/calibration-holdout.test.js test/independent-population-gate.test.js test/catalog-freshness.test.js test/incremental-parity.test.js test/surface-smoke.test.js test/fix-coverage.test.js test/raw-source-carveout.test.js test/mlbom-conformance.test.js test/deploy-gate-replay.test.js test/sbom-conformance.test.js test/unscored-claims.test.js test/mcp-rug-pull.test.js test/agent-boundary-taint.test.js test/confinement-adversarial.test.js test/comment-strip-cost.test.js test/reachability-claim.test.js test/entrypoint-breadth.test.js test/dep-file-admission.test.js test/custom-rules-freshness.test.js test/posture/provenance-schema.test.js test/posture/provenance-cache.test.js test/helpers/build-git-fixture.test.js test/posture/provenance-git-evidence.test.js test/posture/provenance-dag-walk.test.js test/posture/provenance-confidence.test.js test/posture/provenance-predicate-replay.test.js test/posture/provenance-origin-resolver.test.js test/posture/provenance-ai-authorship.test.js test/posture/provenance-branch-entry.test.js test/posture/provenance-evidence-attribution.test.js test/posture/provenance-lifecycle.test.js test/posture/provenance-missing-control-resolver.test.js test/posture/provenance-missing-control-wiring.test.js test/posture/provenance-coordinator.test.js test/posture/provenance-sca-origin.test.js test/posture/provenance-transitive-sca.test.js test/posture/provenance-coordinator-sca.test.js test/posture/provenance-providers.test.js test/posture/provenance-evidence-bundle.test.js test/posture/provenance-repo-lineage.test.js test/posture/provenance-secrets-logic.test.js test/cli/provenance-flags.test.js test/cli/attest-provenance.test.js test/cli/attest-obligations.test.js test/cli/compliance-walkthrough-lineage.test.js test/cli/dataflow-export-privacy.test.js test/cli/dataflow-export-briefing.test.js test/cli/lineage-snapshot-persist.test.js test/cli/dataflow-diff.test.js test/cli/dataflow-watch.test.js test/cli/dataflow-recipients.test.js test/cli/dataflow-coverage.test.js test/security/provenance-safety.test.js test/security/provenance-injection.test.js test/posture/remediation-ledger.test.js",
|
|
68
|
+
"test:dataflow": "node --test test/privacy-catalog.test.js test/privacy-deep-walker.test.js test/privacy-deep-e2e.test.js test/container-taint.test.js test/stored-taint-families.test.js test/py-annotation-sources.test.js test/fn-reach.test.js test/deep-taint.test.js test/calibration.test.js test/holdout-eval.test.js test/cross-lang-meta.test.js test/cross-lang-queues.test.js test/phase5-xlang.test.js test/phase5-coverage.test.js test/phase6-taint.test.js test/llm-validator-consistency.test.js test/llm-validator-default-on.test.js test/llm-validator-preset.test.js test/parser-py-cst.test.js test/chrome-probe.test.js test/parser-cs-kt.test.js test/parser-cs-annotations.test.js test/parser-cs-control-flow.test.js test/parser-kt-control-flow.test.js test/parser-js-annotations.test.js test/parser-java-annotations.test.js test/parser-java-control-flow.test.js test/parser-java-calls.test.js test/parser-go.test.js test/parser-php-rb.test.js test/parser-php-control-flow.test.js test/interproc-k2.test.js test/proven-clean.test.js test/backward-default.test.js test/incremental-cache.test.js test/string-regex-lattice.test.js test/closure-capture.test.js test/points-to.test.js test/type-stubs.test.js test/soft-taint.test.js test/ifds.test.js test/symbolic-exec-proof.test.js test/ifds-summary-edges.test.js test/stub-aware-filter.test.js test/cross-repo.test.js test/proof-gate.test.js test/layer-recall.test.js test/java-taint-flow.test.js test/kt-taint-flow.test.js test/sanitizer-typed-flow.test.js test/sanitizer-gate-unit.test.js test/proof-safe.test.js test/collection-taint.test.js test/kcfa-context.test.js test/kcfa-callstring.test.js test/flow-parity.test.js test/callgraph-resolve.test.js test/import-reachability.test.js test/ir-stats.test.js test/parser-cpp.test.js test/parser-js-decorators.test.js test/parser-js-if-else-cfg.test.js test/cpp-integration.test.js test/engine-reconnect.test.js test/phase2-scoping.test.js test/engine-recall.test.js test/catalog-annotation-source.test.js test/catalog-cs-p1.test.js test/catalog-expanded.test.js test/builtin-summaries.test.js test/interproc-mutation-crash.test.js test/mutated-param-taint.test.js test/return-sink-check.test.js test/higher-order-inline-callback.test.js test/interproc-findings-discard.test.js test/runscan-deep-option.test.js test/summary-cache-convergence.test.js test/parser-rb-calls.test.js test/parser-rb-module-level.test.js test/balanced-call.test.js test/destructuring-taint.test.js test/computed-member-taint.test.js test/string-interpolation-taint.test.js test/dataflow-deadcode-severity.test.js test/catalog-dotted-callee-lookup.test.js test/builtin-summary-family-blind-kill.test.js test/deep-mode-annotator-pipeline.test.js test/receiver-type-and-nested-calls.test.js test/member-write-and-loop-taint.test.js test/parser-py-module-level.test.js test/parser-php-module-level.test.js test/r14b-module-level-e2e.test.js test/annotation-taint-engine.test.js test/interproc-nested-call-taint.test.js test/catalog-xpath-injection.test.js test/catalog-ldap-injection.test.js test/catalog-xxe.test.js test/catalog-response-splitting.test.js test/catalog-code-injection.test.js test/parser-rb-control-flow.test.js test/catalog-ruby-p1.test.js test/callee-receiver-taint.test.js test/catalog-command-injection-p4.test.js test/catalog-xss-p4.test.js test/catalog-path-ssrf-p3.test.js test/catalog-ai-model-provider-precision.test.js test/catalog-orm-write.test.js test/dataflow/provenance-pipeline-integration.test.js",
|
|
69
|
+
"test:mcp": "node --test test/mcp.test.js test/mcp-protocol-smoke.test.js test/mcp-audit.test.js test/audit-cli.test.js test/mcp-scratchpad.test.js test/mcp-offload.test.js test/sca-upgrade.test.js test/lsp-server.test.js test/mcp-dataflow-tools.test.js test/cli/governance-propose-edit.test.js test/cli/remediation-open-update.test.js test/cli/remediation-verify-reopen.test.js test/cli/dataflow-observations.test.js test/cli/federate-declare-list.test.js",
|
|
70
70
|
"test:report": "node --test test/junit.test.js test/ci.test.js test/poc-generator.test.js test/verifier.test.js test/verifier-target.test.js test/annotator-errors.test.js test/scan-health.test.js test/finding-schema.test.js test/pipeline/finding-schema-provenance.test.js test/evidence-provenance.test.js test/report/provenance-output.test.js test/report/provenance-format-parity.test.js test/legacy-compat.test.js test/annotator-runner.test.js test/detector-runner.test.js test/detector-errors.test.js test/analyzer-supervisor.test.js test/cascade-worker-pool.test.js test/cascade-pool-wiring.test.js test/coverage-ledger.test.js test/coverage-ledger-completeness.test.js test/assurance-mode.test.js test/artifact-registry.test.js test/artifact-registry-completeness.test.js test/retention-policy.test.js test/state-lifecycle-report.test.js test/legal-hold.test.js test/production-feedback.test.js test/calibration-feedback.test.js test/encryption-provider.test.js test/grader-calibration.test.js test/pr-delta-gate.test.js test/vex.test.js test/report-render.test.js test/oscal-conformance.test.js test/cli-fix-apply.test.js test/apply-fix-service.test.js test/high-impact-approval-gate.test.js test/approver-registry.test.js test/suppression-exceptions.test.js test/fix-history.test.js test/producer-registry.test.js test/producer-collector.test.js test/enrichment-completion.test.js",
|
|
71
|
+
"test:lineage": "node --test test/lineage/schema.test.js test/lineage/ids.test.js test/lineage/protection.test.js test/lineage/classification.test.js test/lineage/validate.test.js test/lineage/json-schema-parity.test.js test/lineage/flagship-fixture.test.js test/lineage/flagship-fixture-semantics.test.js test/lineage/field-identity.test.js test/lineage/engine-expr-resolver.test.js test/lineage/engine-walker.test.js test/lineage/engine-integration.test.js test/lineage/engine-receiver-identity.test.js test/lineage/summaries.test.js test/lineage/driver.test.js test/lineage/engine-provenance.test.js test/lineage/engine-provenance-interprocedural.test.js test/lineage/path-store.test.js test/lineage/path-query.test.js test/lineage/flow-grade.test.js test/lineage/source-registry.test.js test/lineage/sink-registry.test.js test/lineage/transform-catalog.test.js test/lineage/handling-analyzer.test.js test/lineage/registry-real-code.test.js test/lineage/source-seeding.test.js test/lineage/graph-builder.test.js test/lineage/coverage.test.js test/lineage/resolve-destination.test.js test/lineage/queue-detail.test.js test/lineage/index.test.js test/lineage/obligation-mapping.test.js test/lineage/obligation-predicates.test.js test/lineage/obligation-predicates-walkthrough.test.js test/lineage/transit-protection.test.js test/lineage/at-rest-protection.test.js test/lineage/protection-summary.test.js test/lineage/ac01-multi-sink.test.js test/lineage/policy-verdict.test.js test/lineage/governance-refs.test.js test/lineage/export-privacy.test.js test/lineage/export-json.test.js test/lineage/export-csv.test.js test/lineage/decision-story.test.js test/lineage/export-briefing.test.js test/lineage/graph-snapshot.test.js test/lineage/graph-diff.test.js test/lineage/drift-policy.test.js test/lineage/recipient-profile.test.js test/lineage/recipient-registry.test.js test/lineage/recipient-wiring.test.js test/lineage/redact-graph.test.js test/lineage-scan-wiring.test.js test/lineage-artifact-write.test.js test/bench-data-lineage-runner.test.js test/bundle-frontend.test.js test/bundle-frontend-golden.test.js test/generate-html-report.test.js test/export-image.test.js test/lineage/scenario.test.js test/lineage/scenario-engine.test.js test/lineage/scenario-diff.test.js test/lineage/scenario-no-obligation-wiring.test.js test/lineage/impact-assessment.test.js test/lineage/impact-engine.test.js test/lineage/impact-no-obligation-wiring.test.js test/lineage/governance-edit.test.js test/lineage/remediation.test.js test/lineage/runtime-observation.test.js test/lineage/observation-correlation.test.js test/lineage/observation-adapters.test.js test/lineage/observation-store.test.js test/lineage/runtime-corroboration-wiring.test.js test/lineage/cross-repo-link.test.js test/lineage/federation-loader.test.js test/lineage/cross-repo-link-wiring.test.js",
|
|
71
72
|
"test:bench-modules": "node --test test/phase4-harness.test.js test/pipeline.test.js test/proof-corpus-lib.test.js test/proof-corpus-runner.test.js",
|
|
73
|
+
"test:server": "node --test test/server/graph-loader.test.js test/server/security.test.js test/server/routes.test.js test/server/http-server.test.js test/server/cmd-explore.test.js test/server/cmd-dataflow-export.test.js test/server/static-assets.test.js test/server/dataflow-scenario-cli.test.js test/server/dataflow-impact-cli.test.js",
|
|
72
74
|
"test:lifecycle": "node --test test/lsp-protocol-smoke.test.js test/ide-surfaces.test.js test/detector-liveness.test.js test/bench-watchdog.test.js test/ci-parity.test.js test/dead-code.test.js test/no-dead-modules.test.js test/no-orphan-scripts.test.js test/no-stray-state.test.js test/tree-integrity.test.js test/stop-hook.test.js test/plugin-self-check.test.js test/skills-registry.test.js test/bodyguard.test.js test/cache-invalidator-guard.test.js test/dispatch-pre-tool.test.js test/dispatch-user-prompt.test.js test/session-start-model-capture.test.js test/sandbox.test.js test/sandbox-escape.test.js test/ci-templates.test.js test/agent-mcp-tools.test.js test/triage-command.test.js test/no-orphan-tests.test.js test/supply-command.test.js test/posture-command.test.js test/labs-command.test.js test/compliance-command.test.js test/check-doc-drift.test.js test/dist-chunks-tracked.test.js && node ../scripts/lint-command-descriptions.mjs",
|
|
73
75
|
"test:eval": "node --test test/independent-eval.test.js test/realworld-recall.test.js",
|
|
74
76
|
"test:discovery": "node --test test/discovery-partition.test.js test/discovery-lenses.test.js test/discovery-hunter.test.js test/discovery-confirm.test.js test/discovery-disprove.test.js test/discovery-judge.test.js test/discovery-run.test.js test/discovery-wiring.test.js test/discovery-llm-invoke.test.js test/local-only-mode.test.js",
|
|
@@ -81,6 +83,8 @@
|
|
|
81
83
|
"prebench:realworld": "npm run build",
|
|
82
84
|
"bench:realworld": "node test/benchmark/realworld/bench-realworld.js",
|
|
83
85
|
"bench:llm-goats": "node test/benchmark/llm-goats/bench-llm-goats.js",
|
|
86
|
+
"bench:data-lineage": "node ../bench/data-lineage/runner.mjs",
|
|
87
|
+
"bench:data-lineage:check": "node ../bench/data-lineage/runner.mjs --check",
|
|
84
88
|
"bench:cve-replay": "node ../bench/cve-replay/runner.mjs",
|
|
85
89
|
"bench:cve-replay:ci": "node ../bench/cve-replay/runner.mjs --ci",
|
|
86
90
|
"bench:cve-replay:check": "node ../bench/cve-replay/runner.mjs --check-baseline",
|
|
@@ -109,6 +113,7 @@
|
|
|
109
113
|
"bench:self-scan": "node ../bench/self-scan/measure.mjs",
|
|
110
114
|
"bench:self-scan:check": "node ../bench/self-scan/check.mjs",
|
|
111
115
|
"bench:mutation:check": "node ../bench/mutation/runner.mjs",
|
|
116
|
+
"bench:protection-verdict:check": "node ../bench/protection-verdict/runner.mjs",
|
|
112
117
|
"bench:fix-correctness": "node ../bench/fix-correctness/runner.mjs",
|
|
113
118
|
"bench:iac-coverage": "node ../bench/iac-coverage/runner.mjs",
|
|
114
119
|
"bench:prompt-injection": "node ../bench/prompt-injection/runner.mjs",
|
|
@@ -125,12 +130,14 @@
|
|
|
125
130
|
"bench:provenance-accuracy:check": "node ../bench/provenance-accuracy/runner.mjs --check",
|
|
126
131
|
"bench:provenance-accuracy:update-baseline": "node ../bench/provenance-accuracy/runner.mjs --update-baseline",
|
|
127
132
|
"bench:privacy-recall": "node ../bench/privacy-recall/measure.mjs",
|
|
133
|
+
"bench:privacy-recall:compare-lineage": "node ../bench/privacy-recall/compare-lineage.mjs",
|
|
128
134
|
"bench:privacy-recall:check": "node ../bench/privacy-recall/check.mjs",
|
|
129
135
|
"bench:privacy-recall:update-baseline": "node ../bench/privacy-recall/check.mjs --update-baseline",
|
|
130
136
|
"bench:self-scan:update-baseline": "node ../bench/self-scan/check.mjs --update-baseline",
|
|
131
137
|
"bench:engine-recall": "node ../bench/engine-recall/measure.mjs",
|
|
132
138
|
"scorecard": "node ../scripts/scorecard.mjs",
|
|
133
139
|
"check-doc-drift": "node ../scripts/check-doc-drift.mjs",
|
|
140
|
+
"docs:verify-examples": "node ../scripts/verify-doc-examples.mjs",
|
|
134
141
|
"harness-score": "node ../scripts/harness-score.cjs",
|
|
135
142
|
"corpus:enroll": "node ../scripts/enroll-proven-finding.mjs",
|
|
136
143
|
"corpus:provenance": "node ../scripts/corpus-provenance-check.mjs",
|
package/src/dataflow/CLAUDE.md
CHANGED
|
@@ -6,7 +6,7 @@ Layer-2 taint engine. Walks the Layer-1 IR (`../ir/`) with field-sensitive forwa
|
|
|
6
6
|
|
|
7
7
|
- **Intra-procedural field-sensitive taint** with access-path lattice (`access-paths.js`). `user.email` is distinguishable from `user.password`.
|
|
8
8
|
- **Value-context-sensitive interprocedural taint (FR-SEM-2).** `SummaryCache` (`summaries.js`) holds a distinct summary per distinct entry-taint-state. A pre-pass computes the empty-entry base for every function; call sites then lazily compute the summary under their actual tainted-arg context (at both assign-from-call and plain-call sites) so a helper that is clean with clean args but tainted with user input is detected per call site. Bounded by a per-function context cap (`AGENTIC_SECURITY_KCFA_MAX_CONTEXTS`, default 16; 0 = monovariant). Over the cap → reuse the empty-entry summary.
|
|
9
|
-
- **Catalog-driven source/sink matching.** Add entries in `catalog.js`. Each entry: `kind` ∈ {source, sink, sanitizer}, plus language + framework + match shape. `match.type` ∈ {`call`, `member`, `global`, `annotation`} — 655 entries (149 source, 124 sink, 382 sanitizer — re-derive via `CATALOG.length` / a per-`kind` count rather than trusting a hardcoded number here again; this has already drifted once) spanning Express/Flask/FastAPI/Django/Rails/PHP/Go-net-http/Gin/Echo.
|
|
9
|
+
- **Catalog-driven source/sink matching.** Add entries in `catalog.js`. Each entry: `kind` ∈ {source, sink, sanitizer}, plus language + framework + match shape. `match.type` ∈ {`call`, `member`, `global`, `annotation`} — 655 entries (149 source, 124 sink, 382 sanitizer — re-derive via `CATALOG.length` / a per-`kind` count rather than trusting a hardcoded number here again; this has already drifted once) **— and it has now drifted a SECOND time: as of 2026-08-31 the real figures are 756 (180 source, 194 sink, 382 sanitizer). See `../lineage/DESIGN_REGISTRIES.md` §7.3 item 1 — originally measured and pinned by the design-phase PoC, since deleted; the 180-source and 194-sink figures are now pinned as shipped, permanent equality tests in the lineage package's own source-registry.test.js and sink-registry.test.js (see `../lineage/CLAUDE.md`'s module table for their exact paths). The stale numbers are left in place above rather than hand-patched a third time, because nothing in this file can keep them true; trust `CATALOG.length`, not this sentence — and it HAS drifted a third time already, predictably: Sub-project H's AC-07 closure (2026-08-31) added 4 sink entries, so the real sink-entry count is now 198, not 194** — spanning Express/Flask/FastAPI/Django/Rails/PHP/Go-net-http/Gin/Echo.
|
|
10
10
|
- **`match.type: 'call'`/`'member'`/`'global'`** are matched against an *expression* the taint-walker encounters while visiting a CFG node (`matchSource` / `matchSinkOrSanitizer`) — `call` against a call expression's callee, `member` against a property-access chain (`match.object` + `match.prop`), `global` against a bare identifier read.
|
|
11
11
|
- **`match.type: 'annotation'`** (R14(a): Spring `@RequestParam`/`@PathVariable`/`@RequestBody`/`@RequestHeader`, ASP.NET Core `[FromQuery]`/`[FromBody]`/`[FromForm]`/`[FromRoute]`/`[FromHeader]`, NestJS `@Query()`/`@Body()`/`@Param()`/`@Headers()`) works differently from the other three, and this is the one fact worth internalizing before touching it: **it is not consulted during the CFG walk.** There is no CFG node for "this function's own declared parameter list." Instead `matchAnnotationParams` (`catalog.js`) is called once per function — by `engine.js`'s `_unionAnnotationTaint`, before `analyzeFunction` runs — against the IR's `fn.paramAnnotations` side-channel (`{index, name, decorator}[]`, populated by `parser-cs.js`/`parser-js.js`/`parser-java.js`; see `../ir/CLAUDE.md`), and the resulting tainted param names are unioned into the entry taint-state for that function/call-site. A reader who assumes `annotation` entries get matched against expressions mid-walk, the way `call`/`member`/`global` do, will be wrong.
|
|
12
12
|
- **Sanitizer entries are RECORDED, never trusted to kill taint.** `_sanitizersForExpr()` collects the sanitizer callees applied to the value reaching each sink argument — inline in the argument, or inherited from the variable it reads (`_sanitizersByVar`, updated on every assignment and cleared when the RHS is clean). They are stamped on the finding as `_sanitizersOnPath` and consumed by `sanitizer-gate.js`, which sets `sanitized` + `sanitizerProof` **only when the sanitizer's `appliesTo` family covers the finding's threat class** (`*` covers everything). The proof gate then demotes. Taint itself still dies only on clean re-assignment (`removePathAndDescendants`).
|
package/src/dataflow/catalog.js
CHANGED
|
@@ -606,6 +606,48 @@ export const CATALOG = [
|
|
|
606
606
|
vuln: { name: 'SSRF (axios/http.get)', severity: 'high', cwe: 'CWE-918',
|
|
607
607
|
remediation: 'Validate the target URL against an allow-list before fetching; reject RFC1918 + metadata endpoints.' } },
|
|
608
608
|
|
|
609
|
+
// ─── SINKS (AI model provider) ────────────────────────────────────────────
|
|
610
|
+
// AC-07 closure (Data Flow Explorer, Sub-project H). Regulated data
|
|
611
|
+
// (PCI/PHI/PII) reaching a hosted third-party AI model provider is a real
|
|
612
|
+
// data-exposure concern the same way any other third-party API call is —
|
|
613
|
+
// CWE-201 (Insertion of Sensitive Information Into Sent Data), NOT CWE-359
|
|
614
|
+
// (reserved exclusively for privacy-catalog.js's own "Privacy Leak" family
|
|
615
|
+
// — sink-registry.js's completeness/1c test enforces this).
|
|
616
|
+
//
|
|
617
|
+
// Precision comes from `receiver`/`receiverBase`: CALLEE_INDEX is keyed on
|
|
618
|
+
// the bare name `create`, so every `X.create(...)` in the tree is a
|
|
619
|
+
// candidate. Every receiver-bearing entry below constrains BOTH the
|
|
620
|
+
// property chain AND the receiver's own name/alias — `receiver` alone
|
|
621
|
+
// (checked via `_receiverAllowed`'s `.some()` over the whole member
|
|
622
|
+
// chain) is not enough: a first cut of `js-anthropic-messages-create`/
|
|
623
|
+
// `js-openai-responses-create` shipped with only `receiver` set, and a
|
|
624
|
+
// task review found it matched ordinary `db.messages.create()`/
|
|
625
|
+
// `prisma.messages.create()` (Sequelize/Prisma's idiomatic row-insert
|
|
626
|
+
// shape) — a real false-attribution SAST finding, not a hypothetical.
|
|
627
|
+
// `receiverBase: '^chat$'` on the OpenAI chat-completions entry is what
|
|
628
|
+
// separates it from the legacy `anthropic.completions.create` shape
|
|
629
|
+
// (deliberately not cataloged here — AC-07 names only OpenAI/Anthropic/
|
|
630
|
+
// Bedrock).
|
|
631
|
+
{ kind: 'sink', id: 'js-openai-chat-completions-create', language: 'js', framework: 'openai',
|
|
632
|
+
match: { type: 'call', callee: 'create', receiver: '^completions$', receiverBase: '^chat$' }, argIndex: 0,
|
|
633
|
+
vuln: { name: 'Regulated Data to AI Model Provider (OpenAI chat.completions.create)', severity: 'medium', cwe: 'CWE-201',
|
|
634
|
+
remediation: 'Confirm the request payload carries no PCI/PHI/PII before sending to a third-party model provider, or route through an approved DPA / redaction layer.' } },
|
|
635
|
+
{ kind: 'sink', id: 'js-openai-responses-create', language: 'js', framework: 'openai',
|
|
636
|
+
match: { type: 'call', callee: 'create', receiver: '^responses$', receiverBase: '^(?:openai|client|oai)$' }, argIndex: 0,
|
|
637
|
+
vuln: { name: 'Regulated Data to AI Model Provider (OpenAI responses.create)', severity: 'medium', cwe: 'CWE-201',
|
|
638
|
+
remediation: 'Confirm the request payload carries no PCI/PHI/PII before sending to a third-party model provider, or route through an approved DPA / redaction layer.' } },
|
|
639
|
+
{ kind: 'sink', id: 'js-anthropic-messages-create', language: 'js', framework: 'anthropic',
|
|
640
|
+
match: { type: 'call', callee: 'create', receiver: '^messages$', receiverBase: '^(?:anthropic|client|claude)$' }, argIndex: 0,
|
|
641
|
+
vuln: { name: 'Regulated Data to AI Model Provider (Anthropic messages.create)', severity: 'medium', cwe: 'CWE-201',
|
|
642
|
+
remediation: 'Confirm the request payload carries no PCI/PHI/PII before sending to a third-party model provider, or route through an approved DPA / redaction layer.' } },
|
|
643
|
+
// Bare, constructor-shaped call with no fixed receiver — safe to match on the
|
|
644
|
+
// bare name alone, the same precedent `js-fetch` already uses, because
|
|
645
|
+
// `InvokeModelCommand` is a distinctive, unambiguous identifier.
|
|
646
|
+
{ kind: 'sink', id: 'js-bedrock-invoke-model-command', language: 'js', framework: 'bedrock',
|
|
647
|
+
match: { type: 'call', callee: 'InvokeModelCommand' }, argIndex: 0,
|
|
648
|
+
vuln: { name: 'Regulated Data to AI Model Provider (AWS Bedrock InvokeModelCommand)', severity: 'medium', cwe: 'CWE-201',
|
|
649
|
+
remediation: 'Confirm the request payload carries no PCI/PHI/PII before sending to a third-party model provider, or route through an approved DPA / redaction layer.' } },
|
|
650
|
+
|
|
609
651
|
// ─── SINKS (command exec) ─────────────────────────────────────────────────
|
|
610
652
|
{ kind: 'sink', id: 'py-subprocess-run', language: 'py', framework: 'subprocess', match: { type: 'call', callee: 'run', requireKeyword: { name: 'shell', pattern: '^(?:true|True|1)$' } }, argIndex: 0,
|
|
611
653
|
vuln: { name: 'Command Injection (subprocess.run shell=True)', severity: 'critical', cwe: 'CWE-78',
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// Milestone 2, Sub-project E, increment 1 (ORM-write sink recognition).
|
|
2
|
+
// Per docs/superpowers/plans/2026-08-31-data-flow-explorer-m2-subproject-e1-plan.md
|
|
3
|
+
// and its own referenced scoping doc's Finding 3 (the precision-mechanism
|
|
4
|
+
// gap): a catalog of ORM row-write call shapes (`Model.create({...})`,
|
|
5
|
+
// `Model.save({...})`, `Model.update({...})`, `Model.upsert({...})`) for
|
|
6
|
+
// `src/lineage/`'s Data Flow Explorer only.
|
|
7
|
+
//
|
|
8
|
+
// DELIBERATELY NOT ADDED TO `dataflow/catalog.js`'s own `CATALOG`, and NOT
|
|
9
|
+
// wired into `matchSinkOrSanitizer`/`runTaintEngine` — the exact same
|
|
10
|
+
// isolation reasoning `privacy-catalog.js`'s own header comment gives for
|
|
11
|
+
// itself (see that file, lines 12-32), reapplied here for a stronger
|
|
12
|
+
// reason: `CATALOG` is a shared, always-active singleton consulted for
|
|
13
|
+
// EVERY scan, with no per-family filtering, so merging these entries in
|
|
14
|
+
// would make every already-tainted general source (`req.body`, etc.)
|
|
15
|
+
// immediately produce a new, unreviewed SAST finding class the moment it
|
|
16
|
+
// reached an ORM `.create()`/`.save()`/`.update()`/`.upsert()` call — a
|
|
17
|
+
// real, unintended expansion of the general SAST pipeline's output as a
|
|
18
|
+
// side effect of a Data Flow Explorer feature, not something this
|
|
19
|
+
// increment is chartered to decide. Unlike `privacy-catalog.js` (which
|
|
20
|
+
// shares its entry shape with something that COULD wire into `CATALOG`
|
|
21
|
+
// later), this catalog's own precision gate — "the call's first argument
|
|
22
|
+
// must be an object-literal expression" — cannot be expressed inside
|
|
23
|
+
// `matchSinkOrSanitizer`'s existing `(calleeExpr, file, receiverType)`
|
|
24
|
+
// signature at all, since that signature never receives the call's
|
|
25
|
+
// arguments. Making that check work requires a caller with `site.args`
|
|
26
|
+
// (`src/lineage/graph-builder.js`'s own site enumeration), so the
|
|
27
|
+
// isolation here is closer to structural than a mere policy choice.
|
|
28
|
+
//
|
|
29
|
+
// Keeping this catalog in its own file, imported ONLY by `src/lineage/`'s
|
|
30
|
+
// own registry/graph-builder modules, is what makes it genuinely inert to
|
|
31
|
+
// every other scan surface.
|
|
32
|
+
//
|
|
33
|
+
// TWO signals gate a real match, and only one lives in this file:
|
|
34
|
+
// 1. Callee shape (HERE, in `ORM_WRITE_CATALOG` + `matchOrmWrite`):
|
|
35
|
+
// method name is one of create/save/update/upsert, receiver is a
|
|
36
|
+
// BARE, CAPITALIZED identifier (`^[A-Z]\w*$`) — the SAME shape
|
|
37
|
+
// `sast/mass-assignment.js` (line 27) and `posture/cross-lang-orm.js`
|
|
38
|
+
// (`findOrmWrites`) already use in production as real SAST
|
|
39
|
+
// detectors; this is not a new or untested heuristic, it is the
|
|
40
|
+
// established one, reused here for a lower-stakes (candidate-tier,
|
|
41
|
+
// disclosed) purpose than either of those two modules' own
|
|
42
|
+
// full-confidence findings.
|
|
43
|
+
// 2. Argument shape (NOT here — lineage-side, in `graph-builder.js`'s
|
|
44
|
+
// site enumeration): the matched call's first argument must be an
|
|
45
|
+
// object-literal expression (`kind: 'object'`). A call whose first
|
|
46
|
+
// argument is not an object literal (a bare variable, a spread, a
|
|
47
|
+
// positional string — e.g. `User.create(req.body)`) never becomes an
|
|
48
|
+
// ORM-write sink candidate at all; this file cannot express that gate
|
|
49
|
+
// itself, since `matchOrmWrite`'s signature (mirroring
|
|
50
|
+
// `matchPrivacySink`'s) never receives the call's arguments.
|
|
51
|
+
//
|
|
52
|
+
// `coverageStatus` for every site this catalog recognizes is the literal
|
|
53
|
+
// string 'candidate', unconditionally, computed nowhere — see
|
|
54
|
+
// `sink-registry.js`'s `reclassifyOrmWrite`. Even with both signals
|
|
55
|
+
// present, this is real, disclosed uncertainty: an arbitrary
|
|
56
|
+
// capitalized-identifier receiver could still be a non-ORM builder
|
|
57
|
+
// pattern that happens to take an object-literal argument.
|
|
58
|
+
//
|
|
59
|
+
// Scope boundary, disclosed rather than silently assumed: JS/TS only.
|
|
60
|
+
// Python/Java/Go/Ruby/PHP ORM shapes (Django `.objects.create()`, GORM,
|
|
61
|
+
// ActiveRecord, Eloquent) are real, common shapes this catalog does not
|
|
62
|
+
// recognize — out of scope for this increment, per the plan's own
|
|
63
|
+
// "Explicitly deferred" list. Table/column/operation extraction, and
|
|
64
|
+
// Prisma's distinctive `data: {...}` wrapper form's own precise handling,
|
|
65
|
+
// are likewise deferred (the object-literal-argument check as specified
|
|
66
|
+
// sees Prisma's OUTER `{ data: {...} }` literal and passes, which is
|
|
67
|
+
// consistent for the callee-match gate, but this file makes no claim
|
|
68
|
+
// about extracting the inner Prisma shape — that's E2's job).
|
|
69
|
+
//
|
|
70
|
+
// `category: 'database'` reuses the existing `SINK_CATEGORIES` value
|
|
71
|
+
// (schema.js) rather than minting a new `orm-write`-style category — a
|
|
72
|
+
// genuine, lower-confidence detection of the same kind of destination a
|
|
73
|
+
// raw-SQL sink already models. Whether a dedicated category is warranted
|
|
74
|
+
// is an open question left to a future increment, not decided here.
|
|
75
|
+
|
|
76
|
+
import { _languageFamilyExtensions } from './catalog.js';
|
|
77
|
+
|
|
78
|
+
// The method-name vocabulary is verified against `cross-lang-orm.js`'s own
|
|
79
|
+
// `findOrmWrites` regex (`create|save|update|build|insert|upsert`) and
|
|
80
|
+
// `mass-assignment.js`'s own JS pattern (`create|update|build|save`) —
|
|
81
|
+
// this catalog uses the plan's suggested starting set (create/save/update/
|
|
82
|
+
// upsert), a subset of both, not the full union: `build`/`insert` are
|
|
83
|
+
// real ORM-adjacent method names too, but the plan's own "starting point,
|
|
84
|
+
// not a mandate" framing leaves widening this list to a future increment.
|
|
85
|
+
export const ORM_WRITE_CATALOG = [
|
|
86
|
+
{ kind: 'sink', id: 'orm-write-js-create', language: 'js', framework: 'orm', category: 'database',
|
|
87
|
+
match: { type: 'call', callee: 'create' }, argIndex: 0,
|
|
88
|
+
vuln: { name: 'ORM Write (create)', severity: 'info', cwe: null,
|
|
89
|
+
remediation: 'Heuristic ORM row-write recognition for the Data Flow Explorer only — not a SAST finding. No remediation is implied.' } },
|
|
90
|
+
{ kind: 'sink', id: 'orm-write-js-save', language: 'js', framework: 'orm', category: 'database',
|
|
91
|
+
match: { type: 'call', callee: 'save' }, argIndex: 0,
|
|
92
|
+
vuln: { name: 'ORM Write (save)', severity: 'info', cwe: null,
|
|
93
|
+
remediation: 'Heuristic ORM row-write recognition for the Data Flow Explorer only — not a SAST finding. No remediation is implied.' } },
|
|
94
|
+
{ kind: 'sink', id: 'orm-write-js-update', language: 'js', framework: 'orm', category: 'database',
|
|
95
|
+
match: { type: 'call', callee: 'update' }, argIndex: 0,
|
|
96
|
+
vuln: { name: 'ORM Write (update)', severity: 'info', cwe: null,
|
|
97
|
+
remediation: 'Heuristic ORM row-write recognition for the Data Flow Explorer only — not a SAST finding. No remediation is implied.' } },
|
|
98
|
+
{ kind: 'sink', id: 'orm-write-js-upsert', language: 'js', framework: 'orm', category: 'database',
|
|
99
|
+
match: { type: 'call', callee: 'upsert' }, argIndex: 0,
|
|
100
|
+
vuln: { name: 'ORM Write (upsert)', severity: 'info', cwe: null,
|
|
101
|
+
remediation: 'Heuristic ORM row-write recognition for the Data Flow Explorer only — not a SAST finding. No remediation is implied.' } },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
function _ormLanguageAllowed(entry, file) {
|
|
105
|
+
if (!file) return true;
|
|
106
|
+
const res = _languageFamilyExtensions(entry.language);
|
|
107
|
+
if (!res.length) return true; // unmapped language stays permissive
|
|
108
|
+
return res.some((re) => re.test(file));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Small, local copy of the callee-name extraction shape `privacy-catalog.js`'s
|
|
112
|
+
// own `_privacyCalleeNames` establishes — not imported from that file (it's
|
|
113
|
+
// private/unexported there), matching this package's established precedent
|
|
114
|
+
// of a small local duplicate over an awkward cross-module dependency on
|
|
115
|
+
// another module's private helper (see `src/lineage/handling-analyzer.js`'s
|
|
116
|
+
// own disclosed `calleeDescriptorOf` duplicate).
|
|
117
|
+
function _ormCalleeNames(calleeExpr) {
|
|
118
|
+
let last = null;
|
|
119
|
+
let full = null;
|
|
120
|
+
if (typeof calleeExpr === 'string') {
|
|
121
|
+
full = calleeExpr;
|
|
122
|
+
last = calleeExpr.includes('.') ? calleeExpr.slice(calleeExpr.lastIndexOf('.') + 1) : calleeExpr;
|
|
123
|
+
} else if (calleeExpr && calleeExpr.kind === 'member' && calleeExpr.prop) {
|
|
124
|
+
last = calleeExpr.prop;
|
|
125
|
+
if (calleeExpr.object && calleeExpr.object.kind === 'ident') full = `${calleeExpr.object.name}.${calleeExpr.prop}`;
|
|
126
|
+
} else if (calleeExpr && calleeExpr.kind === 'ident') {
|
|
127
|
+
last = calleeExpr.name || null;
|
|
128
|
+
}
|
|
129
|
+
return { last, full };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Bare, capitalized receiver identifier — a SHAPE regex on the receiver's
|
|
133
|
+
// own name, not a `receiverTypeIn` exact-alias lookup (unrelated to the
|
|
134
|
+
// IR's CHA-resolved `receiverType`). Only a `kind: 'member'` calleeExpr
|
|
135
|
+
// whose `object` is itself a plain `kind: 'ident'` can satisfy this — a
|
|
136
|
+
// computed or chained receiver (`db.models.User.create(...)`) does not,
|
|
137
|
+
// by design (the same conservative shape `mass-assignment.js`/
|
|
138
|
+
// `cross-lang-orm.js` already use in production).
|
|
139
|
+
const CAPITALIZED_IDENT_RE = /^[A-Z]\w*$/;
|
|
140
|
+
|
|
141
|
+
function _ormReceiverIsCapitalizedIdent(calleeExpr) {
|
|
142
|
+
return Boolean(
|
|
143
|
+
calleeExpr && typeof calleeExpr === 'object' &&
|
|
144
|
+
calleeExpr.kind === 'member' &&
|
|
145
|
+
calleeExpr.object && calleeExpr.object.kind === 'ident' &&
|
|
146
|
+
typeof calleeExpr.object.name === 'string' &&
|
|
147
|
+
CAPITALIZED_IDENT_RE.test(calleeExpr.object.name),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Signal 1 only (callee shape) — the argument-shape signal (signal 2) is
|
|
153
|
+
* NOT checked here; see this file's own header for why it structurally
|
|
154
|
+
* cannot be. Mirrors `matchPrivacySink`'s `(calleeExpr, file, receiverType)`
|
|
155
|
+
* contract, minus the unused third parameter (this catalog's receiver
|
|
156
|
+
* constraint is a name-shape regex, not a `receiverTypeIn` lookup, so no
|
|
157
|
+
* `receiverType` input is ever consulted). Returns an array of hits, or
|
|
158
|
+
* `null` — same "array of hits, or null" contract `matchSinkOrSanitizer`/
|
|
159
|
+
* `matchPrivacySink` already establish.
|
|
160
|
+
*/
|
|
161
|
+
export function matchOrmWrite(calleeExpr, file) {
|
|
162
|
+
if (!calleeExpr) return null;
|
|
163
|
+
if (!_ormReceiverIsCapitalizedIdent(calleeExpr)) return null;
|
|
164
|
+
const { last, full } = _ormCalleeNames(calleeExpr);
|
|
165
|
+
if (!last && !full) return null;
|
|
166
|
+
const hits = ORM_WRITE_CATALOG.filter((e) => {
|
|
167
|
+
if (!e || e.kind !== 'sink') return false;
|
|
168
|
+
const cName = e.match && e.match.callee;
|
|
169
|
+
if (!cName) return false;
|
|
170
|
+
if (cName !== last && cName !== full) return false;
|
|
171
|
+
if (!_ormLanguageAllowed(e, file)) return false;
|
|
172
|
+
return true;
|
|
173
|
+
});
|
|
174
|
+
return hits.length ? hits : null;
|
|
175
|
+
}
|