agentcheck-sdk 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ /**
2
+ * LangChain integration for AgentCheck.
3
+ *
4
+ * Wraps LangChain tools with delegation checking and provides a callback
5
+ * handler that logs all tool calls to the AgentCheck audit trail.
6
+ *
7
+ * Requires: npm install langchain @langchain/core
8
+ *
9
+ * Tier: Molecule (be-mol-agentcheck-langchain-ts) - composes Client + LangChain.
10
+ */
11
+ import type { AgentCheckClient } from "../client";
12
+ /** Minimal BaseTool interface - duck-typed to avoid a hard langchain-core dependency. */
13
+ interface LangChainTool {
14
+ name: string;
15
+ _run?: (...args: unknown[]) => unknown | Promise<unknown>;
16
+ [key: string]: unknown;
17
+ }
18
+ /** Minimal BaseCallbackHandler shape from langchain-core. */
19
+ interface LangChainCallbackHandlerBase {
20
+ on_tool_start?: (serialized: Record<string, unknown>, inputStr: string, ...args: unknown[]) => void | Promise<void>;
21
+ on_tool_end?: (output: string, ...args: unknown[]) => void | Promise<void>;
22
+ on_tool_error?: (error: Error, ...args: unknown[]) => void | Promise<void>;
23
+ }
24
+ export declare class AgentCheckToolkit {
25
+ private readonly client;
26
+ private readonly delegationId;
27
+ /**
28
+ * @param client AgentCheck Client used to verify delegations.
29
+ * @param delegationId The agreement ID that authorizes tool usage.
30
+ */
31
+ constructor(client: AgentCheckClient, delegationId: string);
32
+ /**
33
+ * Wrap a single LangChain tool with a delegation guard.
34
+ *
35
+ * Replaces the tool's _run method so that the delegation is checked
36
+ * before every invocation.
37
+ *
38
+ * @param tool LangChain BaseTool instance.
39
+ * @returns The same tool with _run replaced.
40
+ */
41
+ wrapTool<T extends LangChainTool>(tool: T): T;
42
+ /**
43
+ * Wrap multiple tools with delegation guards.
44
+ *
45
+ * @param tools Array of LangChain BaseTool instances.
46
+ * @returns Array of wrapped tools.
47
+ */
48
+ wrapTools<T extends LangChainTool>(tools: T[]): T[];
49
+ }
50
+ export declare class AgentCheckCallbackHandler implements LangChainCallbackHandlerBase {
51
+ private readonly client;
52
+ private readonly delegationId;
53
+ /**
54
+ * @param client AgentCheck Client used for logging executions.
55
+ * @param delegationId The agreement ID to associate tool calls with.
56
+ */
57
+ constructor(client: AgentCheckClient, delegationId: string);
58
+ on_tool_start(serialized: Record<string, unknown>, inputStr: string): Promise<void>;
59
+ on_tool_end(output: string, ...args: unknown[]): Promise<void>;
60
+ on_tool_error(error: Error, ...args: unknown[]): Promise<void>;
61
+ private logExecution;
62
+ }
63
+ export {};
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * LangChain integration for AgentCheck.
4
+ *
5
+ * Wraps LangChain tools with delegation checking and provides a callback
6
+ * handler that logs all tool calls to the AgentCheck audit trail.
7
+ *
8
+ * Requires: npm install langchain @langchain/core
9
+ *
10
+ * Tier: Molecule (be-mol-agentcheck-langchain-ts) - composes Client + LangChain.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AgentCheckCallbackHandler = exports.AgentCheckToolkit = void 0;
14
+ class AgentCheckToolkit {
15
+ /**
16
+ * @param client AgentCheck Client used to verify delegations.
17
+ * @param delegationId The agreement ID that authorizes tool usage.
18
+ */
19
+ constructor(client, delegationId) {
20
+ this.client = client;
21
+ this.delegationId = delegationId;
22
+ }
23
+ /**
24
+ * Wrap a single LangChain tool with a delegation guard.
25
+ *
26
+ * Replaces the tool's _run method so that the delegation is checked
27
+ * before every invocation.
28
+ *
29
+ * @param tool LangChain BaseTool instance.
30
+ * @returns The same tool with _run replaced.
31
+ */
32
+ wrapTool(tool) {
33
+ const originalRun = tool._run?.bind(tool);
34
+ if (!originalRun)
35
+ return tool;
36
+ const client = this.client;
37
+ const delegationId = this.delegationId;
38
+ tool._run = async (...args) => {
39
+ await checkDelegation(client, delegationId);
40
+ return originalRun(...args);
41
+ };
42
+ return tool;
43
+ }
44
+ /**
45
+ * Wrap multiple tools with delegation guards.
46
+ *
47
+ * @param tools Array of LangChain BaseTool instances.
48
+ * @returns Array of wrapped tools.
49
+ */
50
+ wrapTools(tools) {
51
+ return tools.map((t) => this.wrapTool(t));
52
+ }
53
+ }
54
+ exports.AgentCheckToolkit = AgentCheckToolkit;
55
+ class AgentCheckCallbackHandler {
56
+ /**
57
+ * @param client AgentCheck Client used for logging executions.
58
+ * @param delegationId The agreement ID to associate tool calls with.
59
+ */
60
+ constructor(client, delegationId) {
61
+ this.client = client;
62
+ this.delegationId = delegationId;
63
+ }
64
+ async on_tool_start(serialized, inputStr) {
65
+ const toolName = serialized.name ?? "unknown_tool";
66
+ await this.logExecution(toolName, "started", { input: inputStr });
67
+ }
68
+ async on_tool_end(output, ...args) {
69
+ const kwargs = args[0] ?? {};
70
+ const toolName = kwargs.name ?? "unknown_tool";
71
+ await this.logExecution(toolName, "success", {
72
+ output: String(output).slice(0, 200),
73
+ });
74
+ }
75
+ async on_tool_error(error, ...args) {
76
+ const kwargs = args[0] ?? {};
77
+ const toolName = kwargs.name ?? "unknown_tool";
78
+ await this.logExecution(toolName, "error", { error: error.message });
79
+ }
80
+ async logExecution(toolName, result, metadata) {
81
+ try {
82
+ await this.client.request("POST", "/api/v1/executions", {
83
+ agent: "langchain",
84
+ action: toolName,
85
+ agreement_id: this.delegationId,
86
+ result,
87
+ metadata,
88
+ });
89
+ }
90
+ catch {
91
+ // Best-effort logging - do not propagate errors
92
+ }
93
+ }
94
+ }
95
+ exports.AgentCheckCallbackHandler = AgentCheckCallbackHandler;
96
+ // ---------------------------------------------------------------------------
97
+ // Internal helpers
98
+ // ---------------------------------------------------------------------------
99
+ async function checkDelegation(client, delegationId) {
100
+ const agreement = await client.get(delegationId);
101
+ if (agreement.status !== "approved") {
102
+ throw new Error(`Delegation ${delegationId} is not approved (status=${agreement.status})`);
103
+ }
104
+ }
@@ -3,10 +3,18 @@
3
3
  *
