@opensip-cli/external-tool-adapter 0.1.15

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.
Files changed (172) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +33 -0
  4. package/dist/__tests__/acceptance-harness.test.d.ts +2 -0
  5. package/dist/__tests__/acceptance-harness.test.d.ts.map +1 -0
  6. package/dist/__tests__/acceptance-harness.test.js +106 -0
  7. package/dist/__tests__/acceptance-harness.test.js.map +1 -0
  8. package/dist/__tests__/artifact-path.test.d.ts +2 -0
  9. package/dist/__tests__/artifact-path.test.d.ts.map +1 -0
  10. package/dist/__tests__/artifact-path.test.js +19 -0
  11. package/dist/__tests__/artifact-path.test.js.map +1 -0
  12. package/dist/__tests__/binary-resolver.test.d.ts +2 -0
  13. package/dist/__tests__/binary-resolver.test.d.ts.map +1 -0
  14. package/dist/__tests__/binary-resolver.test.js +64 -0
  15. package/dist/__tests__/binary-resolver.test.js.map +1 -0
  16. package/dist/__tests__/define-external-tool-adapter.test.d.ts +2 -0
  17. package/dist/__tests__/define-external-tool-adapter.test.d.ts.map +1 -0
  18. package/dist/__tests__/define-external-tool-adapter.test.js +165 -0
  19. package/dist/__tests__/define-external-tool-adapter.test.js.map +1 -0
  20. package/dist/__tests__/doctor-command.test.d.ts +2 -0
  21. package/dist/__tests__/doctor-command.test.d.ts.map +1 -0
  22. package/dist/__tests__/doctor-command.test.js +124 -0
  23. package/dist/__tests__/doctor-command.test.js.map +1 -0
  24. package/dist/__tests__/exit-model.test.d.ts +2 -0
  25. package/dist/__tests__/exit-model.test.d.ts.map +1 -0
  26. package/dist/__tests__/exit-model.test.js +30 -0
  27. package/dist/__tests__/exit-model.test.js.map +1 -0
  28. package/dist/__tests__/fingerprint.test.d.ts +2 -0
  29. package/dist/__tests__/fingerprint.test.d.ts.map +1 -0
  30. package/dist/__tests__/fingerprint.test.js +39 -0
  31. package/dist/__tests__/fingerprint.test.js.map +1 -0
  32. package/dist/__tests__/gate-render.test.d.ts +2 -0
  33. package/dist/__tests__/gate-render.test.d.ts.map +1 -0
  34. package/dist/__tests__/gate-render.test.js +82 -0
  35. package/dist/__tests__/gate-render.test.js.map +1 -0
  36. package/dist/__tests__/ingest-json.test.d.ts +2 -0
  37. package/dist/__tests__/ingest-json.test.d.ts.map +1 -0
  38. package/dist/__tests__/ingest-json.test.js +53 -0
  39. package/dist/__tests__/ingest-json.test.js.map +1 -0
  40. package/dist/__tests__/ingest-sarif.test.d.ts +2 -0
  41. package/dist/__tests__/ingest-sarif.test.d.ts.map +1 -0
  42. package/dist/__tests__/ingest-sarif.test.js +283 -0
  43. package/dist/__tests__/ingest-sarif.test.js.map +1 -0
  44. package/dist/__tests__/manifest-commands.test.d.ts +2 -0
  45. package/dist/__tests__/manifest-commands.test.d.ts.map +1 -0
  46. package/dist/__tests__/manifest-commands.test.js +67 -0
  47. package/dist/__tests__/manifest-commands.test.js.map +1 -0
  48. package/dist/__tests__/provenance.test.d.ts +2 -0
  49. package/dist/__tests__/provenance.test.d.ts.map +1 -0
  50. package/dist/__tests__/provenance.test.js +48 -0
  51. package/dist/__tests__/provenance.test.js.map +1 -0
  52. package/dist/__tests__/redact.test.d.ts +2 -0
  53. package/dist/__tests__/redact.test.d.ts.map +1 -0
  54. package/dist/__tests__/redact.test.js +37 -0
  55. package/dist/__tests__/redact.test.js.map +1 -0
  56. package/dist/__tests__/run-loop-artifact.test.d.ts +21 -0
  57. package/dist/__tests__/run-loop-artifact.test.d.ts.map +1 -0
  58. package/dist/__tests__/run-loop-artifact.test.js +186 -0
  59. package/dist/__tests__/run-loop-artifact.test.js.map +1 -0
  60. package/dist/__tests__/run-loop-exit.test.d.ts +21 -0
  61. package/dist/__tests__/run-loop-exit.test.d.ts.map +1 -0
  62. package/dist/__tests__/run-loop-exit.test.js +123 -0
  63. package/dist/__tests__/run-loop-exit.test.js.map +1 -0
  64. package/dist/__tests__/run-loop-gate.test.d.ts +10 -0
  65. package/dist/__tests__/run-loop-gate.test.d.ts.map +1 -0
  66. package/dist/__tests__/run-loop-gate.test.js +159 -0
  67. package/dist/__tests__/run-loop-gate.test.js.map +1 -0
  68. package/dist/__tests__/session-payload.test.d.ts +12 -0
  69. package/dist/__tests__/session-payload.test.d.ts.map +1 -0
  70. package/dist/__tests__/session-payload.test.js +131 -0
  71. package/dist/__tests__/session-payload.test.js.map +1 -0
  72. package/dist/__tests__/severity-map.test.d.ts +2 -0
  73. package/dist/__tests__/severity-map.test.d.ts.map +1 -0
  74. package/dist/__tests__/severity-map.test.js +57 -0
  75. package/dist/__tests__/severity-map.test.js.map +1 -0
  76. package/dist/acceptance-harness.d.ts +48 -0
  77. package/dist/acceptance-harness.d.ts.map +1 -0
  78. package/dist/acceptance-harness.js +78 -0
  79. package/dist/acceptance-harness.js.map +1 -0
  80. package/dist/adapter-config.d.ts +58 -0
  81. package/dist/adapter-config.d.ts.map +1 -0
  82. package/dist/adapter-config.js +73 -0
  83. package/dist/adapter-config.js.map +1 -0
  84. package/dist/adapter-manifest.d.ts +57 -0
  85. package/dist/adapter-manifest.d.ts.map +1 -0
  86. package/dist/adapter-manifest.js +68 -0
  87. package/dist/adapter-manifest.js.map +1 -0
  88. package/dist/artifact-path.d.ts +26 -0
  89. package/dist/artifact-path.d.ts.map +1 -0
  90. package/dist/artifact-path.js +22 -0
  91. package/dist/artifact-path.js.map +1 -0
  92. package/dist/binary-resolver.d.ts +51 -0
  93. package/dist/binary-resolver.d.ts.map +1 -0
  94. package/dist/binary-resolver.js +66 -0
  95. package/dist/binary-resolver.js.map +1 -0
  96. package/dist/define-external-tool-adapter.d.ts +25 -0
  97. package/dist/define-external-tool-adapter.d.ts.map +1 -0
  98. package/dist/define-external-tool-adapter.js +149 -0
  99. package/dist/define-external-tool-adapter.js.map +1 -0
  100. package/dist/doctor-command.d.ts +81 -0
  101. package/dist/doctor-command.d.ts.map +1 -0
  102. package/dist/doctor-command.js +160 -0
  103. package/dist/doctor-command.js.map +1 -0
  104. package/dist/exit-model.d.ts +33 -0
  105. package/dist/exit-model.d.ts.map +1 -0
  106. package/dist/exit-model.js +35 -0
  107. package/dist/exit-model.js.map +1 -0
  108. package/dist/fingerprint.d.ts +26 -0
  109. package/dist/fingerprint.d.ts.map +1 -0
  110. package/dist/fingerprint.js +32 -0
  111. package/dist/fingerprint.js.map +1 -0
  112. package/dist/gate-render.d.ts +18 -0
  113. package/dist/gate-render.d.ts.map +1 -0
  114. package/dist/gate-render.js +25 -0
  115. package/dist/gate-render.js.map +1 -0
  116. package/dist/index.d.ts +39 -0
  117. package/dist/index.d.ts.map +1 -0
  118. package/dist/index.js +35 -0
  119. package/dist/index.js.map +1 -0
  120. package/dist/ingest-json.d.ts +32 -0
  121. package/dist/ingest-json.d.ts.map +1 -0
  122. package/dist/ingest-json.js +66 -0
  123. package/dist/ingest-json.js.map +1 -0
  124. package/dist/ingest-sarif.d.ts +113 -0
  125. package/dist/ingest-sarif.d.ts.map +1 -0
  126. package/dist/ingest-sarif.js +158 -0
  127. package/dist/ingest-sarif.js.map +1 -0
  128. package/dist/manifest-commands.d.ts +23 -0
  129. package/dist/manifest-commands.d.ts.map +1 -0
  130. package/dist/manifest-commands.js +47 -0
  131. package/dist/manifest-commands.js.map +1 -0
  132. package/dist/process-exec.d.ts +51 -0
  133. package/dist/process-exec.d.ts.map +1 -0
  134. package/dist/process-exec.js +99 -0
  135. package/dist/process-exec.js.map +1 -0
  136. package/dist/provenance.d.ts +19 -0
  137. package/dist/provenance.d.ts.map +1 -0
  138. package/dist/provenance.js +31 -0
  139. package/dist/provenance.js.map +1 -0
  140. package/dist/redact.d.ts +24 -0
  141. package/dist/redact.d.ts.map +1 -0
  142. package/dist/redact.js +38 -0
  143. package/dist/redact.js.map +1 -0
  144. package/dist/run-context.d.ts +24 -0
  145. package/dist/run-context.d.ts.map +1 -0
  146. package/dist/run-context.js +36 -0
  147. package/dist/run-context.js.map +1 -0
  148. package/dist/run-loop.d.ts +64 -0
  149. package/dist/run-loop.d.ts.map +1 -0
  150. package/dist/run-loop.js +320 -0
  151. package/dist/run-loop.js.map +1 -0
  152. package/dist/scan-emit.d.ts +81 -0
  153. package/dist/scan-emit.d.ts.map +1 -0
  154. package/dist/scan-emit.js +125 -0
  155. package/dist/scan-emit.js.map +1 -0
  156. package/dist/session-payload.d.ts +81 -0
  157. package/dist/session-payload.d.ts.map +1 -0
  158. package/dist/session-payload.js +86 -0
  159. package/dist/session-payload.js.map +1 -0
  160. package/dist/severity-map.d.ts +43 -0
  161. package/dist/severity-map.d.ts.map +1 -0
  162. package/dist/severity-map.js +84 -0
  163. package/dist/severity-map.js.map +1 -0
  164. package/dist/types.d.ts +228 -0
  165. package/dist/types.d.ts.map +1 -0
  166. package/dist/types.js +15 -0
  167. package/dist/types.js.map +1 -0
  168. package/dist/version-command.d.ts +36 -0
  169. package/dist/version-command.d.ts.map +1 -0
  170. package/dist/version-command.js +74 -0
  171. package/dist/version-command.js.map +1 -0
  172. package/package.json +52 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * session-payload — the adapter-owned, dashboard-shaped session detail blob
