@mindburn/helm-ai-kernel 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ export { HelmClient, HelmApiError } from "./client.js";
2
+ export type { HelmClientConfig, ReasonCode, HelmError, EvidenceEnvelopeExportRequest, EvidenceEnvelopeManifest, EvidenceEnvelopePayload, EvidenceEnvelopeVerification, ApprovalCeremony, ApprovalWebAuthnAssertion, ApprovalWebAuthnChallenge, BoundaryCheckpoint, BoundaryRecordVerification, GovernanceMetadata, ChatCompletionWithReceipt, McpQuarantineRecord, McpRegistryApprovalRequest, McpRegistryDiscoverRequest, NegativeBoundaryVector, SandboxBackendProfile, SandboxGrant, SurfaceRecord, } from "./client.js";
3
+ export { agentFrameworkAdapters, buildGovernedToolRequest, createAgentFrameworkAdapter, fromCrewAITask, fromAutoGenToolCall, fromLangChainToolCall, fromLangGraphToolCall, fromLiteLLMToolCall, fromLlamaIndexToolCall, fromN8NNodeExecution, fromOpenAIAgentsToolCall, fromPydanticAIToolCall, fromRawMCPToolCall, fromSemanticKernelFunctionCall, fromZapierWebhookCall, submitGovernedToolIntent, toOpenAIFunctionTool, } from "./adapters/agent-frameworks.js";
4
+ export type { AgentFramework, AgentFrameworkAction, AgentFrameworkAdapterMetadata, AutoGenToolCall, CrewAITaskCall, FrameworkAdapterDefaults, FrameworkAdapterOptions, GovernedFrameworkResult, HelmGovernanceClient, LangChainToolCall, LangGraphToolCall, LiteLLMToolCall, LlamaIndexToolCall, N8NNodeExecution, OpenAIAgentsToolCall, PydanticAIToolCall, RawMCPToolCall, SemanticKernelFunctionCall, ZapierWebhookCall, } from "./adapters/agent-frameworks.js";
5
+ export type { ChatCompletionRequest, ChatCompletionResponse, ApprovalRequest, Receipt, Session, VerificationResult, ConformanceRequest, ConformanceResult, VersionInfo, ExportRequest, } from "./types.gen.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { HelmClient, HelmApiError } from "./client.js";
2
+ export { agentFrameworkAdapters, buildGovernedToolRequest, createAgentFrameworkAdapter, fromCrewAITask, fromAutoGenToolCall, fromLangChainToolCall, fromLangGraphToolCall, fromLiteLLMToolCall, fromLlamaIndexToolCall, fromN8NNodeExecution, fromOpenAIAgentsToolCall, fromPydanticAIToolCall, fromRawMCPToolCall, fromSemanticKernelFunctionCall, fromZapierWebhookCall, submitGovernedToolIntent, toOpenAIFunctionTool, } from "./adapters/agent-frameworks.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,297 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { HelmClient, HelmApiError } from './client.js';
3
+ // ── Helpers ─────────────────────────────────────────────
4
+ function jsonResponse(body, status = 200) {
5
+ return new Response(JSON.stringify(body), {
6
+ status,
7
+ headers: { 'Content-Type': 'application/json' },
8
+ });
9
+ }
10
+ function errorResponse(status, reasonCode = 'ERROR_INTERNAL', message = 'boom') {
11
+ return jsonResponse({ error: { message, type: 'internal_error', code: 'err', reason_code: reasonCode } }, status);
12
+ }
13
+ // ── Tests ───────────────────────────────────────────────
14
+ describe('HelmApiError', () => {
15
+ it('exposes status, reasonCode, details, and message', () => {
16
+ const err = new HelmApiError(403, {
17
+ error: {
18
+ message: 'denied',
19
+ type: 'permission_denied',
20
+ code: 'DENY',
21
+ reason_code: 'DENY_POLICY_VIOLATION',
22
+ details: { policy: 'no-writes' },
23
+ },
24
+ });
25
+ expect(err.status).toBe(403);
26
+ expect(err.reasonCode).toBe('DENY_POLICY_VIOLATION');
27
+ expect(err.details).toEqual({ policy: 'no-writes' });
28
+ expect(err.message).toBe('denied');
29
+ expect(err.name).toBe('HelmApiError');
30
+ });
31
+ });
32
+ describe('HelmClient', () => {
33
+ let fetchSpy;
34
+ beforeEach(() => {
35
+ fetchSpy = vi.fn();
36
+ vi.stubGlobal('fetch', fetchSpy);
37
+ });
38
+ afterEach(() => {
39
+ vi.restoreAllMocks();
40
+ });
41
+ // ── Constructor ─────────────────────────────────────
42
+ describe('constructor', () => {
43
+ it('strips trailing slash from baseUrl', () => {
44
+ const client = new HelmClient({ baseUrl: 'http://host:8080/' });
45
+ // Verify via a call that the URL has no double slash
46
+ fetchSpy.mockResolvedValue(jsonResponse({ status: 'ok' }));
47
+ client.health();
48
+ expect(fetchSpy).toHaveBeenCalledWith('http://host:8080/healthz', expect.anything());
49
+ });
50
+ it('sets Authorization header when apiKey provided', () => {
51
+ const client = new HelmClient({ baseUrl: 'http://h', apiKey: 'sk-test' });
52
+ fetchSpy.mockResolvedValue(jsonResponse({ status: 'ok' }));
53
+ client.health();
54
+ const callArgs = fetchSpy.mock.calls[0][1];
55
+ expect(callArgs.headers['Authorization']).toBe('Bearer sk-test');
56
+ });
57
+ it('omits Authorization header when apiKey not provided', () => {
58
+ const client = new HelmClient({ baseUrl: 'http://h' });
59
+ fetchSpy.mockResolvedValue(jsonResponse({ status: 'ok' }));
60
+ client.health();
61
+ const callArgs = fetchSpy.mock.calls[0][1];
62
+ expect(callArgs.headers['Authorization']).toBeUndefined();
63
+ });
64
+ });
65
+ // ── Error handling ──────────────────────────────────
66
+ describe('error handling', () => {
67
+ it('throws HelmApiError on non-2xx response', async () => {
68
+ fetchSpy.mockResolvedValue(errorResponse(500));
69
+ const client = new HelmClient({ baseUrl: 'http://h' });
70
+ await expect(client.health()).rejects.toThrow(HelmApiError);
71
+ });
72
+ it('populates error fields from response body', async () => {
73
+ fetchSpy.mockResolvedValue(errorResponse(422, 'DENY_SCHEMA_MISMATCH', 'bad schema'));
74
+ const client = new HelmClient({ baseUrl: 'http://h' });
75
+ try {
76
+ await client.health();
77
+ expect.unreachable('should have thrown');
78
+ }
79
+ catch (e) {
80
+ const err = e;
81
+ expect(err.status).toBe(422);
82
+ expect(err.reasonCode).toBe('DENY_SCHEMA_MISMATCH');
83
+ expect(err.message).toBe('bad schema');
84
+ }
85
+ });
86
+ });
87
+ // ── chatCompletions ─────────────────────────────────
88
+ describe('chatCompletions', () => {
89
+ it('POSTs to /v1/chat/completions with request body', async () => {
90
+ const mockRes = { id: 'chatcmpl-1', object: 'chat.completion', created: 1, model: 'gpt-4', choices: [] };
91
+ fetchSpy.mockResolvedValue(jsonResponse(mockRes));
92
+ const client = new HelmClient({ baseUrl: 'http://h' });
93
+ const result = await client.chatCompletions({
94
+ model: 'gpt-4',
95
+ messages: [{ role: 'user', content: 'hi' }],
96
+ });
97
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/v1/chat/completions', expect.objectContaining({ method: 'POST' }));
98
+ expect(result.id).toBe('chatcmpl-1');
99
+ });
100
+ });
101
+ // ── approveIntent ───────────────────────────────────
102
+ describe('approveIntent', () => {
103
+ it('POSTs to /api/v1/kernel/approve', async () => {
104
+ const receipt = {
105
+ receipt_id: 'r1', decision_id: 'd1', effect_id: 'e1',
106
+ status: 'APPROVED', reason_code: 'ALLOW', output_hash: 'h',
107
+ blob_hash: 'b', prev_hash: 'p', lamport_clock: 1,
108
+ signature: 's', timestamp: 't', principal: 'pr',
109
+ };
110
+ fetchSpy.mockResolvedValue(jsonResponse(receipt));
111
+ const client = new HelmClient({ baseUrl: 'http://h' });
112
+ const result = await client.approveIntent({
113
+ intent_hash: 'abc', signature_b64: 's', public_key_b64: 'pk',
114
+ });
115
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/kernel/approve', expect.objectContaining({ method: 'POST' }));
116
+ expect(result.receipt_id).toBe('r1');
117
+ expect(result.status).toBe('APPROVED');
118
+ });
119
+ });
120
+ // ── ProofGraph ──────────────────────────────────────
121
+ describe('listSessions', () => {
122
+ it('GETs /api/v1/proofgraph/sessions with query params', async () => {
123
+ fetchSpy.mockResolvedValue(jsonResponse([]));
124
+ const client = new HelmClient({ baseUrl: 'http://h' });
125
+ await client.listSessions(10, 5);
126
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/proofgraph/sessions?limit=10&offset=5', expect.objectContaining({ method: 'GET' }));
127
+ });
128
+ });
129
+ describe('getReceipts', () => {
130
+ it('GETs receipts for a session', async () => {
131
+ fetchSpy.mockResolvedValue(jsonResponse([]));
132
+ const client = new HelmClient({ baseUrl: 'http://h' });
133
+ await client.getReceipts('sess-1');
134
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/proofgraph/sessions/sess-1/receipts', expect.objectContaining({ method: 'GET' }));
135
+ });
136
+ });
137
+ describe('getReceipt', () => {
138
+ it('GETs a single receipt by hash', async () => {
139
+ const receipt = {
140
+ receipt_id: 'r1', decision_id: 'd1', effect_id: 'e1',
141
+ status: 'APPROVED', reason_code: 'ALLOW', output_hash: 'h',
142
+ blob_hash: 'b', prev_hash: 'p', lamport_clock: 1,
143
+ signature: 's', timestamp: 't', principal: 'pr',
144
+ };
145
+ fetchSpy.mockResolvedValue(jsonResponse(receipt));
146
+ const client = new HelmClient({ baseUrl: 'http://h' });
147
+ const result = await client.getReceipt('hash-abc');
148
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/proofgraph/receipts/hash-abc', expect.objectContaining({ method: 'GET' }));
149
+ expect(result.receipt_id).toBe('r1');
150
+ });
151
+ });
152
+ // ── Conformance ─────────────────────────────────────
153
+ describe('conformanceRun', () => {
154
+ it('POSTs to /api/v1/conformance/run', async () => {
155
+ const report = { report_id: 'rpt1', level: 'L1', verdict: 'PASS', gates: 12, failed: 0, details: {} };
156
+ fetchSpy.mockResolvedValue(jsonResponse(report));
157
+ const client = new HelmClient({ baseUrl: 'http://h' });
158
+ const result = await client.conformanceRun({ level: 'L1' });
159
+ expect(result.verdict).toBe('PASS');
160
+ expect(result.gates).toBe(12);
161
+ });
162
+ });
163
+ describe('getConformanceReport', () => {
164
+ it('GETs conformance report by ID', async () => {
165
+ const report = { report_id: 'rpt1', level: 'L1', verdict: 'PASS', gates: 12, failed: 0, details: {} };
166
+ fetchSpy.mockResolvedValue(jsonResponse(report));
167
+ const client = new HelmClient({ baseUrl: 'http://h' });
168
+ const result = await client.getConformanceReport('rpt1');
169
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/conformance/reports/rpt1', expect.objectContaining({ method: 'GET' }));
170
+ expect(result.report_id).toBe('rpt1');
171
+ });
172
+ });
173
+ describe('execution boundary surfaces', () => {
174
+ it('creates evidence envelope manifests', async () => {
175
+ fetchSpy.mockResolvedValue(jsonResponse({
176
+ manifest_id: 'env1',
177
+ envelope: 'dsse',
178
+ native_evidence_hash: 'sha256:native',
179
+ native_authority: true,
180
+ created_at: '2026-05-05T00:00:00Z',
181
+ }));
182
+ const client = new HelmClient({ baseUrl: 'http://h' });
183
+ const result = await client.createEvidenceEnvelopeManifest({
184
+ manifest_id: 'env1',
185
+ envelope: 'dsse',
186
+ native_evidence_hash: 'sha256:native',
187
+ });
188
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/evidence/envelopes', expect.objectContaining({ method: 'POST' }));
189
+ expect(result.native_authority).toBe(true);
190
+ });
191
+ it('retrieves envelope payloads and verifies checkpoints', async () => {
192
+ fetchSpy
193
+ .mockResolvedValueOnce(jsonResponse({
194
+ manifest_id: 'env1',
195
+ payload_hash: 'sha256:payload',
196
+ payload: { payloadType: 'application/vnd.dsse+json' },
197
+ }))
198
+ .mockResolvedValueOnce(jsonResponse({
199
+ checkpoint_id: 'cp1',
200
+ verdict: 'PASS',
201
+ checks: { checkpoint_hash: 'PASS' },
202
+ }));
203
+ const client = new HelmClient({ baseUrl: 'http://h' });
204
+ const payload = await client.getEvidenceEnvelopePayload('env1');
205
+ const checkpoint = await client.verifyBoundaryCheckpoint('cp1');
206
+ expect(fetchSpy).toHaveBeenNthCalledWith(1, 'http://h/api/v1/evidence/envelopes/env1/payload', expect.objectContaining({ method: 'GET' }));
207
+ expect(fetchSpy).toHaveBeenNthCalledWith(2, 'http://h/api/v1/boundary/checkpoints/cp1/verify', expect.objectContaining({ method: 'POST' }));
208
+ expect(payload.payload_hash).toBe('sha256:payload');
209
+ expect(checkpoint.verdict).toBe('PASS');
210
+ });
211
+ it('creates and asserts approval WebAuthn ceremonies', async () => {
212
+ fetchSpy
213
+ .mockResolvedValueOnce(jsonResponse({
214
+ challenge_id: 'ch1',
215
+ approval_id: 'ap1',
216
+ challenge_hash: 'sha256:challenge',
217
+ }))
218
+ .mockResolvedValueOnce(jsonResponse({
219
+ approval_id: 'ap1',
220
+ state: 'approved',
221
+ auth_method: 'passkey',
222
+ }));
223
+ const client = new HelmClient({ baseUrl: 'http://h' });
224
+ const challenge = await client.createApprovalWebAuthnChallenge('ap1', { actor: 'user:alice' });
225
+ const assertion = await client.assertApprovalWebAuthnChallenge('ap1', {
226
+ challenge_id: 'ch1',
227
+ assertion: 'signed-client-data',
228
+ actor: 'user:alice',
229
+ });
230
+ expect(fetchSpy).toHaveBeenNthCalledWith(1, 'http://h/api/v1/approvals/ap1/webauthn/challenge', expect.objectContaining({ method: 'POST' }));
231
+ expect(fetchSpy).toHaveBeenNthCalledWith(2, 'http://h/api/v1/approvals/ap1/webauthn/assert', expect.objectContaining({ method: 'POST' }));
232
+ expect(challenge.challenge_id).toBe('ch1');
233
+ expect(assertion.state).toBe('approved');
234
+ });
235
+ it('lists negative conformance vectors', async () => {
236
+ fetchSpy.mockResolvedValue(jsonResponse([{ id: 'pdp-outage', category: 'policy' }]));
237
+ const client = new HelmClient({ baseUrl: 'http://h' });
238
+ const result = await client.listNegativeConformanceVectors();
239
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/conformance/negative', expect.objectContaining({ method: 'GET' }));
240
+ expect(result[0].id).toBe('pdp-outage');
241
+ });
242
+ it('manages MCP quarantine records', async () => {
243
+ fetchSpy.mockResolvedValue(jsonResponse({
244
+ server_id: 'mcp1',
245
+ risk: 'high',
246
+ state: 'quarantined',
247
+ discovered_at: '2026-05-05T00:00:00Z',
248
+ }));
249
+ const client = new HelmClient({ baseUrl: 'http://h' });
250
+ const result = await client.discoverMcpServer({ server_id: 'mcp1', risk: 'high' });
251
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/mcp/registry', expect.objectContaining({ method: 'POST' }));
252
+ expect(result.state).toBe('quarantined');
253
+ });
254
+ it('inspects sandbox grants with query parameters', async () => {
255
+ fetchSpy.mockResolvedValue(jsonResponse({
256
+ grant_id: 'grant1',
257
+ runtime: 'wazero',
258
+ profile: 'deny-default',
259
+ env: { mode: 'deny-all' },
260
+ network: { mode: 'deny-all' },
261
+ declared_at: '2026-05-05T00:00:00Z',
262
+ }));
263
+ const client = new HelmClient({ baseUrl: 'http://h' });
264
+ const result = await client.inspectSandboxGrants('wazero', 'deny-default', 'epoch1');
265
+ expect(fetchSpy).toHaveBeenCalledWith('http://h/api/v1/sandbox/grants/inspect?runtime=wazero&profile=deny-default&policy_epoch=epoch1', expect.objectContaining({ method: 'GET' }));
266
+ expect(result.grant_id).toBe('grant1');
267
+ });
268
+ });
269
+ // ── System ──────────────────────────────────────────
270
+ describe('health', () => {
271
+ it('GETs /healthz', async () => {
272
+ fetchSpy.mockResolvedValue(jsonResponse({ status: 'ok', version: '0.1.0' }));
273
+ const client = new HelmClient({ baseUrl: 'http://h' });
274
+ const result = await client.health();
275
+ expect(result.status).toBe('ok');
276
+ expect(result.version).toBe('0.1.0');
277
+ });
278
+ });
279
+ describe('version', () => {
280
+ it('GETs /version', async () => {
281
+ const info = { version: '0.1.0', commit: 'abc123', build_time: '2026-01-01T00:00:00Z', go_version: '1.24' };
282
+ fetchSpy.mockResolvedValue(jsonResponse(info));
283
+ const client = new HelmClient({ baseUrl: 'http://h' });
284
+ const result = await client.version();
285
+ expect(result.version).toBe('0.1.0');
286
+ expect(result.commit).toBe('abc123');
287
+ });
288
+ });
289
+ });
290
+ // ── Re-exports ────────────────────────────────────────
291
+ describe('index re-exports', () => {
292
+ it('exports HelmClient and HelmApiError', async () => {
293
+ const mod = await import('./index.js');
294
+ expect(mod.HelmClient).toBeDefined();
295
+ expect(mod.HelmApiError).toBeDefined();
296
+ });
297
+ });