@getstackrun/sdk 0.4.1 → 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.
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/services/intents.d.ts +176 -0
- package/dist/services/intents.d.ts.map +1 -0
- package/dist/services/intents.js +111 -0
- package/dist/services/intents.js.map +1 -0
- package/dist/sign-claim.d.ts +64 -0
- package/dist/sign-claim.d.ts.map +1 -0
- package/dist/sign-claim.js +97 -0
- package/dist/sign-claim.js.map +1 -0
- package/dist/sign-claim.test.d.ts +2 -0
- package/dist/sign-claim.test.d.ts.map +1 -0
- package/dist/sign-claim.test.js +164 -0
- package/dist/sign-claim.test.js.map +1 -0
- package/package.json +5 -2
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { ProxyService } from './services/proxy.js';
|
|
|
14
14
|
import { ScanService } from './services/scan.js';
|
|
15
15
|
import { AuditService } from './services/audit.js';
|
|
16
16
|
import { DetectorConfigService } from './services/detector-config.js';
|
|
17
|
+
import { IntentsService } from './services/intents.js';
|
|
17
18
|
export declare class Stack {
|
|
18
19
|
private readonly client;
|
|
19
20
|
readonly agents: AgentService;
|
|
@@ -31,10 +32,14 @@ export declare class Stack {
|
|
|
31
32
|
readonly scan: ScanService;
|
|
32
33
|
readonly audit: AuditService;
|
|
33
34
|
readonly detectorConfig: DetectorConfigService;
|
|
35
|
+
/** Phase 2.5a Macro 2 — intent simulate / submit / approve / reject. */
|
|
36
|
+
readonly intents: IntentsService;
|
|
34
37
|
constructor(options?: ClientOptions);
|
|
35
38
|
}
|
|
39
|
+
export type { IntentInput, SimulationCost, SimulationDiagnostics, SimulateInput, SimulateResult, SubmitInput, SubmitResult, PendingApproval, DecisionResult, DecideInput, SubmitAndWaitResult, } from './services/intents.js';
|
|
36
40
|
export type { ClientOptions } from './client.js';
|
|
37
41
|
export * from './types.js';
|
|
38
42
|
export * from './errors.js';
|
|
39
43
|
export { verifyPassportOffline, type VerifiedPassportClaims, type VerifyOfflineOptions, } from './verify-offline.js';
|
|
44
|
+
export { signClaimEnvelope, type ClaimEnvelope, type SignClaimEnvelopeOptions, } from './sign-claim.js';
|
|
40
45
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC;IAChD,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,oBAAoB,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;IAC/C,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;gBAErB,OAAO,GAAE,aAAkB;CAmBxC;AAGD,YAAY,EACV,WAAW,EACX,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,eAAe,EACf,cAAc,EACd,WAAW,EACX,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAK5B,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EACL,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,wBAAwB,GAC9B,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { ProxyService } from './services/proxy.js';
|
|
|
14
14
|
import { ScanService } from './services/scan.js';
|
|
15
15
|
import { AuditService } from './services/audit.js';
|
|
16
16
|
import { DetectorConfigService } from './services/detector-config.js';
|
|
17
|
+
import { IntentsService } from './services/intents.js';
|
|
17
18
|
export class Stack {
|
|
18
19
|
client;
|
|
19
20
|
agents;
|
|
@@ -31,6 +32,8 @@ export class Stack {
|
|
|
31
32
|
scan;
|
|
32
33
|
audit;
|
|
33
34
|
detectorConfig;
|
|
35
|
+
/** Phase 2.5a Macro 2 — intent simulate / submit / approve / reject. */
|
|
36
|
+
intents;
|
|
34
37
|
constructor(options = {}) {
|
|
35
38
|
this.client = new HttpClient(options);
|
|
36
39
|
this.agents = new AgentService(this.client);
|
|
@@ -48,6 +51,7 @@ export class Stack {
|
|
|
48
51
|
this.scan = new ScanService(this.client);
|
|
49
52
|
this.audit = new AuditService(this.client);
|
|
50
53
|
this.detectorConfig = new DetectorConfigService(this.client);
|
|
54
|
+
this.intents = new IntentsService(this.client);
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
export * from './types.js';
|
|
@@ -56,4 +60,11 @@ export * from './errors.js';
|
|
|
56
60
|
// the STACK API. Pair with a cache against /v1/passports/verify if you
|
|
57
61
|
// also need revocation-aware verdicts.
|
|
58
62
|
export { verifyPassportOffline, } from './verify-offline.js';
|
|
63
|
+
// Customer-side claim envelope signing for `customer_managed` agents
|
|
64
|
+
// (Phase 2.5a Sub-chunk 1.11). Produces a COSE_Sign1 byte-identical to
|
|
65
|
+
// what STACK's server-side ClaimSigner produces, so the same verify
|
|
66
|
+
// path on STACK accepts both. Pair with the existing agent-auth.ts
|
|
67
|
+
// enrollment flow: enroll once (POP-gated, stores pubkey), then sign
|
|
68
|
+
// envelopes locally with the persisted privkey.
|
|
69
|
+
export { signClaimEnvelope, } from './sign-claim.js';
|
|
59
70
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { HttpClient } from '../client.js';
|
|
2
|
+
/** Subset of the IntentClaim payload — kept loose so SDK consumers
|
|
3
|
+
* can ship through whatever they've assembled without us shipping
|
|
4
|
+
* the entire Zod schema as a peer dependency. */
|
|
5
|
+
export interface IntentInput {
|
|
6
|
+
type: 'intent_claim';
|
|
7
|
+
intent_type: 'http_call' | 'mcp_tool' | 'skill_invocation' | 'onchain_tx' | 'task_complete';
|
|
8
|
+
agent_id: string;
|
|
9
|
+
named_intent: string;
|
|
10
|
+
target: string;
|
|
11
|
+
action: string;
|
|
12
|
+
parameters: Record<string, unknown>;
|
|
13
|
+
estimated_cost: {
|
|
14
|
+
wallet_cents: number | null;
|
|
15
|
+
tokens: number | null;
|
|
16
|
+
gas_gwei: number | null;
|
|
17
|
+
};
|
|
18
|
+
accountability: 'enforced' | 'logged' | 'standard';
|
|
19
|
+
reason: string | null;
|
|
20
|
+
requires: string[];
|
|
21
|
+
user_subject: string | null;
|
|
22
|
+
mission_ref: string | null;
|
|
23
|
+
submitted_at: number;
|
|
24
|
+
}
|
|
25
|
+
export interface SimulationCost {
|
|
26
|
+
wallet_cents: number | null;
|
|
27
|
+
tokens: number | null;
|
|
28
|
+
gas_gwei: number | null;
|
|
29
|
+
}
|
|
30
|
+
export interface SimulationDiagnostics {
|
|
31
|
+
failed_constraint?: {
|
|
32
|
+
path: string;
|
|
33
|
+
op: string;
|
|
34
|
+
};
|
|
35
|
+
scope_missing_service?: string;
|
|
36
|
+
accountability_passport?: 'enforced' | 'logged' | 'standard';
|
|
37
|
+
accountability_intent?: 'enforced' | 'logged' | 'standard';
|
|
38
|
+
tier_limit?: {
|
|
39
|
+
meter: string;
|
|
40
|
+
cap: number | null;
|
|
41
|
+
used: number;
|
|
42
|
+
wallet_balance_cents: number;
|
|
43
|
+
overage_price_cents: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export interface SimulateInput {
|
|
47
|
+
intent: IntentInput;
|
|
48
|
+
intent_claim_ref?: string;
|
|
49
|
+
persist?: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface SimulateResult {
|
|
52
|
+
allowed: boolean;
|
|
53
|
+
denial_reasons: string[];
|
|
54
|
+
simulated_cost: SimulationCost;
|
|
55
|
+
predicted_detector_fires: Array<{
|
|
56
|
+
detector_key: string;
|
|
57
|
+
severity: string;
|
|
58
|
+
}>;
|
|
59
|
+
simulated_at: number;
|
|
60
|
+
claim_id?: string;
|
|
61
|
+
diagnostics: SimulationDiagnostics;
|
|
62
|
+
}
|
|
63
|
+
export interface SubmitInput {
|
|
64
|
+
intent: IntentInput;
|
|
65
|
+
expires_in_seconds?: number;
|
|
66
|
+
skip_simulation?: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface SubmitResult {
|
|
69
|
+
approval_id: string;
|
|
70
|
+
intent_claim_id: string;
|
|
71
|
+
simulated_claim_id?: string;
|
|
72
|
+
status: 'pending';
|
|
73
|
+
expires_at: string;
|
|
74
|
+
simulation?: SimulateResult;
|
|
75
|
+
}
|
|
76
|
+
export interface PendingApproval {
|
|
77
|
+
id: string;
|
|
78
|
+
operator_id: string;
|
|
79
|
+
agent_id: string;
|
|
80
|
+
passport_jti: string;
|
|
81
|
+
intent_claim_id: string;
|
|
82
|
+
simulated_claim_id: string | null;
|
|
83
|
+
status: 'pending' | 'approved' | 'rejected' | 'expired';
|
|
84
|
+
requested_at: string;
|
|
85
|
+
expires_at: string;
|
|
86
|
+
decided_at: string | null;
|
|
87
|
+
decided_by_member_id: string | null;
|
|
88
|
+
notes: string | null;
|
|
89
|
+
block_future: boolean;
|
|
90
|
+
}
|
|
91
|
+
export interface DecisionResult {
|
|
92
|
+
approval_id: string;
|
|
93
|
+
status: 'approved' | 'rejected';
|
|
94
|
+
decided_at: string;
|
|
95
|
+
}
|
|
96
|
+
export interface DecideInput {
|
|
97
|
+
notes?: string;
|
|
98
|
+
block_future?: boolean;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Result of `submitAndWait` — either the row reached a terminal status
|
|
102
|
+
* within the deadline (`status` is one of approved / rejected /
|
|
103
|
+
* expired) or polling timed out (`timed_out: true`).
|
|
104
|
+
*/
|
|
105
|
+
export type SubmitAndWaitResult = {
|
|
106
|
+
timed_out: false;
|
|
107
|
+
row: PendingApproval;
|
|
108
|
+
initial: SubmitResult;
|
|
109
|
+
} | {
|
|
110
|
+
timed_out: true;
|
|
111
|
+
row: PendingApproval;
|
|
112
|
+
initial: SubmitResult;
|
|
113
|
+
};
|
|
114
|
+
export declare class IntentsService {
|
|
115
|
+
private client;
|
|
116
|
+
constructor(client: HttpClient);
|
|
117
|
+
/**
|
|
118
|
+
* Dry-run an Intent against a passport WITHOUT registering an
|
|
119
|
+
* approval. Sub-chunk 2.1 surface.
|
|
120
|
+
*/
|
|
121
|
+
simulate(input: SimulateInput, options: {
|
|
122
|
+
passportToken: string;
|
|
123
|
+
}): Promise<SimulateResult>;
|
|
124
|
+
/**
|
|
125
|
+
* Submit an Intent for pre-execution operator approval. Registers
|
|
126
|
+
* the intent_claim, runs simulation (unless `skip_simulation=true`),
|
|
127
|
+
* persists a pending intent_approvals row, and notifies the operator
|
|
128
|
+
* via their configured channels. Returns the approval id; callers
|
|
129
|
+
* poll `/v1/intents/:id` (via `listPending` + custom filter, or via
|
|
130
|
+
* `submitAndWait`) until status leaves 'pending'.
|
|
131
|
+
*/
|
|
132
|
+
submit(input: SubmitInput, options: {
|
|
133
|
+
passportToken: string;
|
|
134
|
+
}): Promise<SubmitResult>;
|
|
135
|
+
/**
|
|
136
|
+
* Convenience: submit + poll. Polls the operator's pending list at
|
|
137
|
+
* `intervalMs` until either the approval reaches a terminal status
|
|
138
|
+
* or `timeoutMs` elapses. The poll uses listPending which is
|
|
139
|
+
* operator-scope — the SDK caller must be authenticated as the
|
|
140
|
+
* operator (or a member with role=admin) for this to work end-to-end.
|
|
141
|
+
*
|
|
142
|
+
* Practical use: in batch / CI scripts where the agent and operator
|
|
143
|
+
* are the same identity. For agent-runtime mode where the operator
|
|
144
|
+
* approves async via dashboard, callers should subscribe to
|
|
145
|
+
* notifications or poll `listPending` themselves.
|
|
146
|
+
*/
|
|
147
|
+
submitAndWait(input: SubmitInput, options: {
|
|
148
|
+
passportToken: string;
|
|
149
|
+
timeoutMs?: number;
|
|
150
|
+
intervalMs?: number;
|
|
151
|
+
}): Promise<SubmitAndWaitResult>;
|
|
152
|
+
/**
|
|
153
|
+
* Fetch a single approval row by id, regardless of status. Returns
|
|
154
|
+
* the full row when the calling operator owns it; 404s when the row
|
|
155
|
+
* doesn't exist OR belongs to a different operator (existence is
|
|
156
|
+
* hidden cross-tenant). Used by `submitAndWait` to distinguish
|
|
157
|
+
* approved from rejected reliably.
|
|
158
|
+
*/
|
|
159
|
+
get(approvalId: string): Promise<PendingApproval>;
|
|
160
|
+
/** List pending approvals scoped to the calling operator. */
|
|
161
|
+
listPending(opts?: {
|
|
162
|
+
page?: number;
|
|
163
|
+
limit?: number;
|
|
164
|
+
}): Promise<{
|
|
165
|
+
items: PendingApproval[];
|
|
166
|
+
total: number;
|
|
167
|
+
}>;
|
|
168
|
+
/** Transition a pending approval → approved. */
|
|
169
|
+
approve(approvalId: string, input?: DecideInput): Promise<DecisionResult>;
|
|
170
|
+
/**
|
|
171
|
+
* Transition a pending approval → rejected. Auto-revokes the
|
|
172
|
+
* passport; `block_future=true` additionally suspends the agent.
|
|
173
|
+
*/
|
|
174
|
+
reject(approvalId: string, input?: DecideInput): Promise<DecisionResult>;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=intents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intents.d.ts","sourceRoot":"","sources":["../../src/services/intents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Phase 2.5a Macro 2 Sub-chunk 2.2 — IntentsService TS SDK wrapper.
|
|
2
|
+
//
|
|
3
|
+
// Three groupings:
|
|
4
|
+
// 1. simulate() Sub-chunk 2.1 dry-run dispatcher.
|
|
5
|
+
// 2. submit() Sub-chunk 2.2 pre-execution gate. Registers the
|
|
6
|
+
// intent_claim, runs simulation, persists a pending
|
|
7
|
+
// intent_approvals row, returns an approval id.
|
|
8
|
+
// submitAndWait() Polls /v1/intents/:id until status leaves
|
|
9
|
+
// 'pending' or the deadline passes.
|
|
10
|
+
// 3. listPending() / approve() / reject() — operator-side surface.
|
|
11
|
+
//
|
|
12
|
+
// Every shape stays a plain interface mirroring the wire JSON so
|
|
13
|
+
// consumers can compose without TypeScript reaching for our internals.
|
|
14
|
+
export class IntentsService {
|
|
15
|
+
client;
|
|
16
|
+
constructor(client) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Dry-run an Intent against a passport WITHOUT registering an
|
|
21
|
+
* approval. Sub-chunk 2.1 surface.
|
|
22
|
+
*/
|
|
23
|
+
async simulate(input, options) {
|
|
24
|
+
return this.client.post('/v1/intents/simulate', input, {
|
|
25
|
+
headers: { 'X-Passport-Token': options.passportToken },
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Submit an Intent for pre-execution operator approval. Registers
|
|
30
|
+
* the intent_claim, runs simulation (unless `skip_simulation=true`),
|
|
31
|
+
* persists a pending intent_approvals row, and notifies the operator
|
|
32
|
+
* via their configured channels. Returns the approval id; callers
|
|
33
|
+
* poll `/v1/intents/:id` (via `listPending` + custom filter, or via
|
|
34
|
+
* `submitAndWait`) until status leaves 'pending'.
|
|
35
|
+
*/
|
|
36
|
+
async submit(input, options) {
|
|
37
|
+
return this.client.post('/v1/intents/submit', input, {
|
|
38
|
+
headers: { 'X-Passport-Token': options.passportToken },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Convenience: submit + poll. Polls the operator's pending list at
|
|
43
|
+
* `intervalMs` until either the approval reaches a terminal status
|
|
44
|
+
* or `timeoutMs` elapses. The poll uses listPending which is
|
|
45
|
+
* operator-scope — the SDK caller must be authenticated as the
|
|
46
|
+
* operator (or a member with role=admin) for this to work end-to-end.
|
|
47
|
+
*
|
|
48
|
+
* Practical use: in batch / CI scripts where the agent and operator
|
|
49
|
+
* are the same identity. For agent-runtime mode where the operator
|
|
50
|
+
* approves async via dashboard, callers should subscribe to
|
|
51
|
+
* notifications or poll `listPending` themselves.
|
|
52
|
+
*/
|
|
53
|
+
async submitAndWait(input, options) {
|
|
54
|
+
const initial = await this.submit(input, options);
|
|
55
|
+
const timeoutMs = options.timeoutMs ?? 60_000;
|
|
56
|
+
const intervalMs = options.intervalMs ?? 1_000;
|
|
57
|
+
const deadline = Date.now() + timeoutMs;
|
|
58
|
+
let last = null;
|
|
59
|
+
// Poll the per-id endpoint so we can read the actual terminal
|
|
60
|
+
// status (approved | rejected | expired) — listPending alone can't
|
|
61
|
+
// distinguish "no longer pending" from "approved", which made the
|
|
62
|
+
// 0.5.0 implementation silently treat rejections as approvals.
|
|
63
|
+
while (Date.now() < deadline) {
|
|
64
|
+
const row = await this.get(initial.approval_id);
|
|
65
|
+
last = row;
|
|
66
|
+
if (row.status !== 'pending') {
|
|
67
|
+
return { timed_out: false, row, initial };
|
|
68
|
+
}
|
|
69
|
+
await sleep(intervalMs);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
timed_out: true,
|
|
73
|
+
row: last ?? { id: initial.approval_id, status: 'pending' },
|
|
74
|
+
initial,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Fetch a single approval row by id, regardless of status. Returns
|
|
79
|
+
* the full row when the calling operator owns it; 404s when the row
|
|
80
|
+
* doesn't exist OR belongs to a different operator (existence is
|
|
81
|
+
* hidden cross-tenant). Used by `submitAndWait` to distinguish
|
|
82
|
+
* approved from rejected reliably.
|
|
83
|
+
*/
|
|
84
|
+
async get(approvalId) {
|
|
85
|
+
return this.client.get(`/v1/intents/${encodeURIComponent(approvalId)}`);
|
|
86
|
+
}
|
|
87
|
+
/** List pending approvals scoped to the calling operator. */
|
|
88
|
+
async listPending(opts) {
|
|
89
|
+
const query = {};
|
|
90
|
+
if (opts?.page !== undefined)
|
|
91
|
+
query['page'] = String(opts.page);
|
|
92
|
+
if (opts?.limit !== undefined)
|
|
93
|
+
query['limit'] = String(opts.limit);
|
|
94
|
+
return this.client.get('/v1/intents/pending', query);
|
|
95
|
+
}
|
|
96
|
+
/** Transition a pending approval → approved. */
|
|
97
|
+
async approve(approvalId, input) {
|
|
98
|
+
return this.client.post(`/v1/intents/${encodeURIComponent(approvalId)}/approve`, input ?? {});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Transition a pending approval → rejected. Auto-revokes the
|
|
102
|
+
* passport; `block_future=true` additionally suspends the agent.
|
|
103
|
+
*/
|
|
104
|
+
async reject(approvalId, input) {
|
|
105
|
+
return this.client.post(`/v1/intents/${encodeURIComponent(approvalId)}/reject`, input ?? {});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function sleep(ms) {
|
|
109
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=intents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intents.js","sourceRoot":"","sources":["../../src/services/intents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { JWK } from 'jose';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of the STACK claim envelope. Mirrors the server-side
|
|
4
|
+
* `ClaimEnvelope` Zod schema (see `@stack/shared` schemas/passport-
|
|
5
|
+
* claims/envelope.ts) at the field level. Re-declared here so the SDK
|
|
6
|
+
* does not have to import the shared package's full schema graph for
|
|
7
|
+
* one type.
|
|
8
|
+
*
|
|
9
|
+
* `claim_type` discriminates the payload shape. The signer treats the
|
|
10
|
+
* envelope as opaque CBOR-encodable JSON — it does NOT validate the
|
|
11
|
+
* payload against the per-claim-type Zod schema. The customer is
|
|
12
|
+
* responsible for producing a well-formed envelope; STACK validates
|
|
13
|
+
* shape on the receive side.
|
|
14
|
+
*/
|
|
15
|
+
export interface ClaimEnvelope {
|
|
16
|
+
envelope_version: 1;
|
|
17
|
+
issuer: string;
|
|
18
|
+
subject: string;
|
|
19
|
+
issued_at: number;
|
|
20
|
+
claim_type: string;
|
|
21
|
+
claim_version: number;
|
|
22
|
+
payload: unknown;
|
|
23
|
+
receipt: unknown | null;
|
|
24
|
+
co_signatures: unknown[];
|
|
25
|
+
[extra: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
export interface SignClaimEnvelopeOptions {
|
|
28
|
+
/**
|
|
29
|
+
* The agent's local private key, in JWK form. For customers using the
|
|
30
|
+
* SDK's built-in enrollment, the keypair is persisted at
|
|
31
|
+
* `~/.stack/agents/<agent_id>.json` by `agent-auth.ts`; pass
|
|
32
|
+
* `storedKey.privateKey` into this option. For customers managing
|
|
33
|
+
* their own key material, pass the JWK directly.
|
|
34
|
+
*/
|
|
35
|
+
privateKey: JWK;
|
|
36
|
+
/**
|
|
37
|
+
* The agent id this signature speaks for. The COSE protected header's
|
|
38
|
+
* `kid` is set to `agent:<id>:v1`. STACK's verifyPreSigned path uses
|
|
39
|
+
* the kid to look up the enrolled pubkey; a mismatch fails
|
|
40
|
+
* verification.
|
|
41
|
+
*/
|
|
42
|
+
agentId: string;
|
|
43
|
+
/**
|
|
44
|
+
* Defaults to 'EdDSA'. ML-DSA-65 is reserved but not yet implemented
|
|
45
|
+
* (waiting on the JOSE/COSE post-quantum draft).
|
|
46
|
+
*/
|
|
47
|
+
alg?: 'EdDSA' | 'ML-DSA-65';
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Sign a STACK claim envelope locally and produce a base64url-encoded
|
|
51
|
+
* COSE_Sign1 message. The output is the wire-format string the customer
|
|
52
|
+
* submits to STACK in the body of the eventual `POST /v1/claims`
|
|
53
|
+
* endpoint (lands with the producer migrations in Sub-chunks 1.16-1.20).
|
|
54
|
+
*
|
|
55
|
+
* The function is synchronous-friendly (no awaits beyond what cbor-x
|
|
56
|
+
* needs). Throws on unsupported algorithm or malformed JWK.
|
|
57
|
+
*
|
|
58
|
+
* Wire-format compatibility: byte-identical output to
|
|
59
|
+
* `@stack/vault`'s `ClaimSigner.sign` over the same envelope + kid +
|
|
60
|
+
* key material. Verified by the vault-side test
|
|
61
|
+
* `AgentSigner.verifyPreSigned` consuming the SDK's output unmodified.
|
|
62
|
+
*/
|
|
63
|
+
export declare function signClaimEnvelope(envelope: ClaimEnvelope, opts: SignClaimEnvelopeOptions): string;
|
|
64
|
+
//# sourceMappingURL=sign-claim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-claim.d.ts","sourceRoot":"","sources":["../src/sign-claim.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAsBhC;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,CAAC,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,aAAa,EAAE,OAAO,EAAE,CAAC;IACzB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC;;;;;;OAMG;IACH,UAAU,EAAE,GAAG,CAAC;IAChB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CAC7B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,wBAAwB,GAC7B,MAAM,CAiDR"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Customer-side COSE_Sign1 signer for `customer_managed` agents.
|
|
3
|
+
*
|
|
4
|
+
* Phase 2.5a Macro 1 Sub-chunk 1.11 of the Signed Primitive epic.
|
|
5
|
+
*
|
|
6
|
+
* `customer_managed` mode (ADR Design Decision 10) keeps the agent's
|
|
7
|
+
* private key on customer infrastructure. STACK only stores the pubkey
|
|
8
|
+
* (registered via the proof-of-possession dance at `POST /v1/agents/:id
|
|
9
|
+
* /enroll`). When the customer's agent produces a STACK claim envelope
|
|
10
|
+
* (intent_claim, intent_outcome, detector_signal, intent_denial,
|
|
11
|
+
* intent_simulation), the envelope is signed locally with this helper
|
|
12
|
+
* and submitted pre-signed.
|
|
13
|
+
*
|
|
14
|
+
* The wire format is byte-identical to what `@stack/vault`'s
|
|
15
|
+
* `ClaimSigner.sign` produces server-side, so the same `ClaimSigner
|
|
16
|
+
* .verify` path on STACK accepts both. We do NOT depend on
|
|
17
|
+
* `@stack/vault` here — that's a server package, not published, and
|
|
18
|
+
* we don't want a transitive `@aws-sdk/client-kms` blob landing in
|
|
19
|
+
* customer apps. The encoding logic is small (~50 lines) and trivially
|
|
20
|
+
* duplicated.
|
|
21
|
+
*
|
|
22
|
+
* Defaults to EdDSA / Ed25519. Algorithm is pluggable from day one so
|
|
23
|
+
* the same call site picks up ML-DSA-65 when the JOSE/COSE post-quantum
|
|
24
|
+
* draft hits RFC.
|
|
25
|
+
*/
|
|
26
|
+
import { encode as cborEncode } from 'cbor-x';
|
|
27
|
+
import { createPrivateKey, sign as cryptoSign } from 'node:crypto';
|
|
28
|
+
// ─── COSE constants per RFC 9052 / 9053 ─────────────────────────────
|
|
29
|
+
/** Algorithm identifier for EdDSA (Ed25519) — RFC 9053 §2.2. */
|
|
30
|
+
const COSE_ALG_EDDSA = -8;
|
|
31
|
+
/** Protected header label for `alg` — RFC 9052 §3.1. */
|
|
32
|
+
const COSE_HEADER_ALG = 1;
|
|
33
|
+
/** Protected header label for `kid`. */
|
|
34
|
+
const COSE_HEADER_KID = 4;
|
|
35
|
+
/** Protected header label for `typ` (content type). */
|
|
36
|
+
const COSE_HEADER_TYP = 16;
|
|
37
|
+
/** Stable media-type label for a STACK claim envelope. */
|
|
38
|
+
const STACK_CLAIM_TYP = 'stack/claim+cose';
|
|
39
|
+
/** Sig_structure1 context string — RFC 9052 §4.4. */
|
|
40
|
+
const SIG_STRUCTURE_CONTEXT = 'Signature1';
|
|
41
|
+
/**
|
|
42
|
+
* Sign a STACK claim envelope locally and produce a base64url-encoded
|
|
43
|
+
* COSE_Sign1 message. The output is the wire-format string the customer
|
|
44
|
+
* submits to STACK in the body of the eventual `POST /v1/claims`
|
|
45
|
+
* endpoint (lands with the producer migrations in Sub-chunks 1.16-1.20).
|
|
46
|
+
*
|
|
47
|
+
* The function is synchronous-friendly (no awaits beyond what cbor-x
|
|
48
|
+
* needs). Throws on unsupported algorithm or malformed JWK.
|
|
49
|
+
*
|
|
50
|
+
* Wire-format compatibility: byte-identical output to
|
|
51
|
+
* `@stack/vault`'s `ClaimSigner.sign` over the same envelope + kid +
|
|
52
|
+
* key material. Verified by the vault-side test
|
|
53
|
+
* `AgentSigner.verifyPreSigned` consuming the SDK's output unmodified.
|
|
54
|
+
*/
|
|
55
|
+
export function signClaimEnvelope(envelope, opts) {
|
|
56
|
+
const alg = opts.alg ?? 'EdDSA';
|
|
57
|
+
if (alg !== 'EdDSA') {
|
|
58
|
+
throw new Error(`signClaimEnvelope: algorithm '${alg}' is reserved but not yet ` +
|
|
59
|
+
`implemented. Only 'EdDSA' is supported in v1. ML-DSA-65 ships ` +
|
|
60
|
+
`when the JOSE/COSE post-quantum draft (draft-ietf-cose-dilithium) ` +
|
|
61
|
+
`lands at RFC.`);
|
|
62
|
+
}
|
|
63
|
+
const kid = `agent:${opts.agentId}:v1`;
|
|
64
|
+
const privateKey = createPrivateKey({
|
|
65
|
+
key: opts.privateKey,
|
|
66
|
+
format: 'jwk',
|
|
67
|
+
});
|
|
68
|
+
// Payload bytes — CBOR-encoded envelope. Deterministic given the
|
|
69
|
+
// input (cbor-x stable iteration order for plain objects).
|
|
70
|
+
const payloadBytes = cborEncode(envelope);
|
|
71
|
+
// Protected header — kid + alg + typ. Order is fixed for byte-
|
|
72
|
+
// identical output across SDK + vault.
|
|
73
|
+
const protectedHeader = new Map([
|
|
74
|
+
[COSE_HEADER_ALG, COSE_ALG_EDDSA],
|
|
75
|
+
[COSE_HEADER_KID, Buffer.from(kid, 'utf8')],
|
|
76
|
+
[COSE_HEADER_TYP, STACK_CLAIM_TYP],
|
|
77
|
+
]);
|
|
78
|
+
const protectedBytes = cborEncode(protectedHeader);
|
|
79
|
+
// Sig_structure1 per RFC 9052 §4.4. The signer signs this whole
|
|
80
|
+
// structure, not the envelope or payload alone. external_aad is
|
|
81
|
+
// empty (we don't use AAD on STACK claims).
|
|
82
|
+
const sigStructure = [
|
|
83
|
+
SIG_STRUCTURE_CONTEXT,
|
|
84
|
+
protectedBytes,
|
|
85
|
+
Buffer.alloc(0),
|
|
86
|
+
payloadBytes,
|
|
87
|
+
];
|
|
88
|
+
const sigStructureBytes = cborEncode(sigStructure);
|
|
89
|
+
// Ed25519: pass null as digest — algorithm has its own internal
|
|
90
|
+
// hashing per RFC 8032.
|
|
91
|
+
const signature = cryptoSign(null, sigStructureBytes, privateKey);
|
|
92
|
+
// COSE_Sign1 = [protected, unprotected, payload, signature]
|
|
93
|
+
const coseSign1 = [protectedBytes, new Map(), payloadBytes, signature];
|
|
94
|
+
const coseBytes = cborEncode(coseSign1);
|
|
95
|
+
return Buffer.from(coseBytes).toString('base64url');
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=sign-claim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-claim.js","sourceRoot":"","sources":["../src/sign-claim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,IAAI,IAAI,UAAU,EAAmB,MAAM,aAAa,CAAC;AAGpF,uEAAuE;AAEvE,gEAAgE;AAChE,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC;AAE1B,wDAAwD;AACxD,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,wCAAwC;AACxC,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,uDAAuD;AACvD,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,0DAA0D;AAC1D,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAE3C,qDAAqD;AACrD,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAqD3C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAuB,EACvB,IAA8B;IAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC;IAChC,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,iCAAiC,GAAG,4BAA4B;YAC9D,gEAAgE;YAChE,oEAAoE;YACpE,eAAe,CAClB,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,IAAI,CAAC,OAAO,KAAK,CAAC;IACvC,MAAM,UAAU,GAAG,gBAAgB,CAAC;QAClC,GAAG,EAAE,IAAI,CAAC,UAAwB;QAClC,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,iEAAiE;IACjE,2DAA2D;IAC3D,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAE1C,+DAA+D;IAC/D,uCAAuC;IACvC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAkB;QAC/C,CAAC,eAAe,EAAE,cAAc,CAAC;QACjC,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC,eAAe,EAAE,eAAe,CAAC;KACnC,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;IAEnD,gEAAgE;IAChE,gEAAgE;IAChE,4CAA4C;IAC5C,MAAM,YAAY,GAAG;QACnB,qBAAqB;QACrB,cAAc;QACd,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACf,YAAY;KACb,CAAC;IACF,MAAM,iBAAiB,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAEnD,gEAAgE;IAChE,wBAAwB;IACxB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,EAAE,iBAAiB,EAAE,UAAU,CAAC,CAAC;IAElE,4DAA4D;IAC5D,MAAM,SAAS,GAAG,CAAC,cAAc,EAAE,IAAI,GAAG,EAAE,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-claim.test.d.ts","sourceRoot":"","sources":["../src/sign-claim.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { generateKeyPair, exportJWK } from 'jose';
|
|
3
|
+
import { encode as cborEncode, decode as cborDecode } from 'cbor-x';
|
|
4
|
+
import { createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
|
5
|
+
import { signClaimEnvelope } from './sign-claim.js';
|
|
6
|
+
/**
|
|
7
|
+
* The SDK's signClaimEnvelope produces a COSE_Sign1 wire format that
|
|
8
|
+
* @stack/vault's ClaimSigner.verify accepts unmodified (Sub-chunk
|
|
9
|
+
* 1.11 wire-compat guarantee). We can't import vault here (it's a
|
|
10
|
+
* server-side package), so this test inlines the verification logic
|
|
11
|
+
* using the same primitives (cbor-x + node:crypto). The vault-side
|
|
12
|
+
* test `agent-signer.test.ts > verifyPreSigned` covers the same
|
|
13
|
+
* round-trip in the opposite direction — together they pin the wire
|
|
14
|
+
* format on both sides.
|
|
15
|
+
*/
|
|
16
|
+
// COSE constants — must match sign-claim.ts.
|
|
17
|
+
const COSE_ALG_EDDSA = -8;
|
|
18
|
+
const COSE_HEADER_ALG = 1;
|
|
19
|
+
const COSE_HEADER_KID = 4;
|
|
20
|
+
const COSE_HEADER_TYP = 16;
|
|
21
|
+
const STACK_CLAIM_TYP = 'stack/claim+cose';
|
|
22
|
+
async function newEd25519KeyPair() {
|
|
23
|
+
const { privateKey, publicKey } = await generateKeyPair('EdDSA', {
|
|
24
|
+
crv: 'Ed25519',
|
|
25
|
+
extractable: true,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
privateJwk: await exportJWK(privateKey),
|
|
29
|
+
publicJwk: await exportJWK(publicKey),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function makeEnvelope() {
|
|
33
|
+
return {
|
|
34
|
+
envelope_version: 1,
|
|
35
|
+
issuer: 'op_cust',
|
|
36
|
+
subject: 'stack://operator/op_cust/passport/ppt_abc',
|
|
37
|
+
issued_at: 1778600000000,
|
|
38
|
+
claim_type: 'intent_claim',
|
|
39
|
+
claim_version: 1,
|
|
40
|
+
payload: { intent_type: 'http_call', target: 'https://api.example.com' },
|
|
41
|
+
receipt: null,
|
|
42
|
+
co_signatures: [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Inline COSE_Sign1 verify — mirrors what @stack/vault's
|
|
47
|
+
* ClaimSigner.verify does, with the kid pinned to the agent's kid.
|
|
48
|
+
* Returns { valid, kid, envelope } or { valid: false, error }.
|
|
49
|
+
*/
|
|
50
|
+
function verifyCose(base64Cose, pubkey) {
|
|
51
|
+
try {
|
|
52
|
+
const coseBytes = Buffer.from(base64Cose, 'base64url');
|
|
53
|
+
const cose = cborDecode(coseBytes);
|
|
54
|
+
if (!Array.isArray(cose) || cose.length !== 4) {
|
|
55
|
+
return { valid: false, error: 'not a 4-element COSE_Sign1 array' };
|
|
56
|
+
}
|
|
57
|
+
const [protectedBytes, , payloadBytes, signatureBytes] = cose;
|
|
58
|
+
const protectedMap = cborDecode(protectedBytes);
|
|
59
|
+
if (!(protectedMap instanceof Map)) {
|
|
60
|
+
return { valid: false, error: 'protected header is not a CBOR map' };
|
|
61
|
+
}
|
|
62
|
+
const alg = protectedMap.get(COSE_HEADER_ALG);
|
|
63
|
+
if (alg !== COSE_ALG_EDDSA) {
|
|
64
|
+
return { valid: false, error: `unsupported alg ${alg}` };
|
|
65
|
+
}
|
|
66
|
+
const typ = protectedMap.get(COSE_HEADER_TYP);
|
|
67
|
+
if (typ !== STACK_CLAIM_TYP) {
|
|
68
|
+
return { valid: false, error: `unexpected typ ${typ}` };
|
|
69
|
+
}
|
|
70
|
+
const kidRaw = protectedMap.get(COSE_HEADER_KID);
|
|
71
|
+
const kid = kidRaw instanceof Uint8Array
|
|
72
|
+
? Buffer.from(kidRaw).toString('utf8')
|
|
73
|
+
: typeof kidRaw === 'string'
|
|
74
|
+
? kidRaw
|
|
75
|
+
: null;
|
|
76
|
+
if (!kid)
|
|
77
|
+
return { valid: false, error: 'kid missing' };
|
|
78
|
+
const publicKey = createPublicKey({
|
|
79
|
+
key: pubkey,
|
|
80
|
+
format: 'jwk',
|
|
81
|
+
});
|
|
82
|
+
const sigStructure = [
|
|
83
|
+
'Signature1',
|
|
84
|
+
protectedBytes,
|
|
85
|
+
Buffer.alloc(0),
|
|
86
|
+
payloadBytes,
|
|
87
|
+
];
|
|
88
|
+
const sigStructureBytes = cborEncode(sigStructure);
|
|
89
|
+
const valid = cryptoVerify(null, sigStructureBytes, publicKey, signatureBytes);
|
|
90
|
+
if (!valid)
|
|
91
|
+
return { valid: false, kid, error: 'signature verification failed' };
|
|
92
|
+
const envelope = cborDecode(payloadBytes);
|
|
93
|
+
return { valid: true, kid, envelope };
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return { valid: false, error: err.message };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
describe('signClaimEnvelope (customer-managed claim signing)', () => {
|
|
100
|
+
it('produces a COSE_Sign1 that round-trips under the customer pubkey', async () => {
|
|
101
|
+
const { privateJwk, publicJwk } = await newEd25519KeyPair();
|
|
102
|
+
const envelope = makeEnvelope();
|
|
103
|
+
const cose = signClaimEnvelope(envelope, {
|
|
104
|
+
privateKey: privateJwk,
|
|
105
|
+
agentId: 'ag_cust',
|
|
106
|
+
});
|
|
107
|
+
expect(cose).toMatch(/^[A-Za-z0-9_-]+$/);
|
|
108
|
+
const result = verifyCose(cose, publicJwk);
|
|
109
|
+
expect(result.valid).toBe(true);
|
|
110
|
+
expect(result.kid).toBe('agent:ag_cust:v1');
|
|
111
|
+
expect(result.envelope?.claim_type).toBe('intent_claim');
|
|
112
|
+
expect(result.envelope?.payload?.intent_type).toBe('http_call');
|
|
113
|
+
});
|
|
114
|
+
it('signs every standard claim_type variant', async () => {
|
|
115
|
+
const { privateJwk, publicJwk } = await newEd25519KeyPair();
|
|
116
|
+
const claimTypes = [
|
|
117
|
+
'intent_claim',
|
|
118
|
+
'intent_outcome',
|
|
119
|
+
'detector_signal',
|
|
120
|
+
'intent_denial',
|
|
121
|
+
'intent_simulation',
|
|
122
|
+
];
|
|
123
|
+
for (const claim_type of claimTypes) {
|
|
124
|
+
const cose = signClaimEnvelope({ ...makeEnvelope(), claim_type }, { privateKey: privateJwk, agentId: 'ag_cust' });
|
|
125
|
+
const result = verifyCose(cose, publicJwk);
|
|
126
|
+
expect(result.valid, `claim_type=${claim_type}`).toBe(true);
|
|
127
|
+
expect(result.envelope?.claim_type).toBe(claim_type);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it('does not verify under a different keypair', async () => {
|
|
131
|
+
const { privateJwk } = await newEd25519KeyPair();
|
|
132
|
+
const { publicJwk: otherPubkey } = await newEd25519KeyPair();
|
|
133
|
+
const cose = signClaimEnvelope(makeEnvelope(), {
|
|
134
|
+
privateKey: privateJwk,
|
|
135
|
+
agentId: 'ag_cust',
|
|
136
|
+
});
|
|
137
|
+
const result = verifyCose(cose, otherPubkey);
|
|
138
|
+
expect(result.valid).toBe(false);
|
|
139
|
+
expect(result.error).toBe('signature verification failed');
|
|
140
|
+
});
|
|
141
|
+
it('throws on unsupported algorithm', async () => {
|
|
142
|
+
const { privateJwk } = await newEd25519KeyPair();
|
|
143
|
+
expect(() => signClaimEnvelope(makeEnvelope(), {
|
|
144
|
+
privateKey: privateJwk,
|
|
145
|
+
agentId: 'ag_cust',
|
|
146
|
+
alg: 'ML-DSA-65',
|
|
147
|
+
})).toThrow(/reserved but not yet implemented/);
|
|
148
|
+
});
|
|
149
|
+
it("embeds kid 'agent:<id>:v1' in the protected header", async () => {
|
|
150
|
+
const { privateJwk } = await newEd25519KeyPair();
|
|
151
|
+
const cose = signClaimEnvelope(makeEnvelope(), {
|
|
152
|
+
privateKey: privateJwk,
|
|
153
|
+
agentId: 'ag_xyz_2',
|
|
154
|
+
});
|
|
155
|
+
// Decode just to inspect the kid — verification uses pubkey above.
|
|
156
|
+
const buf = Buffer.from(cose, 'base64url');
|
|
157
|
+
const cosePieces = cborDecode(buf);
|
|
158
|
+
const headerMap = cborDecode(cosePieces[0]);
|
|
159
|
+
const kidRaw = headerMap.get(COSE_HEADER_KID);
|
|
160
|
+
const kid = kidRaw instanceof Uint8Array ? Buffer.from(kidRaw).toString('utf8') : kidRaw;
|
|
161
|
+
expect(kid).toBe('agent:ag_xyz_2:v1');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
//# sourceMappingURL=sign-claim.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign-claim.test.js","sourceRoot":"","sources":["../src/sign-claim.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getstackrun/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Official JavaScript/TypeScript SDK for STACK - the runtime control plane for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsc",
|
|
21
21
|
"dev": "tsc --watch",
|
|
22
|
+
"test": "vitest run",
|
|
22
23
|
"typecheck": "tsc --noEmit",
|
|
23
24
|
"clean": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('.turbo',{recursive:true,force:true})\"",
|
|
24
25
|
"prepublishOnly": "npm run clean && npm run build"
|
|
@@ -55,9 +56,11 @@
|
|
|
55
56
|
"access": "public"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
59
|
+
"cbor-x": "^1.6.4",
|
|
58
60
|
"jose": "^6.2.2"
|
|
59
61
|
},
|
|
60
62
|
"devDependencies": {
|
|
61
|
-
"typescript": "^5.8.0"
|
|
63
|
+
"typescript": "^5.8.0",
|
|
64
|
+
"vitest": "^3.1.0"
|
|
62
65
|
}
|
|
63
66
|
}
|