3
+ * (A2: an adapter session must carry `summary` + grouped `checks[]` so the HTML
4
+ * report renders a secret/vuln scan's findings instead of falsely "clean").
5
+ *
6
+ * Proves the grouped shape AND the secret-hygiene invariant: every field is
7
+ * copied from an already-redacted signal, and `metadata` is narrowed to JSON
8
+ * scalars (the nested provenance object is dropped) — so NO raw credential reaches
9
+ * the persisted payload.
10
+ */
11
+ import { createSignal } from '@opensip-cli/core';
12
+ import { describe, expect, it } from 'vitest';
13
+ import { buildAdapterSessionPayload } from '../session-payload.js';
14
+ /** A `high`-severity (error-rung) secret signal carrying ONLY a redacted preview. */
15
+ function leakSignal(overrides = {}) {
16
+ return createSignal({
17
+ source: 'gitleaks',
18
+ category: 'security',
19
+ severity: 'high',
20
+ ruleId: 'aws-access-token',
21
+ message: 'AWS Access Key',
22
+ code: { file: 'config/prod.env', line: 12, column: 19 },
23
+ // The provenance object + a redacted scalar preview — the raw secret is NEVER
24
+ // present (the ingest parser masked it). The provenance object must be dropped.
25
+ metadata: {
26
+ secretPreview: 'AKIA…',
27
+ entropy: 3.65,
28
+ provenance: { tool: 'gitleaks', adapterPackage: '@opensip-cli/tool-gitleaks' },
29
+ },
30
+ ...overrides,
31
+ });
32
+ }
33
+ describe('buildAdapterSessionPayload', () => {
34
+ it('groups signals by ruleId into checks[] with a populated summary (NOT clean)', () => {
35
+ const payload = buildAdapterSessionPayload([
36
+ leakSignal(),
37
+ leakSignal({ ruleId: 'aws-access-token', code: { file: 'a.env', line: 3 } }),
38
+ leakSignal({
39
+ ruleId: 'stripe-token',
40
+ message: 'Stripe Token',
41
+ code: { file: 'b.ts', line: 9 },
42
+ }),
43
+ ]);
44
+ expect(payload.__version).toBe(1);
45
+ // Two distinct rules → two checks; the aws rule grouped both occurrences.
46
+ expect(payload.checks).toHaveLength(2);
47
+ const aws = payload.checks.find((c) => c.checkSlug === 'aws-access-token');
48
+ expect(aws?.violationCount).toBe(2);
49
+ expect(aws?.findings).toHaveLength(2);
50
+ expect(aws?.passed).toBe(false); // error-rung findings ⇒ the rule failed
51
+ // The summary the dashboard reads for its clean/dirty decision — NOT clean.
52
+ expect(payload.summary).toEqual({
53
+ total: 2, // rules that fired
54
+ passed: 0,
55
+ failed: 2,
56
+ errors: 3, // high-severity signal count
57
+ warnings: 0,
58
+ });
59
+ // The dashboard's `clean = errors === 0 && warnings === 0` is therefore FALSE.
60
+ expect(payload.summary.errors === 0 && payload.summary.warnings === 0).toBe(false);
61
+ });
62
+ it('collapses 4-level severity to the dashboard 2-level bucket and marks a warning rule passed', () => {
63
+ const payload = buildAdapterSessionPayload([
64
+ leakSignal({ ruleId: 'low-rule', severity: 'low', message: 'minor' }),
65
+ ]);
66
+ const check = payload.checks[0];
67
+ expect(check?.findings[0]?.severity).toBe('warning');
68
+ // A rule with only warning-rung findings does NOT fail (fit/graph semantics).
69
+ expect(check?.passed).toBe(true);
70
+ expect(payload.summary).toMatchObject({ errors: 0, warnings: 1, passed: 1, failed: 0 });
71
+ });
72
+ it('an empty scan yields zero checks and a zeroed summary', () => {
73
+ const payload = buildAdapterSessionPayload([]);
74
+ expect(payload.checks).toHaveLength(0);
75
+ expect(payload.summary).toEqual({ total: 0, passed: 0, failed: 0, errors: 0, warnings: 0 });
76
+ });
77
+ it('carries per-finding file/line/column/suggestion and projects metadata to scalars', () => {
78
+ const payload = buildAdapterSessionPayload([
79
+ leakSignal({ suggestion: 'rotate the credential' }),
80
+ ]);
81
+ const finding = payload.checks[0]?.findings[0];
82
+ expect(finding?.filePath).toBe('config/prod.env');
83
+ expect(finding?.line).toBe(12);
84
+ expect(finding?.column).toBe(19);
85
+ expect(finding?.suggestion).toBe('rotate the credential');
86
+ // Scalar metadata survives; the nested provenance OBJECT is dropped.
87
+ expect(finding?.metadata).toEqual({ secretPreview: 'AKIA…', entropy: 3.65 });
88
+ expect((finding?.metadata).provenance).toBeUndefined();
89
+ });
90
+ it('omits absent optional fields and keeps structured repair guidance', () => {
91
+ // A "bare" signal (no code ⇒ no file/line/column, no scalar metadata, no
92
+ // suggestion) and a repair-carrying signal — exercises both arms of every
93
+ // optional spread and the empty-metadata path.
94
+ const bare = createSignal({
95
+ source: 'osv-scanner',
96
+ severity: 'high',
97
+ ruleId: 'r',
98
+ message: 'm',
99
+ });
100
+ const withRepair = createSignal({
101
+ source: 'osv-scanner',
102
+ severity: 'high',
103
+ ruleId: 'r2',
104
+ message: 'm2',
105
+ repair: { repairKind: 'manual', autofixable: false },
106
+ });
107
+ const payload = buildAdapterSessionPayload([bare, withRepair]);
108
+ const bareFinding = payload.checks.find((c) => c.checkSlug === 'r')?.findings[0];
109
+ expect(bareFinding?.filePath).toBe('');
110
+ expect(bareFinding?.line).toBeUndefined();
111
+ expect(bareFinding?.column).toBeUndefined();
112
+ expect(bareFinding?.suggestion).toBeUndefined();
113
+ expect(bareFinding?.metadata).toBeUndefined();
114
+ const repairFinding = payload.checks.find((c) => c.checkSlug === 'r2')?.findings[0];
115
+ expect(repairFinding?.repair).toEqual({ repairKind: 'manual', autofixable: false });
116
+ });
117
+ it('NEVER lets a raw secret or the Match key reach the serialized payload (redaction proof)', () => {
118
+ // The signal carries ONLY a masked preview (redaction happens at ingest, before
119
+ // the envelope/payload build). Prove the serialized blob the host persists holds
120
+ // no raw credential bytes and no `Match` field.
121
+ const RAW_SECRET = 'AKIAIOSFODNN7EXAMPLE';
122
+ const payload = buildAdapterSessionPayload([leakSignal()]);
123
+ const blob = JSON.stringify(payload);
124
+ expect(blob).not.toContain(RAW_SECRET);
125
+ expect(blob).not.toContain('"Match"');
126
+ expect(blob).not.toContain('"Secret"');
127
+ // The masked preview IS present (the finding stays identifiable).
128
+ expect(blob).toContain('AKIA…');
129
+ });
130
+ });
131
+ //# sourceMappingURL=session-payload.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-payload.test.js","sourceRoot":"","sources":["../../src/__tests__/session-payload.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=severity-map.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity-map.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/severity-map.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { cvssToSeverity, parseCvss, sarifLevelToSeverity, withNativeSeverity, } from '../severity-map.js';
3
+ describe('cvssToSeverity (FIRST/NVD v3 bands)', () => {
4
+ it('maps the band boundaries', () => {
5
+ expect(cvssToSeverity(9)).toBe('critical');
6
+ expect(cvssToSeverity(9.8)).toBe('critical');
7
+ expect(cvssToSeverity(10)).toBe('critical');
8
+ expect(cvssToSeverity(8.9)).toBe('high');
9
+ expect(cvssToSeverity(7)).toBe('high');
10
+ expect(cvssToSeverity(6.9)).toBe('medium');
11
+ expect(cvssToSeverity(4)).toBe('medium');
12
+ expect(cvssToSeverity(3.9)).toBe('low');
13
+ expect(cvssToSeverity(0.1)).toBe('low');
14
+ });
15
+ it('treats 0 / negative / non-finite as low', () => {
16
+ expect(cvssToSeverity(0)).toBe('low');
17
+ expect(cvssToSeverity(-1)).toBe('low');
18
+ expect(cvssToSeverity(Number.NaN)).toBe('low');
19
+ // Non-finite is treated defensively as low (not a real CVSS score).
20
+ expect(cvssToSeverity(Number.POSITIVE_INFINITY)).toBe('low');
21
+ });
22
+ });
23
+ describe('parseCvss', () => {
24
+ it('reads numbers and numeric strings', () => {
25
+ expect(parseCvss(7.5)).toBe(7.5);
26
+ expect(parseCvss('9.8')).toBe(9.8);
27
+ expect(parseCvss(' 4.0 ')).toBe(4);
28
+ });
29
+ it('rejects vectors, empty, and non-numeric', () => {
30
+ expect(parseCvss('CVSS:3.1/AV:N/AC:L')).toBeUndefined();
31
+ expect(parseCvss('')).toBeUndefined();
32
+ expect(parseCvss(' ')).toBeUndefined();
33
+ expect(parseCvss('not-a-number')).toBeUndefined();
34
+ expect(parseCvss(undefined)).toBeUndefined();
35
+ expect(parseCvss(Number.NaN)).toBeUndefined();
36
+ expect(parseCvss({})).toBeUndefined();
37
+ });
38
+ });
39
+ describe('sarifLevelToSeverity (lossy fallback)', () => {
40
+ it('maps error to high (never critical), warning to medium, note/none to low', () => {
41
+ expect(sarifLevelToSeverity('error')).toBe('high');
42
+ expect(sarifLevelToSeverity('warning')).toBe('medium');
43
+ expect(sarifLevelToSeverity('note')).toBe('low');
44
+ expect(sarifLevelToSeverity('none')).toBe('low');
45
+ });
46
+ it('defaults an absent/unknown level to the warning rung (medium)', () => {
47
+ expect(sarifLevelToSeverity(undefined)).toBe('medium');
48
+ expect(sarifLevelToSeverity('bogus')).toBe('medium');
49
+ });
50
+ });
51
+ describe('withNativeSeverity', () => {
52
+ it('records the raw label and null for missing', () => {
53
+ expect(withNativeSeverity({ a: 1 }, 'HIGH')).toEqual({ a: 1, nativeSeverity: 'HIGH' });
54
+ expect(withNativeSeverity({}, undefined)).toEqual({ nativeSeverity: null });
55
+ });
56
+ });
57
+ //# sourceMappingURL=severity-map.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity-map.test.js","sourceRoot":"","sources":["../../src/__tests__/severity-map.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @fileoverview A reusable, framework-agnostic acceptance harness (ADR-0090
3
+ * §4.12). Given a frozen golden (the scanner's native output) it runs the
4
+ * substrate's parse → normalize → envelope path and returns the produced signals
5
+ * + the built `SignalEnvelope`, so an adapter's test asserts on *data* instead of
6
+ * re-scaffolding the pipeline. The real worker E2E lives in each adapter's tests
7
+ * (D6 Tier 2); this covers the in-process normalization tier (D6 Tier 1).
8
+ *
9
+ * Pure: no test framework, no IO, deterministic `runId`/`createdAt`.
10
+ */
11
+ import type { AdapterRunContext, FingerprintStrategyChoice, ParsedScannerOutput, ScannerOutputKind } from './types.js';
12
+ import type { SignalEnvelope } from '@opensip-cli/contracts';
13
+ import type { Signal } from '@opensip-cli/core';
14
+ /** A golden case to drive through the normalization pipeline. */
15
+ export interface AcceptanceFixture {
16
+ readonly tool: string;
17
+ readonly kind: ScannerOutputKind;
18
+ /** The scanner's native output bytes (a frozen golden). */
19
+ readonly raw: string;
20
+ /** Required for JSON/stdout fixtures; SARIF fixtures use the shared `ingestSarif`. */
21
+ readonly parse?: (raw: ParsedScannerOutput, ctx: AdapterRunContext) => readonly Signal[];
22
+ readonly fingerprintStrategy?: FingerprintStrategyChoice;
23
+ /** Optional partial context for a JSON/stdout `parse` (defaults are filled in). */
24
+ readonly ctx?: Partial<AdapterRunContext>;
25
+ }
26
+ /** The normalized output of an acceptance case. */
27
+ export interface AcceptanceResult {
28
+ readonly signals: readonly Signal[];
29
+ readonly envelope: SignalEnvelope;
30
+ }
31
+ /** The stable, comparable shape of a signal for golden assertions. */
32
+ export interface SignalShape {
33
+ readonly ruleId: string;
34
+ readonly severity: string;
35
+ readonly message: string;
36
+ readonly file: string;
37
+ readonly line?: number;
38
+ readonly column?: number;
39
+ }
40
+ /** Project a signal to its stable comparison shape (drops ids/timestamps/metadata). */
41
+ export declare function normalizedSignalShape(signal: Signal): SignalShape;
42
+ /**
43
+ * Run a golden fixture through the substrate pipeline. Returns the normalized
44
+ * signals and a deterministic envelope (host fallback policy, message-hash
45
+ * fingerprints by default).
46
+ */
47
+ export declare function runAcceptanceCase(fixture: AcceptanceFixture): AcceptanceResult;
48
+ //# sourceMappingURL=acceptance-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance-harness.d.ts","sourceRoot":"","sources":["../src/acceptance-harness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EACV,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sFAAsF;IACtF,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE,iBAAiB,KAAK,SAAS,MAAM,EAAE,CAAC;IACzF,QAAQ,CAAC,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IACzD,mFAAmF;IACnF,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC3C;AAED,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;CACnC;AAED,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CASjE;AAuBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,CA8B9E"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @fileoverview A reusable, framework-agnostic acceptance harness (ADR-0090
3
+ * §4.12). Given a frozen golden (the scanner's native output) it runs the
4
+ * substrate's parse → normalize → envelope path and returns the produced signals
5
+ * + the built `SignalEnvelope`, so an adapter's test asserts on *data* instead of
6
+ * re-scaffolding the pipeline. The real worker E2E lives in each adapter's tests
7
+ * (D6 Tier 2); this covers the in-process normalization tier (D6 Tier 1).
8
+ *
9
+ * Pure: no test framework, no IO, deterministic `runId`/`createdAt`.
10
+ */
11
+ import { buildSignalEnvelope } from '@opensip-cli/contracts';
12
+ import { resolveFingerprintStrategy } from './fingerprint.js';
13
+ import { safeParseJson } from './ingest-json.js';
14
+ import { ingestSarif } from './ingest-sarif.js';
15
+ /** Project a signal to its stable comparison shape (drops ids/timestamps/metadata). */
16
+ export function normalizedSignalShape(signal) {
17
+ return {
18
+ ruleId: signal.ruleId,
19
+ severity: signal.severity,
20
+ message: signal.message,
21
+ file: signal.filePath,
22
+ ...(signal.line === undefined ? {} : { line: signal.line }),
23
+ ...(signal.column === undefined ? {} : { column: signal.column }),
24
+ };
25
+ }
26
+ /** A single shared no-op used for every level of the harness's stub logger. */
27
+ const noop = () => undefined;
28
+ function defaultCtx(fixture) {
29
+ return {
30
+ tool: fixture.tool,
31
+ projectRoot: '/acceptance',
32
+ runId: 'acceptance-run',
33
+ logger: {
34
+ info: noop,
35
+ warn: noop,
36
+ error: noop,
37
+ debug: noop,
38
+ },
39
+ config: {},
40
+ binary: { path: `/usr/bin/${fixture.tool}`, layer: 'path' },
41
+ artifactPath: (name) => `/acceptance/acceptance-run/${name}`,
42
+ ...fixture.ctx,
43
+ };
44
+ }
45
+ /**
46
+ * Run a golden fixture through the substrate pipeline. Returns the normalized
47
+ * signals and a deterministic envelope (host fallback policy, message-hash
48
+ * fingerprints by default).
49
+ */
50
+ export function runAcceptanceCase(fixture) {
51
+ const ctx = defaultCtx(fixture);
52
+ let signals;
53
+ if (fixture.kind === 'sarif') {
54
+ const parsed = safeParseJson(fixture.raw);
55
+ signals = parsed.ok ? ingestSarif(parsed.value, { source: fixture.tool }) : [];
56
+ }
57
+ else if (fixture.parse === undefined) {
58
+ signals = [];
59
+ }
60
+ else {
61
+ const json = fixture.kind === 'json' ? safeParseJson(fixture.raw) : undefined;
62
+ signals = fixture.parse({ kind: fixture.kind, raw: fixture.raw, ...(json?.ok === true ? { json: json.value } : {}) }, ctx);
63
+ }
64
+ const envelope = buildSignalEnvelope({
65
+ tool: fixture.tool,
66
+ runId: ctx.runId,
67
+ createdAt: '2026-01-01T00:00:00.000Z',
68
+ units: [
69
+ { slug: 'scan', passed: signals.length === 0, violationCount: signals.length, durationMs: 0 },
70
+ ],
71
+ signals,
72
+ policy: { failOnErrors: 1, failOnWarnings: 0 },
73
+ runFaulted: false,
74
+ fingerprintStrategy: resolveFingerprintStrategy(fixture.fingerprintStrategy),
75
+ });
76
+ return { signals, envelope };
77
+ }
78
+ //# sourceMappingURL=acceptance-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acceptance-harness.js","sourceRoot":"","sources":["../src/acceptance-harness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @fileoverview The DEFAULT namespaced config contribution every adapter claims
3
+ * (ADR-0090 §4.3 / ADR-0023 / ADR-0054 M4-E).
4
+ *
5
+ * Without a claimed namespace `cli.scope.toolConfig?.[<tool>]` is ALWAYS
6
+ * `undefined`, so (1) the documented `binaries.<tool>.path` operator pin is dead,
7
+ * (2) the per-tool verdict policy keys (`failOnErrors`/`failOnWarnings`/
8
+ * `failOnDegraded`) are non-configurable, and (3) an operator adding a `<tool>:`
9
+ * block to `opensip-cli.config.yml` hits the ADR-0043 unclaimed-namespace
10
+ * rejection and BRICKS every project command. So an adapter claims its namespace
11
+ * by default — on BOTH the runtime (the Zod schema the WORKER deep pass runs) and
12
+ * the static manifest (the JSON-Schema descriptor the HOST coarse pass validates
13
+ * against pre-fork, since the host never imports the tool's Zod — ADR-0054 M4-E).
14
+ *
15
+ * Two halves, kept in lock-step:
16
+ * - {@link defaultAdapterConfigSchema} — the runtime Zod. The DEEP pass
17
+ * (`runDeepConfigPass`, worker-side) runs THIS raw schema (it is NOT the
18
+ * gate-key-decorated one the host composes), so the gate keys MUST be declared
19
+ * here or a `<tool>: { failOnWarnings: … }` block would fail the deep pass.
20
+ * - {@link defaultAdapterConfigManifest} — the serializable JSON-Schema
21
+ * descriptor. Declares ONLY `binaries` (coarse — host validates structure
22
+ * pre-fork); the host folds in the reserved gate keys via
23
+ * `decorateToolConfigDeclarationsWithGateKeys` exactly as it does for a bundled
24
+ * tool, so the gate thresholds are configurable like any bundled tool.
25
+ *
26
+ * `binaries` is a `{ <tool>: { path } }` map (the resolver reads
27
+ * `binaries[<tool>].path`, mirroring `binaries.<tool>.path` in the docs).
28
+ */
29
+ import { z } from 'zod';
30
+ import type { ToolConfigManifestDescriptor } from '@opensip-cli/core';
31
+ /** The author-facing config slot (namespace is derived from identity by `defineTool`). */
32
+ export interface AdapterConfigContribution {
33
+ /** The namespace Zod schema — a strict object claiming `binaries` + the gate keys. */
34
+ readonly schema: z.ZodType;
35
+ }
36
+ /**
37
+ * The runtime Zod schema the default adapter config claims for its namespace:
38
+ * the operator binary pin (`binaries.<tool>.path`) PLUS the three reserved
39
+ * verdict-policy keys. Strict, so a typo inside the block is rejected by the
40
+ * worker deep pass. The gate keys are declared HERE (unlike a bundled tool, which
41
+ * leans on the host decorator) because the worker deep pass runs this raw schema —
42
+ * the decorated one only governs the host pre-fork pass.
43
+ */
44
+ export declare function defaultAdapterConfigSchema(): z.ZodType;
45
+ /** The default config contribution forwarded to `defineTool` when a spec omits `config`. */
46
+ export declare function defaultAdapterConfig(): AdapterConfigContribution;
47
+ /**
48
+ * The serializable JSON-Schema descriptor the host coarse pass validates an
49
+ * installed adapter's `<tool>:` block against BEFORE forking (it never imports
50
+ * the tool's Zod — ADR-0054 M4-E). Declares ONLY the `binaries` block as a coarse
51
+ * object; the reserved gate keys are folded in host-side by
52
+ * `decorateToolConfigDeclarationsWithGateKeys`, so they are NOT (and must not be)
53
+ * duplicated here — that keeps the gate-key min(0) policy single-sourced in the
54
+ * decorator, exactly as for a bundled tool. The deep, value-level validation of
55
+ * `binaries.<tool>.path` runs worker-side via {@link defaultAdapterConfigSchema}.
56
+ */
57
+ export declare function defaultAdapterConfigManifest(namespace: string): ToolConfigManifestDescriptor;
58
+ //# sourceMappingURL=adapter-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-config.d.ts","sourceRoot":"","sources":["../src/adapter-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAoB,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAExF,0FAA0F;AAC1F,MAAM,WAAW,yBAAyB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,IAAI,CAAC,CAAC,OAAO,CAWtD;AAED,4FAA4F;AAC5F,wBAAgB,oBAAoB,IAAI,yBAAyB,CAEhE;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,4BAA4B,CAQ5F"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @fileoverview The DEFAULT namespaced config contribution every adapter claims
3
+ * (ADR-0090 §4.3 / ADR-0023 / ADR-0054 M4-E).
4
+ *
5
+ * Without a claimed namespace `cli.scope.toolConfig?.[<tool>]` is ALWAYS
6
+ * `undefined`, so (1) the documented `binaries.<tool>.path` operator pin is dead,
7
+ * (2) the per-tool verdict policy keys (`failOnErrors`/`failOnWarnings`/
8
+ * `failOnDegraded`) are non-configurable, and (3) an operator adding a `<tool>:`
9
+ * block to `opensip-cli.config.yml` hits the ADR-0043 unclaimed-namespace
10
+ * rejection and BRICKS every project command. So an adapter claims its namespace
11
+ * by default — on BOTH the runtime (the Zod schema the WORKER deep pass runs) and
12
+ * the static manifest (the JSON-Schema descriptor the HOST coarse pass validates
13
+ * against pre-fork, since the host never imports the tool's Zod — ADR-0054 M4-E).
14
+ *
15
+ * Two halves, kept in lock-step:
16
+ * - {@link defaultAdapterConfigSchema} — the runtime Zod. The DEEP pass
17
+ * (`runDeepConfigPass`, worker-side) runs THIS raw schema (it is NOT the
18
+ * gate-key-decorated one the host composes), so the gate keys MUST be declared
19
+ * here or a `<tool>: { failOnWarnings: … }` block would fail the deep pass.
20
+ * - {@link defaultAdapterConfigManifest} — the serializable JSON-Schema
21
+ * descriptor. Declares ONLY `binaries` (coarse — host validates structure
22
+ * pre-fork); the host folds in the reserved gate keys via
23
+ * `decorateToolConfigDeclarationsWithGateKeys` exactly as it does for a bundled
24
+ * tool, so the gate thresholds are configurable like any bundled tool.
25
+ *
26
+ * `binaries` is a `{ <tool>: { path } }` map (the resolver reads
27
+ * `binaries[<tool>].path`, mirroring `binaries.<tool>.path` in the docs).
28
+ */
29
+ import { z } from 'zod';
30
+ /**
31
+ * The runtime Zod schema the default adapter config claims for its namespace:
32
+ * the operator binary pin (`binaries.<tool>.path`) PLUS the three reserved
33
+ * verdict-policy keys. Strict, so a typo inside the block is rejected by the
34
+ * worker deep pass. The gate keys are declared HERE (unlike a bundled tool, which
35
+ * leans on the host decorator) because the worker deep pass runs this raw schema —
36
+ * the decorated one only governs the host pre-fork pass.
37
+ */
38
+ export function defaultAdapterConfigSchema() {
39
+ return z
40
+ .object({
41
+ binaries: z
42
+ .record(z.string(), z.object({ path: z.string().min(1).optional() }).strict())
43
+ .optional(),
44
+ failOnErrors: z.number().int().min(0).optional(),
45
+ failOnWarnings: z.number().int().min(0).optional(),
46
+ failOnDegraded: z.boolean().optional(),
47
+ })
48
+ .strict();
49
+ }
50
+ /** The default config contribution forwarded to `defineTool` when a spec omits `config`. */
51
+ export function defaultAdapterConfig() {
52
+ return { schema: defaultAdapterConfigSchema() };
53
+ }
54
+ /**
55
+ * The serializable JSON-Schema descriptor the host coarse pass validates an
56
+ * installed adapter's `<tool>:` block against BEFORE forking (it never imports
57
+ * the tool's Zod — ADR-0054 M4-E). Declares ONLY the `binaries` block as a coarse
58
+ * object; the reserved gate keys are folded in host-side by
59
+ * `decorateToolConfigDeclarationsWithGateKeys`, so they are NOT (and must not be)
60
+ * duplicated here — that keeps the gate-key min(0) policy single-sourced in the
61
+ * decorator, exactly as for a bundled tool. The deep, value-level validation of
62
+ * `binaries.<tool>.path` runs worker-side via {@link defaultAdapterConfigSchema}.
63
+ */
64
+ export function defaultAdapterConfigManifest(namespace) {
65
+ const schema = {
66
+ type: 'object',
67
+ properties: {
68
+ binaries: { type: 'object' },
69
+ },
70
+ };
71
+ return { namespace, schema };
72
+ }
73
+ //# sourceMappingURL=adapter-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-config.js","sourceRoot":"","sources":["../src/adapter-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B;IACxC,OAAO,CAAC;SACL,MAAM,CAAC;QACN,QAAQ,EAAE,CAAC;aACR,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;aAC7E,QAAQ,EAAE;QACb,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAChD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;QAClD,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACvC,CAAC;SACD,MAAM,EAAE,CAAC;AACd,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,oBAAoB;IAClC,OAAO,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,4BAA4B,CAAC,SAAiB;IAC5D,MAAM,MAAM,GAAqB;QAC/B,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC7B;KACF,CAAC;IACF,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview Manifest derivation from the built adapter `Tool` (ADR-0090
3
+ * §4.3 / §4.8 / ADR-0092) — the `config` namespace claim and the `requires`
4
+ * resource needs.
5
+ *
6
+ * An installed adapter's static `package.json#opensipTools` must mirror its
7
+ * runtime, and the generator (`build-tool-command-manifests.mjs`) plus a per-tool
8
+ * `--check` parity gate keep them in lock-step. `deriveAdapterManifestCommands`
9
+ * (a sibling) derives the command shells; the helpers here derive the remaining
10
+ * adapter-shaped manifest fields from data the substrate STAMPS on the built Tool
11
+ * ({@link AdapterToolMarkers}) — the substrate's own data, never a core `Tool`
12
+ * concept:
13
+ *
14
+ * - {@link deriveAdapterManifestRequires} forward-maps the declared `network`
15
+ * posture (ADR-0092) onto `opensipTools.requires`: `subprocess` + `filesystem`
16
+ * ALWAYS (every adapter `execFile`s a binary and reads/writes the project +
17
+ * artifact store), plus `network` WHEN the posture is not `local-only`. This is
18
+ * the §4.8 "honest labeling" mapping the `types.ts` contract claims — derived,
19
+ * not hand-authored, so flipping an adapter to `networked` produces a `--check`
20
+ * drift the gate catches.
21
+ * - {@link deriveAdapterConfigManifest} returns the coarse config descriptor the
22
+ * adapter claims (its namespace + `binaries` block) so the host pre-fork pass
23
+ * recognizes the namespace and an operator's `<tool>:` block no longer bricks.
24
+ */
25
+ import type { NetworkPosture } from './types.js';
26
+ import type { Tool, ToolConfigManifestDescriptor, ToolResourceRequirement } from '@opensip-cli/core';
27
+ /**
28
+ * The adapter-substrate markers {@link defineExternalToolAdapter} stamps on the
29
+ * Tool it returns. Kept off the core `Tool` contract (an adapter concept, not a
30
+ * kernel one); the substrate reads them back here to derive manifest fields.
31
+ */
32
+ export interface AdapterToolMarkers {
33
+ /** The declared network posture (ADR-0092), drives `requires` derivation. */
34
+ readonly adapterNetwork?: NetworkPosture;
35
+ /** The coarse config descriptor the adapter claims, or `undefined` for a custom config. */
36
+ readonly adapterConfigManifest?: ToolConfigManifestDescriptor;
37
+ }
38
+ /** Read the stamped network posture; defaults to `'local-only'` (the safe, no-network posture). */
39
+ export declare function adapterNetworkOf(tool: Tool): NetworkPosture;
40
+ /** Read the stamped config descriptor, or `undefined` when the adapter uses a custom config. */
41
+ export declare function adapterConfigManifestOf(tool: Tool): ToolConfigManifestDescriptor | undefined;
42
+ /**
43
+ * Derive `opensipTools.requires` from the adapter's network posture (ADR-0092
44
+ * §4.8). `subprocess` + `filesystem` are unconditional; `network` is added only
45
+ * when the posture is `networked`/`auth-required`. Pure — the manifest generator
46
+ * writes the result and the per-tool `--check` parity gate fails on drift.
47
+ */
48
+ export declare function deriveAdapterManifestRequires(tool: Tool): readonly ToolResourceRequirement[];
49
+ /**
50
+ * Derive the static `opensipTools.config` descriptor for an adapter — the coarse
51
+ * namespace claim the host validates a `<tool>:` block against pre-fork. Returns
52
+ * `undefined` for an adapter whose config cannot be coarsely serialized (a custom
53
+ * `spec.config`), which defers ALL of its config validation to the worker deep
54
+ * pass (ADR-0054 M4-E); the generator then omits the `config` key.
55
+ */
56
+ export declare function deriveAdapterConfigManifest(tool: Tool): ToolConfigManifestDescriptor | undefined;
57
+ //# sourceMappingURL=adapter-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-manifest.d.ts","sourceRoot":"","sources":["../src/adapter-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EACV,IAAI,EACJ,4BAA4B,EAC5B,uBAAuB,EACxB,MAAM,mBAAmB,CAAC;AAE3B;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC,2FAA2F;IAC3F,QAAQ,CAAC,qBAAqB,CAAC,EAAE,4BAA4B,CAAC;CAC/D;AAED,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,cAAc,CAE3D;AAED,gGAAgG;AAChG,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG,4BAA4B,GAAG,SAAS,CAE5F;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,uBAAuB,EAAE,CAmB5F;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,IAAI,GAAG,4BAA4B,GAAG,SAAS,CAEhG"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview Manifest derivation from the built adapter `Tool` (ADR-0090
3
+ * §4.3 / §4.8 / ADR-0092) — the `config` namespace claim and the `requires`
4
+ * resource needs.
5
+ *
6
+ * An installed adapter's static `package.json#opensipTools` must mirror its
7
+ * runtime, and the generator (`build-tool-command-manifests.mjs`) plus a per-tool
8
+ * `--check` parity gate keep them in lock-step. `deriveAdapterManifestCommands`
9
+ * (a sibling) derives the command shells; the helpers here derive the remaining
10
+ * adapter-shaped manifest fields from data the substrate STAMPS on the built Tool
11
+ * ({@link AdapterToolMarkers}) — the substrate's own data, never a core `Tool`
12
+ * concept:
13
+ *
14
+ * - {@link deriveAdapterManifestRequires} forward-maps the declared `network`
15
+ * posture (ADR-0092) onto `opensipTools.requires`: `subprocess` + `filesystem`
16
+ * ALWAYS (every adapter `execFile`s a binary and reads/writes the project +
17
+ * artifact store), plus `network` WHEN the posture is not `local-only`. This is
18
+ * the §4.8 "honest labeling" mapping the `types.ts` contract claims — derived,
19
+ * not hand-authored, so flipping an adapter to `networked` produces a `--check`
20
+ * drift the gate catches.
21
+ * - {@link deriveAdapterConfigManifest} returns the coarse config descriptor the
22
+ * adapter claims (its namespace + `binaries` block) so the host pre-fork pass
23
+ * recognizes the namespace and an operator's `<tool>:` block no longer bricks.
24
+ */
25
+ /** Read the stamped network posture; defaults to `'local-only'` (the safe, no-network posture). */
26
+ export function adapterNetworkOf(tool) {
27
+ return tool.adapterNetwork ?? 'local-only';
28
+ }
29
+ /** Read the stamped config descriptor, or `undefined` when the adapter uses a custom config. */
30
+ export function adapterConfigManifestOf(tool) {
31
+ return tool.adapterConfigManifest;
32
+ }
33
+ /**
34
+ * Derive `opensipTools.requires` from the adapter's network posture (ADR-0092
35
+ * §4.8). `subprocess` + `filesystem` are unconditional; `network` is added only
36
+ * when the posture is `networked`/`auth-required`. Pure — the manifest generator
37
+ * writes the result and the per-tool `--check` parity gate fails on drift.
38
+ */
39
+ export function deriveAdapterManifestRequires(tool) {
40
+ const requires = [
41
+ {
42
+ resource: 'subprocess',
43
+ reason: `Executes the user-installed ${tool.metadata.name} binary via execFile (no shell)`,
44
+ },
45
+ {
46
+ resource: 'filesystem',
47
+ reason: 'Reads the project working tree and writes the raw scan artifact under .runtime/artifacts',
48
+ },
49
+ ];
50
+ if (adapterNetworkOf(tool) !== 'local-only') {
51
+ requires.push({
52
+ resource: 'network',
53
+ reason: `Performs network I/O for the ${adapterNetworkOf(tool)} scanner posture`,
54
+ });
55
+ }
56
+ return requires;
57
+ }
58
+ /**
59
+ * Derive the static `opensipTools.config` descriptor for an adapter — the coarse
60
+ * namespace claim the host validates a `<tool>:` block against pre-fork. Returns
61
+ * `undefined` for an adapter whose config cannot be coarsely serialized (a custom
62
+ * `spec.config`), which defers ALL of its config validation to the worker deep
63
+ * pass (ADR-0054 M4-E); the generator then omits the `config` key.
64
+ */
65
+ export function deriveAdapterConfigManifest(tool) {
66
+ return adapterConfigManifestOf(tool);
67
+ }
68
+ //# sourceMappingURL=adapter-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-manifest.js","sourceRoot":"","sources":["../src/adapter-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAqBH,mGAAmG;AACnG,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,OAAQ,IAAkC,CAAC,cAAc,IAAI,YAAY,CAAC;AAC5E,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,uBAAuB,CAAC,IAAU;IAChD,OAAQ,IAAkC,CAAC,qBAAqB,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAAU;IACtD,MAAM,QAAQ,GAA8B;QAC1C;YACE,QAAQ,EAAE,YAAY;YACtB,MAAM,EAAE,+BAA+B,IAAI,CAAC,QAAQ,CAAC,IAAI,iCAAiC;SAC3F;QACD;YACE,QAAQ,EAAE,YAAY;YACtB,MAAM,EACJ,0FAA0F;SAC7F;KACF,CAAC;IACF,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,YAAY,EAAE,CAAC;QAC5C,QAAQ,CAAC,IAAI,CAAC;YACZ,QAAQ,EAAE,SAAS;YACnB,MAAM,EAAE,gCAAgC,gBAAgB,CAAC,IAAI,CAAC,kBAAkB;SACjF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAAU;IACpD,OAAO,uBAAuB,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC"}