4
4
  * Connects all modules into a single chain:
5
5
  * delegation check -> scope -> semantic(LLM) -> budget -> pattern -> human -> execute -> log
6
+ *
7
+ * Phase 3 addition: VerificationPipeline accepts optional TrustEngine and
8
+ * LayerRouter. When provided, each verify() call consults the agent's trust
9
+ * score via the router to decide which layers to run. After execution the
10
+ * outcome is recorded back to TrustEngine. When omitted the original
11
+ * fixed-order behaviour is preserved (backwards compatible).
6
12
  */
7
13
  import { AgentCheckClient } from "./client";
8
14
  import { BudgetTracker, HumanEscalation, PatternMonitor } from "./safety";
9
15
  import { LLMProvider } from "./semantic";
16
+ import { TrustEngine } from "./trust";
17
+ import { LayerRouter } from "./router";
10
18
  export interface CheckResult {
11
19
  layer: string;
12
20
  passed: boolean;
@@ -28,22 +36,38 @@ export interface PipelineConfig {
28
36
  pattern?: PatternMonitor;
29
37
  escalation?: HumanEscalation;
30
38
  semanticThreshold?: number;
39
+ /** Optional trust engine for agent trust tracking (Phase 3). */
40
+ trustEngine?: TrustEngine;
41
+ /** Optional router for dynamic layer selection (Phase 3). */
42
+ router?: LayerRouter;
31
43
  }
32
44
  export declare class VerificationPipeline {
45
+ /**
46
+ * Complete delegation verification pipeline.
47
+ *
48
+ * Phase 3: When trustEngine and router are supplied, only the layers
49
+ * selected by the router for the agent's current trust tier are executed.
50
+ * After each verifyAndExecute() call the outcome is recorded back to
51
+ * the TrustEngine so trust scores evolve over time.
52
+ */
33
53
  private client;
34
54
  private scopeEngine;
35
55
  private semantic?;
36
56
  private budget?;
37
57
  private pattern;
38
58
  private escalation?;
59
+ private trustEngine?;
60
+ private router?;
39
61
  constructor(client: AgentCheckClient, config?: PipelineConfig);
40
62
  verify(agent: string, action: string, opts?: {
41
63
  amount?: number;
42
64
  context?: Record<string, unknown>;
65
+ riskLevel?: string;
43
66
  }): Promise<PipelineResult>;
44
67
  verifyAndExecute<T>(agent: string, action: string, executeFn: () => Promise<T>, opts?: {
45
68
  amount?: number;
46
69
  context?: Record<string, unknown>;
70
+ riskLevel?: string;
47
71
  }): Promise<PipelineResult>;
48
72
  private logExecution;
49
73
  }
package/dist/pipeline.js CHANGED
@@ -4,6 +4,12 @@
4
4
  *
5
5
  * Connects all modules into a single chain:
6
6
  * delegation check -> scope -> semantic(LLM) -> budget -> pattern -> human -> execute -> log
7
+ *
8
+ * Phase 3 addition: VerificationPipeline accepts optional TrustEngine and
9
+ * LayerRouter. When provided, each verify() call consults the agent's trust
10
+ * score via the router to decide which layers to run. After execution the
11
+ * outcome is recorded back to TrustEngine. When omitted the original
12
+ * fixed-order behaviour is preserved (backwards compatible).
7
13
  */
8
14
  Object.defineProperty(exports, "__esModule", { value: true });
9
15
  exports.VerificationPipeline = void 0;
@@ -18,11 +24,13 @@ class VerificationPipeline {
18
24
  this.budget = config.budget;
19
25
  this.pattern = config.pattern || new safety_1.PatternMonitor();
20
26
  this.escalation = config.escalation;
27
+ this.trustEngine = config.trustEngine;
28
+ this.router = config.router;
21
29
  }
22
30
  async verify(agent, action, opts = {}) {
23
31
  const checks = [];
24
32
  const amount = opts.amount || 0;
25
- // Layer 1: Delegation exists
33
+ // Layer 1: Delegation exists on AgentCheck server
26
34
  let agreement;
27
35
  let t = Date.now();
28
36
  try {
@@ -38,57 +46,81 @@ class VerificationPipeline {
38
46
  checks.push({ layer: "delegation_check", passed: false, reason: `Server error: ${e.message}`, durationMs: Date.now() - t });
39
47
  return { allowed: false, executed: false, action, agent, checks, error: e.message };
40
48
  }
41
- // Layer 2: Scope rules
42
- t = Date.now();
43
- const scope = this.scopeEngine.parse(agreement.scope);
44
- const scopeResult = this.scopeEngine.verify(scope, action, { amount });
45
- checks.push({ layer: "scope_engine", passed: scopeResult.allowed, reason: scopeResult.reason, durationMs: Date.now() - t });
46
- if (!scopeResult.allowed) {
47
- return { allowed: false, executed: false, action, agent, checks, error: scopeResult.reason };
49
+ // Determine which local layers to run
50
+ let activeLayers;
51
+ if (this.trustEngine && this.router) {
52
+ const trust = this.trustEngine.getScore(agent);
53
+ activeLayers = this.router.route(trust, action, { amount, riskLevel: opts.riskLevel });
48
54
  }
49
- // Layer 3: Semantic (LLM) - only for free-text scope
50
- if (this.semantic && typeof scope === "string") {
51
- t = Date.now();
52
- const sem = await this.semantic.verify(agreement.scope, action, opts.context || { amount });
53
- const isOk = sem.assessment !== "denied";
54
- checks.push({
55
- layer: "semantic_verifier",
56
- passed: isOk,
57
- reason: `[${sem.assessment}] ${sem.reasoning} (confidence: ${(sem.confidence * 100).toFixed(0)}%)`,
58
- durationMs: Date.now() - t,
59
- });
60
- if (sem.assessment === "denied") {
61
- return { allowed: false, executed: false, action, agent, checks, error: sem.reasoning };
55
+ else {
56
+ // Fixed order: run every configured layer (original behaviour)
57
+ activeLayers = ["scope_engine"];
58
+ if (this.semantic)
59
+ activeLayers.push("semantic_verifier");
60
+ if (this.budget)
61
+ activeLayers.push("budget_tracker");
62
+ activeLayers.push("pattern_monitor");
63
+ if (this.escalation)
64
+ activeLayers.push("human_escalation");
65
+ }
66
+ const scope = this.scopeEngine.parse(agreement.scope);
67
+ for (const layerName of activeLayers) {
68
+ if (layerName === "scope_engine") {
69
+ t = Date.now();
70
+ const r = this.scopeEngine.verify(scope, action, { amount });
71
+ checks.push({ layer: "scope_engine", passed: r.allowed, reason: r.reason, durationMs: Date.now() - t });
72
+ if (!r.allowed)
73
+ return { allowed: false, executed: false, action, agent, checks, error: r.reason };
62
74
  }
63
- if (sem.assessment === "suspicious") {
64
- checks.push({ layer: "semantic_flag", passed: true, reason: "LLM flagged suspicious - recommend human review", durationMs: 0 });
75
+ else if (layerName === "semantic_verifier") {
76
+ if (this.semantic && typeof scope === "string") {
77
+ t = Date.now();
78
+ const sem = await this.semantic.verify(agreement.scope, action, opts.context || { amount });
79
+ const isOk = sem.assessment !== "denied";
80
+ checks.push({
81
+ layer: "semantic_verifier",
82
+ passed: isOk,
83
+ reason: `[${sem.assessment}] ${sem.reasoning} (confidence: ${(sem.confidence * 100).toFixed(0)}%)`,
84
+ durationMs: Date.now() - t,
85
+ });
86
+ if (sem.assessment === "denied") {
87
+ return { allowed: false, executed: false, action, agent, checks, error: sem.reasoning };
88
+ }
89
+ if (sem.assessment === "suspicious") {
90
+ checks.push({ layer: "semantic_flag", passed: true, reason: "LLM flagged suspicious - recommend human review", durationMs: 0 });
91
+ }
92
+ }
65
93
  }
66
- }
67
- // Layer 4: Budget
68
- if (this.budget) {
69
- t = Date.now();
70
- const br = this.budget.check(action, amount);
71
- checks.push({ layer: "budget_tracker", passed: br.allowed, reason: br.reason, durationMs: Date.now() - t });
72
- if (!br.allowed) {
73
- return { allowed: false, executed: false, action, agent, checks, error: br.reason };
94
+ else if (layerName === "budget_tracker") {
95
+ if (this.budget) {
96
+ t = Date.now();
97
+ const br = this.budget.check(action, amount);
98
+ checks.push({ layer: "budget_tracker", passed: br.allowed, reason: br.reason, durationMs: Date.now() - t });
99
+ if (!br.allowed)
100
+ return { allowed: false, executed: false, action, agent, checks, error: br.reason };
101
+ }
74
102
  }
75
- }
76
- // Layer 5: Pattern
77
- t = Date.now();
78
- const alerts = this.pattern.check(action, amount);
79
- const hasCritical = alerts.some(a => a.level === "critical");
80
- const patternMsg = alerts.length ? alerts.map(a => a.message).join("; ") : "Normal pattern";
81
- checks.push({ layer: "pattern_monitor", passed: !hasCritical, reason: patternMsg, durationMs: Date.now() - t });
82
- if (hasCritical) {
83
- return { allowed: false, executed: false, action, agent, checks, error: alerts[0].message };
84
- }
85
- // Layer 6: Human escalation
86
- if (this.escalation) {
87
- t = Date.now();
88
- const er = this.escalation.check(action, amount);
89
- checks.push({ layer: "human_escalation", passed: er.allowed, reason: er.reason, durationMs: Date.now() - t });
90
- if (!er.allowed) {
91
- return { allowed: false, executed: false, action, agent, checks, error: er.reason };
103
+ else if (layerName === "pattern_monitor") {
104
+ t = Date.now();
105
+ const alerts = this.pattern.check(action, amount);
106
+ const hasCritical = alerts.some(a => a.level === "critical");
107
+ const patternMsg = alerts.length ? alerts.map(a => a.message).join("; ") : "Normal pattern";
108
+ checks.push({ layer: "pattern_monitor", passed: !hasCritical, reason: patternMsg, durationMs: Date.now() - t });
109
+ if (hasCritical) {
110
+ return { allowed: false, executed: false, action, agent, checks, error: alerts[0].message };
111
+ }
112
+ }
113
+ else if (layerName === "human_escalation") {
114
+ if (this.escalation) {
115
+ t = Date.now();
116
+ const er = this.escalation.check(action, amount);
117
+ checks.push({ layer: "human_escalation", passed: er.allowed, reason: er.reason, durationMs: Date.now() - t });
118
+ if (!er.allowed)
119
+ return { allowed: false, executed: false, action, agent, checks, error: er.reason };
120
+ }
121
+ }
122
+ else if (layerName === "pqc_signing") {
123
+ checks.push({ layer: "pqc_signing", passed: true, reason: `PQC signing required (amount=${amount} > threshold)`, durationMs: 0 });
92
124
  }
93
125
  }
94
126
  return { allowed: true, executed: false, action, agent, checks };
@@ -96,6 +128,8 @@ class VerificationPipeline {
96
128
  async verifyAndExecute(agent, action, executeFn, opts = {}) {
97
129
  const result = await this.verify(agent, action, opts);
98
130
  if (!result.allowed) {
131
+ // Record failed attempt to trust engine
132
+ this.trustEngine?.recordOutcome(agent, false);
99
133
  this.logExecution(agent, action, opts.amount || 0, "blocked", result.error);
100
134
  return result;
101
135
  }
@@ -111,6 +145,8 @@ class VerificationPipeline {
111
145
  }
112
146
  this.budget?.recordUsage(action, opts.amount || 0);
113
147
  this.pattern.record(action, opts.amount || 0);
148
+ // Record outcome to trust engine
149
+ this.trustEngine?.recordOutcome(agent, result.executed);
114
150
  this.logExecution(agent, action, opts.amount || 0, result.executed ? "success" : "failed", result.error);
115
151
  return result;
116
152
  }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * DSSE (Dead Simple Signing Envelope) structures for AgentCheck PQC integration.
3
+ *
4
+ * Implements the DSSE envelope format per https://github.com/secure-systems-lab/dsse
5
+ * with Pre-Authentication Encoding (PAE) for ML-DSA-87 / HMAC-SHA256 signatures.
6
+ *
7
+ * Tier: Atom (be-atom-agentcheck-dsse-ts) - single responsibility: envelope data model.
8
+ */
9
+ export declare const DSSE_PAYLOAD_TYPE = "application/vnd.agentcheck.audit+json";
10
+ export interface DsseSignatureData {
11
+ keyid: string;
12
+ sig: string;
13
+ }
14
+ export declare class DsseSignature {
15
+ readonly keyid: string;
16
+ readonly sig: string;
17
+ constructor(keyid: string, sig: string);
18
+ /** Decode signature from base64 to Uint8Array. */
19
+ sigBytes(): Uint8Array;
20
+ toDict(): DsseSignatureData;
21
+ static fromDict(d: DsseSignatureData): DsseSignature;
22
+ }
23
+ export interface DsseEnvelopeData {
24
+ payloadType: string;
25
+ payload: string;
26
+ signatures: DsseSignatureData[];
27
+ }
28
+ export declare class DsseEnvelope {
29
+ readonly payloadType: string;
30
+ readonly payload: string;
31
+ readonly signatures: DsseSignature[];
32
+ constructor(payloadType: string, payload: string, signatures?: DsseSignature[]);
33
+ /** Decode base64 payload to object. */
34
+ decodePayload(): Record<string, unknown>;
35
+ /**
36
+ * Pre-Authentication Encoding per DSSE spec.
37
+ *
38
+ * Format: DSSEv1 SP len(payloadType) SP payloadType SP len(payload) SP payload
39
+ */
40
+ pae(): Uint8Array;
41
+ toDict(): DsseEnvelopeData;
42
+ static fromDict(d: DsseEnvelopeData): DsseEnvelope;
43
+ /** Create a new unsigned DSSE envelope from a payload object. */
44
+ static create(payload: Record<string, unknown>, payloadType?: string): DsseEnvelope;
45
+ /** Return a new envelope with an additional signature appended. */
46
+ withSignature(sig: DsseSignature): DsseEnvelope;
47
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ /**
3
+ * DSSE (Dead Simple Signing Envelope) structures for AgentCheck PQC integration.
4
+ *
5
+ * Implements the DSSE envelope format per https://github.com/secure-systems-lab/dsse
6
+ * with Pre-Authentication Encoding (PAE) for ML-DSA-87 / HMAC-SHA256 signatures.
7
+ *
8
+ * Tier: Atom (be-atom-agentcheck-dsse-ts) - single responsibility: envelope data model.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.DsseEnvelope = exports.DsseSignature = exports.DSSE_PAYLOAD_TYPE = void 0;
12
+ exports.DSSE_PAYLOAD_TYPE = "application/vnd.agentcheck.audit+json";
13
+ class DsseSignature {
14
+ constructor(keyid, sig) {
15
+ this.keyid = keyid;
16
+ this.sig = sig;
17
+ }
18
+ /** Decode signature from base64 to Uint8Array. */
19
+ sigBytes() {
20
+ return base64Decode(this.sig);
21
+ }
22
+ toDict() {
23
+ return { keyid: this.keyid, sig: this.sig };
24
+ }
25
+ static fromDict(d) {
26
+ return new DsseSignature(d.keyid, d.sig);
27
+ }
28
+ }
29
+ exports.DsseSignature = DsseSignature;
30
+ class DsseEnvelope {
31
+ constructor(payloadType, payload, signatures = []) {
32
+ this.payloadType = payloadType;
33
+ this.payload = payload;
34
+ this.signatures = signatures;
35
+ }
36
+ /** Decode base64 payload to object. */
37
+ decodePayload() {
38
+ const raw = base64Decode(this.payload);
39
+ const json = new TextDecoder().decode(raw);
40
+ return JSON.parse(json);
41
+ }
42
+ /**
43
+ * Pre-Authentication Encoding per DSSE spec.
44
+ *
45
+ * Format: DSSEv1 SP len(payloadType) SP payloadType SP len(payload) SP payload
46
+ */
47
+ pae() {
48
+ const enc = new TextEncoder();
49
+ const payloadTypeBytes = enc.encode(this.payloadType);
50
+ const payloadBytes = base64Decode(this.payload);
51
+ const prefix = enc.encode(`DSSEv1 ${payloadTypeBytes.length} `);
52
+ const middle = enc.encode(` ${payloadBytes.length} `);
53
+ const total = prefix.length +
54
+ payloadTypeBytes.length +
55
+ middle.length +
56
+ payloadBytes.length;
57
+ const result = new Uint8Array(total);
58
+ let offset = 0;
59
+ result.set(prefix, offset);
60
+ offset += prefix.length;
61
+ result.set(payloadTypeBytes, offset);
62
+ offset += payloadTypeBytes.length;
63
+ result.set(middle, offset);
64
+ offset += middle.length;
65
+ result.set(payloadBytes, offset);
66
+ return result;
67
+ }
68
+ toDict() {
69
+ return {
70
+ payloadType: this.payloadType,
71
+ payload: this.payload,
72
+ signatures: this.signatures.map((s) => s.toDict()),
73
+ };
74
+ }
75
+ static fromDict(d) {
76
+ const sigs = (d.signatures ?? []).map(DsseSignature.fromDict);
77
+ return new DsseEnvelope(d.payloadType ?? exports.DSSE_PAYLOAD_TYPE, d.payload, sigs);
78
+ }
79
+ /** Create a new unsigned DSSE envelope from a payload object. */
80
+ static create(payload, payloadType = exports.DSSE_PAYLOAD_TYPE) {
81
+ const json = JSON.stringify(payload);
82
+ const payloadB64 = base64Encode(new TextEncoder().encode(json));
83
+ return new DsseEnvelope(payloadType, payloadB64, []);
84
+ }
85
+ /** Return a new envelope with an additional signature appended. */
86
+ withSignature(sig) {
87
+ return new DsseEnvelope(this.payloadType, this.payload, [
88
+ ...this.signatures,
89
+ sig,
90
+ ]);
91
+ }
92
+ }
93
+ exports.DsseEnvelope = DsseEnvelope;
94
+ // ---------------------------------------------------------------------------
95
+ // Base64 utilities (Node.js + browser compatible)
96
+ // ---------------------------------------------------------------------------
97
+ function base64Encode(bytes) {
98
+ if (typeof Buffer !== "undefined") {
99
+ return Buffer.from(bytes).toString("base64");
100
+ }
101
+ return btoa(String.fromCharCode(...bytes));
102
+ }
103
+ function base64Decode(b64) {
104
+ if (typeof Buffer !== "undefined") {
105
+ return new Uint8Array(Buffer.from(b64, "base64"));
106
+ }
107
+ const bin = atob(b64);
108
+ const bytes = new Uint8Array(bin.length);
109
+ for (let i = 0; i < bin.length; i++) {
110
+ bytes[i] = bin.charCodeAt(i);
111
+ }
112
+ return bytes;
113
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * AgentCheck PQC (Post-Quantum Cryptography) integration module.
3
+ *
4
+ * Provides DSSE envelope structures and ML-DSA-87 signature verification/signing.
5
+ * HMAC-SHA256 operations use the Web Crypto API (Node 18+, all modern browsers).
6
+ * ML-DSA-87 verification/signing is delegated to the fides-rs server.
7
+ */
8
+ export { DSSE_PAYLOAD_TYPE, DsseEnvelope, DsseSignature } from "./dsse";
9
+ export type { DsseEnvelopeData, DsseSignatureData } from "./dsse";
10
+ export { PqcVerifier } from "./verifier";
11
+ export { PqcSigner } from "./signer";
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * AgentCheck PQC (Post-Quantum Cryptography) integration module.
4
+ *
5
+ * Provides DSSE envelope structures and ML-DSA-87 signature verification/signing.
6
+ * HMAC-SHA256 operations use the Web Crypto API (Node 18+, all modern browsers).
7
+ * ML-DSA-87 verification/signing is delegated to the fides-rs server.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.PqcSigner = exports.PqcVerifier = exports.DsseSignature = exports.DsseEnvelope = exports.DSSE_PAYLOAD_TYPE = void 0;
11
+ var dsse_1 = require("./dsse");
12
+ Object.defineProperty(exports, "DSSE_PAYLOAD_TYPE", { enumerable: true, get: function () { return dsse_1.DSSE_PAYLOAD_TYPE; } });
13
+ Object.defineProperty(exports, "DsseEnvelope", { enumerable: true, get: function () { return dsse_1.DsseEnvelope; } });
14
+ Object.defineProperty(exports, "DsseSignature", { enumerable: true, get: function () { return dsse_1.DsseSignature; } });
15
+ var verifier_1 = require("./verifier");
16
+ Object.defineProperty(exports, "PqcVerifier", { enumerable: true, get: function () { return verifier_1.PqcVerifier; } });
17
+ var signer_1 = require("./signer");
18
+ Object.defineProperty(exports, "PqcSigner", { enumerable: true, get: function () { return signer_1.PqcSigner; } });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * PQC signer for DSSE envelopes.
3
+ *
4
+ * Signs audit records with HMAC-SHA256 locally via Web Crypto API.
5
+ * ML-DSA-87 signing is delegated to the fides-rs server so that
6
+ * private keys never exist in JavaScript memory.
7
+ *
8
+ * Tier: Atom (be-atom-agentcheck-pqc-signer-ts) - single responsibility: signing.
9
+ */
10
+ import { DsseEnvelope } from "./dsse";
11
+ export declare class PqcSigner {
12
+ private readonly hmacKey;
13
+ private readonly serverUrl;
14
+ private readonly apiKey;
15
+ /**
16
+ * @param hmacKey Optional HMAC-SHA256 secret for local signing.
17
+ * @param serverUrl Optional fides-rs base URL for ML-DSA-87 server-side signing.
18
+ * @param apiKey Optional API key for authenticating with the signing server.
19
+ */
20
+ constructor(opts?: {
21
+ hmacKey?: string;
22
+ serverUrl?: string;
23
+ apiKey?: string;
24
+ });
25
+ /**
26
+ * Create a DSSE envelope with HMAC-SHA256 signature.
27
+ *
28
+ * If no hmacKey is configured, the envelope is returned unsigned.
29
+ *
30
+ * @param payload Object to sign and encode into the envelope.
31
+ * @param keyId Key identifier to embed in the signature.
32
+ * @returns Signed DsseEnvelope (or unsigned if no key).
33
+ */
34
+ signHmac(payload: Record<string, unknown>, keyId?: string): Promise<DsseEnvelope>;
35
+ /**
36
+ * Request ML-DSA-87 signing from the fides-rs server.
37
+ *
38
+ * Returns null if the server is unavailable or not configured.
39
+ *
40
+ * @param payload Object to sign with ML-DSA-87 on the server.
41
+ * @returns Signed DsseEnvelope, or null if server signing is unavailable.
42
+ */
43
+ signPqc(payload: Record<string, unknown>): Promise<DsseEnvelope | null>;
44
+ }