@tenuo/core 0.3.4-beta.0 → 0.3.6-beta.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.
- package/README.md +2 -1
- package/dist/build-info.json +3 -3
- package/dist/generated/tenuo_wasm.d.ts +10 -0
- package/dist/generated/tenuo_wasm.js +32 -0
- package/dist/generated/tenuo_wasm_bg.wasm +0 -0
- package/dist/generated/tenuo_wasm_bg.wasm.d.ts +1 -0
- package/dist/mcp.js +13 -1
- package/dist/mcp.js.map +1 -1
- package/dist/wasm.d.ts +1 -0
- package/dist/wasm.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -105,7 +105,8 @@ MCP wire helpers live on `tenuo.mcp` (`attach` / `verify` / `handler`). They do
|
|
|
105
105
|
not depend on an MCP framework. For the official v2 server, use `@tenuo/mcp`.
|
|
106
106
|
For `@modelcontextprotocol/sdk` v1, copy the recipe in `examples/mcp/host.ts`.
|
|
107
107
|
`verify` / `handler` can take an optional `nonceStore` (`memoryNonceStore()`,
|
|
108
|
-
or an async Redis `checkAndRecord`) to reject
|
|
108
|
+
or an async Redis `checkAndRecord`) to reject a replayed PoP, regardless of
|
|
109
|
+
equivalent Base64 spelling, and to
|
|
109
110
|
consume the approvals an allowed call carried; that is opt-in. PoP v1 is
|
|
110
111
|
otherwise replayable in-window, including approval-gated calls. For
|
|
111
112
|
in-process tools, pass the same `nonceStore` to `tenuo.tool()` to make
|
package/dist/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "@tenuo/core",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"sourceCommit": "
|
|
3
|
+
"version": "0.3.6-beta.0",
|
|
4
|
+
"sourceCommit": "0410b1f29c6d9f3c9012d246e16c15b57807b179",
|
|
5
5
|
"sourceClean": false,
|
|
6
|
-
"wasmSha256": "
|
|
6
|
+
"wasmSha256": "c37252556cddf2d2df457c81c63da4a800d0ad5b6452b6f13cc7db5e1623c351",
|
|
7
7
|
"wasmMatchesCommit": false
|
|
8
8
|
}
|
|
@@ -322,6 +322,16 @@ export function parse_connect_token(token: string): any;
|
|
|
322
322
|
*/
|
|
323
323
|
export function parse_strict_json(json_text: string): void;
|
|
324
324
|
|
|
325
|
+
/**
|
|
326
|
+
* Decode an MCP proof-of-possession signature with the same parser used by
|
|
327
|
+
* authorization and return its canonical bytes as lowercase hex.
|
|
328
|
+
*
|
|
329
|
+
* Replay stores must key on the verified signature bytes, not on the wire
|
|
330
|
+
* spelling: whitespace, padding, and the standard/URL-safe base64 alphabets
|
|
331
|
+
* can encode the same Ed25519 signature.
|
|
332
|
+
*/
|
|
333
|
+
export function sdkCanonicalMetaSignature(signature: string): string;
|
|
334
|
+
|
|
325
335
|
/**
|
|
326
336
|
* Diagnose all capability-constraint failures without authorizing the call.
|
|
327
337
|
*/
|
|
@@ -969,6 +969,38 @@ function parse_strict_json(json_text) {
|
|
|
969
969
|
}
|
|
970
970
|
exports.parse_strict_json = parse_strict_json;
|
|
971
971
|
|
|
972
|
+
/**
|
|
973
|
+
* Decode an MCP proof-of-possession signature with the same parser used by
|
|
974
|
+
* authorization and return its canonical bytes as lowercase hex.
|
|
975
|
+
*
|
|
976
|
+
* Replay stores must key on the verified signature bytes, not on the wire
|
|
977
|
+
* spelling: whitespace, padding, and the standard/URL-safe base64 alphabets
|
|
978
|
+
* can encode the same Ed25519 signature.
|
|
979
|
+
* @param {string} signature
|
|
980
|
+
* @returns {string}
|
|
981
|
+
*/
|
|
982
|
+
function sdkCanonicalMetaSignature(signature) {
|
|
983
|
+
let deferred3_0;
|
|
984
|
+
let deferred3_1;
|
|
985
|
+
try {
|
|
986
|
+
const ptr0 = passStringToWasm0(signature, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
987
|
+
const len0 = WASM_VECTOR_LEN;
|
|
988
|
+
const ret = wasm.sdkCanonicalMetaSignature(ptr0, len0);
|
|
989
|
+
var ptr2 = ret[0];
|
|
990
|
+
var len2 = ret[1];
|
|
991
|
+
if (ret[3]) {
|
|
992
|
+
ptr2 = 0; len2 = 0;
|
|
993
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
994
|
+
}
|
|
995
|
+
deferred3_0 = ptr2;
|
|
996
|
+
deferred3_1 = len2;
|
|
997
|
+
return getStringFromWasm0(ptr2, len2);
|
|
998
|
+
} finally {
|
|
999
|
+
wasm.__wbindgen_free(deferred3_0, deferred3_1, 1);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
exports.sdkCanonicalMetaSignature = sdkCanonicalMetaSignature;
|
|
1003
|
+
|
|
972
1004
|
/**
|
|
973
1005
|
* Diagnose all capability-constraint failures without authorizing the call.
|
|
974
1006
|
* @param {string} wire
|
|
Binary file
|
|
@@ -54,6 +54,7 @@ export const evaluate_approval_gates: (a: number, b: number, c: number, d: numbe
|
|
|
54
54
|
export const generate_keypair: () => any;
|
|
55
55
|
export const inspect_approval_gate: (a: number, b: number, c: number, d: number) => any;
|
|
56
56
|
export const parse_connect_token: (a: number, b: number) => any;
|
|
57
|
+
export const sdkCanonicalMetaSignature: (a: number, b: number) => [number, number, number, number];
|
|
57
58
|
export const shlex_inspect: (a: any, b: number, c: number) => [number, number, number];
|
|
58
59
|
export const sign: (a: number, b: number, c: number, d: number, e: number, f: number, g: any) => any;
|
|
59
60
|
export const sign_receipt: (a: any, b: number, c: number) => any;
|
package/dist/mcp.js
CHANGED
|
@@ -164,7 +164,19 @@ function isHandlerPolicy(value) {
|
|
|
164
164
|
return keys.length === 0 || hasAllow || hasReceipt || hasNonce || hasStoreError;
|
|
165
165
|
}
|
|
166
166
|
function admitPop(store, signature, onNonceStoreError) {
|
|
167
|
-
|
|
167
|
+
if (store === undefined) {
|
|
168
|
+
return Promise.resolve();
|
|
169
|
+
}
|
|
170
|
+
let canonical;
|
|
171
|
+
try {
|
|
172
|
+
canonical = `tenuo-pop-v1:${loadWasm().sdkCanonicalMetaSignature(signature)}`;
|
|
173
|
+
}
|
|
174
|
+
catch (cause) {
|
|
175
|
+
const error = new TenuoConfigurationError("could not canonicalize an authorized proof for replay protection");
|
|
176
|
+
error.cause = cause;
|
|
177
|
+
return Promise.reject(error);
|
|
178
|
+
}
|
|
179
|
+
return admitNonce(store, canonical, onNonceStoreError, () => new AuthorizationDeniedError("TENUO_INVALID_POP", "PoP replay detected — this authorization token was already consumed."));
|
|
168
180
|
}
|
|
169
181
|
/** The request hash core wrote into the decision receipt, when there is one. */
|
|
170
182
|
function receiptRequestHash(receipt) {
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n McpAttachOptions,\n McpCallParams,\n McpHandlerPolicy,\n McpJsonRpcError,\n McpVerifyOptions,\n PresentedCall,\n Session as SessionContract,\n TenuoErrorCode,\n TenuoMcp,\n} from \"./api.ts\";\nimport { AuthorizationDeniedError, TenuoConfigurationError, TenuoError } from \"./errors.ts\";\nimport { collectReceipt, emitIsolatedReceipt } from \"./receipts.ts\";\nimport { admitNonce, consumeApprovals, snapshotApprovals } from \"./replay.ts\";\nimport { nativeSession, type Session } from \"./session.ts\";\nimport { loadWasm, type WasmContext, type WasmDecision } from \"./wasm.ts\";\n\nexport type Decide = (decision: WasmDecision, tool: string, native?: object, args?: Record<string, unknown>) => void;\n\n/**\n * Transport-agnostic half of `attach`: authorize locally, then sign\n * proof-of-possession over the call. Shared by `tenuo.present()` and\n * `tenuo.mcp.attach()`.\n */\nexport function presentCall(\n context: WasmContext,\n decide: Decide,\n session: SessionContract,\n name: string,\n args: Readonly<Record<string, unknown>>,\n options: McpAttachOptions | undefined,\n label: string,\n host?: object,\n): { readonly presented: PresentedCall; readonly wireArgs: Record<string, unknown> } {\n if (options !== undefined) {\n assertKnownKeys(options, ATTACH_OPTION_KEYS, `${label} options`);\n }\n const native = nativeSession(session as Session);\n const snapshot = captureArguments(args);\n const local = context.authorize(\n native,\n name,\n snapshot.json,\n options?.approvals,\n undefined,\n options?.requestId,\n );\n emitReceipt(options?.onReceipt, local.receipt, session, host);\n decide(local, name, native, snapshot.executionArgs());\n const envelope = context.signMeta(\n native,\n name,\n snapshot.json,\n Math.floor(Date.now() / 1000),\n options?.approvals ?? null,\n );\n const presented = {\n warrant: envelope.warrant,\n signature: envelope.signature,\n ...(envelope.approvals !== undefined && envelope.approvals.length > 0\n ? { approvals: envelope.approvals }\n : {}),\n };\n return { presented, wireArgs: snapshot.executionArgs() };\n}\n\n/**\n * Transport-agnostic half of `verify`: check a presented warrant chain and\n * proof-of-possession, then apply the host ceiling. Shared by\n * `tenuo.verify()` and `tenuo.mcp.verify()`.\n */\nexport async function verifyPresented(\n context: WasmContext,\n decide: Decide,\n presented: PresentedCall,\n name: string,\n args: Readonly<Record<string, unknown>>,\n options: McpVerifyOptions | undefined,\n label: string,\n host?: object,\n): Promise<Readonly<Record<string, unknown>>> {\n if (options !== undefined) {\n assertKnownKeys(options, VERIFY_OPTION_KEYS, `${label} options`);\n }\n const envelope = presentedEnvelope(presented);\n if (envelope === undefined) {\n throw new TenuoConfigurationError(\n `${label} needs { warrant, signature } from tenuo.present() or tenuo.mcp.attach()`,\n );\n }\n const approvals = snapshotApprovals(envelope.approvals);\n // Capture once: replay admission and receipt callbacks may yield or mutate\n // the caller's object. Execution must use the exact snapshot verified here.\n const snapshot = captureArguments(args);\n const decision = context.authorizePresented(\n envelope.warrant,\n name,\n snapshot.json,\n envelope.signature,\n approvals,\n options?.allow,\n options?.requestId,\n );\n // Rust already signed this envelope. Emit before the nonce store can\n // refuse a replay — otherwise an attacker leaves no audit artifact.\n emitReceipt(options?.onReceipt, decision.receipt, undefined, host);\n if (decision.outcome === \"allow\") {\n await admitPop(options?.nonceStore, envelope.signature, options?.onNonceStoreError);\n // A fresh PoP over the same approvals is a new token; consume the\n // approvals themselves so a nonce store makes them one-use here too.\n await consumeApprovals(\n options?.nonceStore,\n approvals,\n receiptRequestHash(decision.receipt),\n name,\n options?.onNonceStoreError,\n );\n }\n decide(decision, name);\n // Run the host parse of the JSON text the proof covers. The raw host\n // object can contain values that JSON drops.\n return snapshot.executionArgs();\n}\n\nexport function createMcp(context: WasmContext, decide: Decide, host?: object): TenuoMcp {\n const mcp: TenuoMcp = {\n attach(session, name, args, options) {\n const { presented, wireArgs } = presentCall(\n context,\n decide,\n session,\n name,\n args,\n options,\n \"mcp.attach()\",\n host,\n );\n return { name, arguments: wireArgs, _meta: { tenuo: presented } };\n },\n\n async verify(name, args, meta, options) {\n const envelope = tenuoEnvelope(meta);\n if (envelope === undefined) {\n throw new TenuoConfigurationError(\n \"MCP call is missing _meta.tenuo. The client must call tenuo.mcp.attach().\",\n );\n }\n return verifyPresented(context, decide, envelope, name, args, options, \"mcp.verify()\", host);\n },\n\n handler(name, policyOrExecute, maybeExecute?) {\n const policy = isHandlerPolicy(policyOrExecute) ? policyOrExecute : undefined;\n const execute = isHandlerPolicy(policyOrExecute) ? maybeExecute : policyOrExecute;\n if (typeof execute !== \"function\") {\n throw new TenuoConfigurationError(\"mcp.handler() requires an execute function\");\n }\n return async (args, extra) => {\n const authorized = await mcp.verify(name, args, extra?._meta ?? extra?.meta, {\n ...(policy?.allow !== undefined ? { allow: policy.allow } : {}),\n ...(policy?.onReceipt !== undefined ? { onReceipt: policy.onReceipt } : {}),\n ...(policy?.nonceStore !== undefined ? { nonceStore: policy.nonceStore } : {}),\n ...(policy?.onNonceStoreError !== undefined ? { onNonceStoreError: policy.onNonceStoreError } : {}),\n });\n return execute(authorized as never);\n };\n },\n\n jsonRpcError(error) {\n return jsonRpcError(error);\n },\n };\n return mcp;\n}\n\n/** A private immutable input snapshot, not an authorization token. */\nfunction captureArguments(args: Readonly<Record<string, unknown>>): {\n readonly json: string;\n executionArgs(): Record<string, unknown>;\n} {\n const text = JSON.stringify(args);\n if (typeof text !== \"string\") {\n throw new TenuoConfigurationError(\"arguments must be JSON\");\n }\n return Object.freeze({\n json: text,\n executionArgs: () => plainArgs(JSON.parse(text)),\n });\n}\n\nfunction presentedEnvelope(\n value: unknown,\n): { warrant: string; signature: string; approvals?: string[] } | undefined {\n if (value === null || typeof value !== \"object\") {\n return undefined;\n }\n const tenuo = value as { warrant?: unknown; signature?: unknown; approvals?: unknown };\n if (typeof tenuo.warrant !== \"string\" || tenuo.warrant.length === 0) {\n return undefined;\n }\n if (typeof tenuo.signature !== \"string\" || tenuo.signature.length === 0) {\n return undefined;\n }\n if (tenuo.approvals != null &&\n (!Array.isArray(tenuo.approvals) || tenuo.approvals.some((item) => typeof item !== \"string\"))) {\n return undefined;\n }\n const approvals = tenuo.approvals ?? undefined;\n return {\n warrant: tenuo.warrant,\n signature: tenuo.signature,\n ...(approvals !== undefined && approvals.length > 0 ? { approvals } : {}),\n };\n}\n\nfunction tenuoEnvelope(\n meta: unknown,\n): { warrant: string; signature: string; approvals?: string[] } | undefined {\n if (meta === null || typeof meta !== \"object\") {\n return undefined;\n }\n const root = meta as { tenuo?: unknown; _meta?: unknown };\n const block = root.tenuo ?? (root._meta as { tenuo?: unknown } | undefined)?.tenuo;\n return presentedEnvelope(block);\n}\n\nconst HANDLER_POLICY_KEYS = new Set([\"allow\", \"onReceipt\", \"nonceStore\", \"onNonceStoreError\"]);\nconst VERIFY_OPTION_KEYS = new Set([\n \"allow\",\n \"onReceipt\",\n \"nonceStore\",\n \"onNonceStoreError\",\n \"requestId\",\n]);\nconst ATTACH_OPTION_KEYS = new Set([\"approvals\", \"onReceipt\", \"requestId\"]);\nfunction assertKnownKeys(value: object, known: ReadonlySet<string>, label: string): void {\n const unknown = Object.keys(value).filter((key) => !known.has(key));\n if (unknown[0] !== undefined) {\n throw new TenuoConfigurationError(\n `${label} has unknown key '${unknown[0]}'. Use ${[...known].join(\", \")}.`,\n );\n }\n}\n\nfunction isHandlerPolicy(value: unknown): value is McpHandlerPolicy {\n if (value === null || typeof value !== \"object\" || Array.isArray(value) || typeof value === \"function\") {\n return false;\n }\n const keys = Object.keys(value);\n assertKnownKeys(value, HANDLER_POLICY_KEYS, \"mcp.handler() policy\");\n const record = value as {\n allow?: unknown;\n onReceipt?: unknown;\n nonceStore?: unknown;\n onNonceStoreError?: unknown;\n };\n const hasAllow =\n \"allow\" in record && record.allow !== null && typeof record.allow === \"object\" && !Array.isArray(record.allow);\n const hasReceipt = \"onReceipt\" in record && typeof record.onReceipt === \"function\";\n const hasNonce = \"nonceStore\" in record && record.nonceStore !== null && typeof record.nonceStore === \"object\";\n const hasStoreError = \"onNonceStoreError\" in record && typeof record.onNonceStoreError === \"function\";\n return keys.length === 0 || hasAllow || hasReceipt || hasNonce || hasStoreError;\n}\n\nfunction admitPop(\n store: McpVerifyOptions[\"nonceStore\"],\n signature: string,\n onNonceStoreError?: (error: unknown) => void | Promise<void>,\n): Promise<void> {\n return admitNonce(store, signature, onNonceStoreError, () =>\n new AuthorizationDeniedError(\n \"TENUO_INVALID_POP\",\n \"PoP replay detected — this exact authorization token was already consumed.\",\n ),\n );\n}\n\n/** The request hash core wrote into the decision receipt, when there is one. */\nfunction receiptRequestHash(receipt: string | undefined): string | undefined {\n if (receipt === undefined) {\n return undefined;\n }\n try {\n return loadWasm().sdkVerifyReceipt(receipt).request_hash;\n } catch {\n return undefined;\n }\n}\n\nfunction emitReceipt(\n onReceipt: ((receipt: string) => void | Promise<void>) | undefined,\n receipt: string | undefined,\n session?: SessionContract,\n host?: object,\n): void {\n collectReceipt(receipt, session, host);\n emitIsolatedReceipt(onReceipt, receipt);\n}\n\nfunction plainArgs(value: unknown): Record<string, unknown> {\n if (value instanceof Map) {\n return Object.fromEntries(value);\n }\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return { ...(value as Record<string, unknown>) };\n }\n return {};\n}\n\nfunction jsonRpcError(error: unknown): McpJsonRpcError {\n if (error instanceof TenuoError) {\n const code: TenuoErrorCode = error.code;\n const rpc = code === \"TENUO_APPROVAL_REQUIRED\" ? -32002 : code === \"TENUO_CANONICALIZATION\" ? -32602 : -32001;\n return { code: rpc, message: error.message, data: { tenuo: { code } } };\n }\n const message = error instanceof Error ? error.message : String(error);\n return { code: -32001, message };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n McpAttachOptions,\n McpCallParams,\n McpHandlerPolicy,\n McpJsonRpcError,\n McpVerifyOptions,\n PresentedCall,\n Session as SessionContract,\n TenuoErrorCode,\n TenuoMcp,\n} from \"./api.ts\";\nimport { AuthorizationDeniedError, TenuoConfigurationError, TenuoError } from \"./errors.ts\";\nimport { collectReceipt, emitIsolatedReceipt } from \"./receipts.ts\";\nimport { admitNonce, consumeApprovals, snapshotApprovals } from \"./replay.ts\";\nimport { nativeSession, type Session } from \"./session.ts\";\nimport { loadWasm, type WasmContext, type WasmDecision } from \"./wasm.ts\";\n\nexport type Decide = (decision: WasmDecision, tool: string, native?: object, args?: Record<string, unknown>) => void;\n\n/**\n * Transport-agnostic half of `attach`: authorize locally, then sign\n * proof-of-possession over the call. Shared by `tenuo.present()` and\n * `tenuo.mcp.attach()`.\n */\nexport function presentCall(\n context: WasmContext,\n decide: Decide,\n session: SessionContract,\n name: string,\n args: Readonly<Record<string, unknown>>,\n options: McpAttachOptions | undefined,\n label: string,\n host?: object,\n): { readonly presented: PresentedCall; readonly wireArgs: Record<string, unknown> } {\n if (options !== undefined) {\n assertKnownKeys(options, ATTACH_OPTION_KEYS, `${label} options`);\n }\n const native = nativeSession(session as Session);\n const snapshot = captureArguments(args);\n const local = context.authorize(\n native,\n name,\n snapshot.json,\n options?.approvals,\n undefined,\n options?.requestId,\n );\n emitReceipt(options?.onReceipt, local.receipt, session, host);\n decide(local, name, native, snapshot.executionArgs());\n const envelope = context.signMeta(\n native,\n name,\n snapshot.json,\n Math.floor(Date.now() / 1000),\n options?.approvals ?? null,\n );\n const presented = {\n warrant: envelope.warrant,\n signature: envelope.signature,\n ...(envelope.approvals !== undefined && envelope.approvals.length > 0\n ? { approvals: envelope.approvals }\n : {}),\n };\n return { presented, wireArgs: snapshot.executionArgs() };\n}\n\n/**\n * Transport-agnostic half of `verify`: check a presented warrant chain and\n * proof-of-possession, then apply the host ceiling. Shared by\n * `tenuo.verify()` and `tenuo.mcp.verify()`.\n */\nexport async function verifyPresented(\n context: WasmContext,\n decide: Decide,\n presented: PresentedCall,\n name: string,\n args: Readonly<Record<string, unknown>>,\n options: McpVerifyOptions | undefined,\n label: string,\n host?: object,\n): Promise<Readonly<Record<string, unknown>>> {\n if (options !== undefined) {\n assertKnownKeys(options, VERIFY_OPTION_KEYS, `${label} options`);\n }\n const envelope = presentedEnvelope(presented);\n if (envelope === undefined) {\n throw new TenuoConfigurationError(\n `${label} needs { warrant, signature } from tenuo.present() or tenuo.mcp.attach()`,\n );\n }\n const approvals = snapshotApprovals(envelope.approvals);\n // Capture once: replay admission and receipt callbacks may yield or mutate\n // the caller's object. Execution must use the exact snapshot verified here.\n const snapshot = captureArguments(args);\n const decision = context.authorizePresented(\n envelope.warrant,\n name,\n snapshot.json,\n envelope.signature,\n approvals,\n options?.allow,\n options?.requestId,\n );\n // Rust already signed this envelope. Emit before the nonce store can\n // refuse a replay — otherwise an attacker leaves no audit artifact.\n emitReceipt(options?.onReceipt, decision.receipt, undefined, host);\n if (decision.outcome === \"allow\") {\n await admitPop(options?.nonceStore, envelope.signature, options?.onNonceStoreError);\n // A fresh PoP over the same approvals is a new token; consume the\n // approvals themselves so a nonce store makes them one-use here too.\n await consumeApprovals(\n options?.nonceStore,\n approvals,\n receiptRequestHash(decision.receipt),\n name,\n options?.onNonceStoreError,\n );\n }\n decide(decision, name);\n // Run the host parse of the JSON text the proof covers. The raw host\n // object can contain values that JSON drops.\n return snapshot.executionArgs();\n}\n\nexport function createMcp(context: WasmContext, decide: Decide, host?: object): TenuoMcp {\n const mcp: TenuoMcp = {\n attach(session, name, args, options) {\n const { presented, wireArgs } = presentCall(\n context,\n decide,\n session,\n name,\n args,\n options,\n \"mcp.attach()\",\n host,\n );\n return { name, arguments: wireArgs, _meta: { tenuo: presented } };\n },\n\n async verify(name, args, meta, options) {\n const envelope = tenuoEnvelope(meta);\n if (envelope === undefined) {\n throw new TenuoConfigurationError(\n \"MCP call is missing _meta.tenuo. The client must call tenuo.mcp.attach().\",\n );\n }\n return verifyPresented(context, decide, envelope, name, args, options, \"mcp.verify()\", host);\n },\n\n handler(name, policyOrExecute, maybeExecute?) {\n const policy = isHandlerPolicy(policyOrExecute) ? policyOrExecute : undefined;\n const execute = isHandlerPolicy(policyOrExecute) ? maybeExecute : policyOrExecute;\n if (typeof execute !== \"function\") {\n throw new TenuoConfigurationError(\"mcp.handler() requires an execute function\");\n }\n return async (args, extra) => {\n const authorized = await mcp.verify(name, args, extra?._meta ?? extra?.meta, {\n ...(policy?.allow !== undefined ? { allow: policy.allow } : {}),\n ...(policy?.onReceipt !== undefined ? { onReceipt: policy.onReceipt } : {}),\n ...(policy?.nonceStore !== undefined ? { nonceStore: policy.nonceStore } : {}),\n ...(policy?.onNonceStoreError !== undefined ? { onNonceStoreError: policy.onNonceStoreError } : {}),\n });\n return execute(authorized as never);\n };\n },\n\n jsonRpcError(error) {\n return jsonRpcError(error);\n },\n };\n return mcp;\n}\n\n/** A private immutable input snapshot, not an authorization token. */\nfunction captureArguments(args: Readonly<Record<string, unknown>>): {\n readonly json: string;\n executionArgs(): Record<string, unknown>;\n} {\n const text = JSON.stringify(args);\n if (typeof text !== \"string\") {\n throw new TenuoConfigurationError(\"arguments must be JSON\");\n }\n return Object.freeze({\n json: text,\n executionArgs: () => plainArgs(JSON.parse(text)),\n });\n}\n\nfunction presentedEnvelope(\n value: unknown,\n): { warrant: string; signature: string; approvals?: string[] } | undefined {\n if (value === null || typeof value !== \"object\") {\n return undefined;\n }\n const tenuo = value as { warrant?: unknown; signature?: unknown; approvals?: unknown };\n if (typeof tenuo.warrant !== \"string\" || tenuo.warrant.length === 0) {\n return undefined;\n }\n if (typeof tenuo.signature !== \"string\" || tenuo.signature.length === 0) {\n return undefined;\n }\n if (tenuo.approvals != null &&\n (!Array.isArray(tenuo.approvals) || tenuo.approvals.some((item) => typeof item !== \"string\"))) {\n return undefined;\n }\n const approvals = tenuo.approvals ?? undefined;\n return {\n warrant: tenuo.warrant,\n signature: tenuo.signature,\n ...(approvals !== undefined && approvals.length > 0 ? { approvals } : {}),\n };\n}\n\nfunction tenuoEnvelope(\n meta: unknown,\n): { warrant: string; signature: string; approvals?: string[] } | undefined {\n if (meta === null || typeof meta !== \"object\") {\n return undefined;\n }\n const root = meta as { tenuo?: unknown; _meta?: unknown };\n const block = root.tenuo ?? (root._meta as { tenuo?: unknown } | undefined)?.tenuo;\n return presentedEnvelope(block);\n}\n\nconst HANDLER_POLICY_KEYS = new Set([\"allow\", \"onReceipt\", \"nonceStore\", \"onNonceStoreError\"]);\nconst VERIFY_OPTION_KEYS = new Set([\n \"allow\",\n \"onReceipt\",\n \"nonceStore\",\n \"onNonceStoreError\",\n \"requestId\",\n]);\nconst ATTACH_OPTION_KEYS = new Set([\"approvals\", \"onReceipt\", \"requestId\"]);\nfunction assertKnownKeys(value: object, known: ReadonlySet<string>, label: string): void {\n const unknown = Object.keys(value).filter((key) => !known.has(key));\n if (unknown[0] !== undefined) {\n throw new TenuoConfigurationError(\n `${label} has unknown key '${unknown[0]}'. Use ${[...known].join(\", \")}.`,\n );\n }\n}\n\nfunction isHandlerPolicy(value: unknown): value is McpHandlerPolicy {\n if (value === null || typeof value !== \"object\" || Array.isArray(value) || typeof value === \"function\") {\n return false;\n }\n const keys = Object.keys(value);\n assertKnownKeys(value, HANDLER_POLICY_KEYS, \"mcp.handler() policy\");\n const record = value as {\n allow?: unknown;\n onReceipt?: unknown;\n nonceStore?: unknown;\n onNonceStoreError?: unknown;\n };\n const hasAllow =\n \"allow\" in record && record.allow !== null && typeof record.allow === \"object\" && !Array.isArray(record.allow);\n const hasReceipt = \"onReceipt\" in record && typeof record.onReceipt === \"function\";\n const hasNonce = \"nonceStore\" in record && record.nonceStore !== null && typeof record.nonceStore === \"object\";\n const hasStoreError = \"onNonceStoreError\" in record && typeof record.onNonceStoreError === \"function\";\n return keys.length === 0 || hasAllow || hasReceipt || hasNonce || hasStoreError;\n}\n\nfunction admitPop(\n store: McpVerifyOptions[\"nonceStore\"],\n signature: string,\n onNonceStoreError?: (error: unknown) => void | Promise<void>,\n): Promise<void> {\n if (store === undefined) {\n return Promise.resolve();\n }\n let canonical: string;\n try {\n canonical = `tenuo-pop-v1:${loadWasm().sdkCanonicalMetaSignature(signature)}`;\n } catch (cause) {\n const error = new TenuoConfigurationError(\n \"could not canonicalize an authorized proof for replay protection\",\n );\n error.cause = cause;\n return Promise.reject(error);\n }\n return admitNonce(store, canonical, onNonceStoreError, () =>\n new AuthorizationDeniedError(\n \"TENUO_INVALID_POP\",\n \"PoP replay detected — this authorization token was already consumed.\",\n ),\n );\n}\n\n/** The request hash core wrote into the decision receipt, when there is one. */\nfunction receiptRequestHash(receipt: string | undefined): string | undefined {\n if (receipt === undefined) {\n return undefined;\n }\n try {\n return loadWasm().sdkVerifyReceipt(receipt).request_hash;\n } catch {\n return undefined;\n }\n}\n\nfunction emitReceipt(\n onReceipt: ((receipt: string) => void | Promise<void>) | undefined,\n receipt: string | undefined,\n session?: SessionContract,\n host?: object,\n): void {\n collectReceipt(receipt, session, host);\n emitIsolatedReceipt(onReceipt, receipt);\n}\n\nfunction plainArgs(value: unknown): Record<string, unknown> {\n if (value instanceof Map) {\n return Object.fromEntries(value);\n }\n if (value !== null && typeof value === \"object\" && !Array.isArray(value)) {\n return { ...(value as Record<string, unknown>) };\n }\n return {};\n}\n\nfunction jsonRpcError(error: unknown): McpJsonRpcError {\n if (error instanceof TenuoError) {\n const code: TenuoErrorCode = error.code;\n const rpc = code === \"TENUO_APPROVAL_REQUIRED\" ? -32002 : code === \"TENUO_CANONICALIZATION\" ? -32602 : -32001;\n return { code: rpc, message: error.message, data: { tenuo: { code } } };\n }\n const message = error instanceof Error ? error.message : String(error);\n return { code: -32001, message };\n}\n"]}
|
package/dist/wasm.d.ts
CHANGED
|
@@ -261,6 +261,7 @@ type Generated = {
|
|
|
261
261
|
sdkInspectWarrant(wire: string): WasmInspect;
|
|
262
262
|
sdkDiagnoseConstraints(wire: string, tool: string, args: unknown): WasmConstraintDiagnostics;
|
|
263
263
|
sdkInspectParts(payloadHex: string, signatureHex: string): WasmInspect;
|
|
264
|
+
sdkCanonicalMetaSignature(signature: string): string;
|
|
264
265
|
sdkProtocolLimits(): WasmProtocolLimits;
|
|
265
266
|
sdkPublicKeyFromHolderKey(holderSecret: Uint8Array): string;
|
|
266
267
|
sdkSignApproval(session: WasmSession, tool: string, args: unknown, approverSecret: Uint8Array, externalId: string, asOf?: number): string;
|
package/dist/wasm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm.js","sourceRoot":"","sources":["../src/wasm.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRequire } from \"node:module\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { TenuoConfigurationError } from \"./errors.ts\";\nimport type { TenuoErrorCode } from \"./api.ts\";\n\nexport type WasmDecision = {\n outcome: \"allow\" | \"deny\" | \"approval_required\";\n code?: TenuoErrorCode;\n field?: string;\n message?: string;\n args?: Record<string, unknown>;\n tool?: string;\n required?: number;\n received?: number;\n receipt?: string;\n};\n\nexport type WasmInspect = {\n payload_hex: string;\n signature_hex: string;\n id: string;\n};\n\nexport type ConstraintViolationKind =\n | \"tool_not_authorized\"\n | \"unknown_field\"\n | \"missing_required\"\n | \"constraint_mismatch\";\n\nexport type ConstraintDiagnostics = {\n closedWorld: boolean;\n violations: Array<{\n field: string;\n kind: ConstraintViolationKind;\n reason: string;\n }>;\n};\n\ntype WasmConstraintDiagnostics = Omit<ConstraintDiagnostics, \"closedWorld\"> & {\n closed_world: boolean;\n};\n\nexport type WasmReceipt = {\n authentic: true;\n /** Hex key the receipt is signed under — resolve against your authorizer set. */\n signer_key: string;\n outcome: \"allow\" | \"deny\";\n action: string;\n decision_code?: string;\n request_id: string;\n /** Version of the revocation list in force, when it carried one. */\n srl_version?: number;\n /**\n * SHA-256 (hex) of the revocation list bytes in force at decision time.\n * Absent means no revocation data was loaded — a different claim from a\n * loaded list that revoked nothing.\n */\n srl_hash?: string;\n /**\n * SHA-256 (hex) commitment to the canonical invocation this decision was\n * made over. Absent when the arguments could not be canonicalized — never\n * zero-filled, so absence is a claim rather than a value.\n */\n request_hash?: string;\n /** SHA-256 (hex) of the host ceiling applied to this decision. */\n policy_definition_hash?: string;\n /**\n * SHA-256 (hex) of the previous receipt from this signer. Absent on the\n * first receipt, or when the deployment does not chain. A broken link means\n * a receipt was removed from the stream.\n */\n prev_receipt_hash?: string;\n /** SHA-256 (hex) of the trusted root set in force at decision time. */\n trusted_roots_hash?: string;\n};\n\nexport type WasmReceiptChain = {\n signer_key: string;\n outcome: \"allow\" | \"deny\";\n decision_code?: string;\n timestamp: number;\n /** The embedded chain verifies to a supplied root at the decision instant. */\n chain_valid: boolean;\n /** Canonical error name when it does not. */\n chain_error?: string;\n /**\n * Deny receipts only: the chain failure matches the stated decision_code,\n * so the embedded authority independently corroborates the refusal.\n */\n corroborates_denial?: boolean;\n root_issuer?: string;\n leaf_holder?: string;\n};\n\nexport type WasmSession = object;\n\n/** Mirrors `SessionInfoDto` in tenuo-wasm. Snake case is the WASM boundary. */\nexport type WasmSessionInfo = {\n kind: \"execution\" | \"issuer\";\n holder_public_key: string;\n root_public_key: string;\n depth: number;\n max_depth: number;\n terminal: boolean;\n expires_at: number;\n tools: string[];\n warrant_ids: string[];\n can_authorize: boolean;\n clearance?: number;\n session_id?: string;\n agent_id?: string;\n issuable_tools?: string[];\n max_issue_depth?: number;\n required_approvers?: string[];\n min_approvals?: number;\n approval_gated_tools: string[];\n};\n\n/** Security limits exported by tenuo-core; TypeScript must not redefine them. */\nexport type WasmProtocolLimits = {\n max_delegation_depth: number;\n max_warrant_ttl_seconds: number;\n};\n\n/** Mirrors `NarrowOptions` in tenuo-wasm. Unknown keys are rejected there. */\nexport type WasmNarrowOptions = {\n holder?: string;\n ttlSeconds?: number;\n terminal?: boolean;\n maxDepth?: number;\n clearance?: number | string;\n agentId?: string;\n addApprovers?: string[];\n minApprovals?: number;\n};\n\nexport type WasmRequireApproval = {\n approvers: string[];\n min: number;\n tools?: string[];\n gates?: Record<string, { message?: string; args?: Record<string, unknown> }>;\n};\n\n/** Mirrors `MintOptions` in tenuo-wasm. */\nexport type WasmMintOptions = {\n kind?: \"execution\" | \"issuer\";\n allow?: unknown;\n ttlSeconds?: number;\n holder?: string;\n maxDepth?: number;\n clearance?: number | string;\n sessionId?: string;\n agentId?: string;\n requireApproval?: WasmRequireApproval;\n issuableTools?: string[];\n constraintBounds?: unknown;\n maxIssueDepth?: number;\n};\n\n/** Mirrors `IssueOptions` in tenuo-wasm. */\nexport type WasmIssueOptions = {\n allow: unknown;\n holder: string;\n ttlSeconds?: number;\n maxDepth?: number;\n clearance?: number | string;\n sessionId?: string;\n agentId?: string;\n requireApproval?: { approvers: string[]; min: number };\n};\n\nexport type WasmExplainField = {\n field: string;\n kind: string;\n constraint: unknown;\n value?: unknown;\n satisfied: boolean;\n reason_code?: string;\n reason?: string;\n};\n\nexport type WasmExplain = {\n tool: string;\n kind: \"execution\" | \"issuer\";\n outcome: \"allow\" | \"deny\";\n code?: TenuoErrorCode;\n field?: string;\n message?: string;\n tool_granted: boolean;\n fields: WasmExplainField[];\n unknown_fields: string[];\n missing_fields: string[];\n expired: boolean;\n expires_at: number;\n chain_valid: boolean;\n chain_error?: TenuoErrorCode;\n};\n\nexport type WasmApprovalRequest = {\n request_id: string;\n warrant_id: string;\n tool: string;\n args: Record<string, unknown>;\n request_hash: string;\n holder_public_key: string;\n required_approvers: string[];\n min_approvals: number;\n warrant_expires_at: number;\n created_at: number;\n message: string;\n};\n\nexport type WasmAttestation = {\n version: number;\n canonicalization: string;\n warrant_id: string;\n tool: string;\n request_hash: string;\n holder_key_hex: string;\n args_canonical_cbor_b64: string;\n signer_key_hex: string;\n signature_b64: string;\n};\n\nexport type WasmApprovalInfo = {\n approver_public_key: string;\n request_hash: string;\n nonce: string;\n external_id: string;\n approved_at: number;\n expires_at: number;\n expired: boolean;\n signature_valid: boolean;\n error?: string;\n};\n\nexport type WasmSrlInfo = {\n version: number;\n issued_at: number;\n issuer_public_key: string;\n revoked_ids: string[];\n signature_valid: boolean;\n};\n\nexport type WasmContext = {\n withReceiptSigner(secret: Uint8Array): WasmContext;\n mint(\n allow: unknown,\n ttlSeconds: number,\n requireApproval?: unknown,\n holderHex?: string,\n maxDepth?: number,\n ): WasmSession;\n mintExtended(options: WasmMintOptions): WasmSession;\n narrow(session: WasmSession, allow: unknown, options?: WasmNarrowOptions): WasmSession;\n issue(issuer: WasmSession, options: WasmIssueOptions): WasmSession;\n issuerPublicKey(): string;\n explain(session: WasmSession, tool: string, args: unknown): WasmExplain;\n approvalRequest(session: WasmSession, tool: string, args: unknown): WasmApprovalRequest;\n approvalContextAttestation(session: WasmSession, tool: string, args: unknown): WasmAttestation;\n signRevocationListVersioned(ids: string[], version?: number): string;\n authorize(\n session: WasmSession,\n tool: string,\n args: unknown,\n approvals?: unknown,\n toolAllow?: unknown,\n requestId?: string,\n ): WasmDecision;\n authorizeAsOf(\n session: WasmSession,\n tool: string,\n args: unknown,\n asOf: number,\n approvals?: unknown,\n toolAllow?: unknown,\n ): WasmDecision;\n loadRevocationList(srl: string): void;\n signRevocationList(ids: string[]): string;\n signPop(session: WasmSession, tool: string, args: unknown): string;\n signMeta(\n session: WasmSession,\n tool: string,\n argsJson: string,\n timestamp: number,\n approvals?: unknown,\n ): { warrant: string; signature: string; approvals?: string[] };\n /** Holder proof only; does not authorize execution. */\n verifyMetaPop(\n warrant: string,\n signature: string,\n tool: string,\n argsJson: string,\n timestamp: number,\n ): boolean;\n /** Compatibility alias for verifyMetaPop. */\n verifyMeta(\n warrant: string,\n signature: string,\n tool: string,\n argsJson: string,\n timestamp: number,\n ): boolean;\n authorizePresented(\n warrants: unknown,\n tool: string,\n args: unknown,\n pop: string,\n approvals?: unknown,\n toolAllow?: unknown,\n requestId?: string,\n ): WasmDecision;\n};\n\ntype Generated = {\n SdkContext: {\n new (): WasmContext;\n fromTrustedRoots(roots: string[]): WasmContext;\n fromIssuerSecret(secret: Uint8Array, extraRoots?: string[]): WasmContext;\n };\n SdkSession: {\n fromWire(warrant: string, holder: Uint8Array): WasmSession;\n fromParts(payloadHex: string, signatureHex: string, holder: Uint8Array): WasmSession;\n fromChain(parts: unknown, holder: Uint8Array): WasmSession;\n };\n sdkInspectWarrant(wire: string): WasmInspect;\n sdkDiagnoseConstraints(wire: string, tool: string, args: unknown): WasmConstraintDiagnostics;\n sdkInspectParts(payloadHex: string, signatureHex: string): WasmInspect;\n sdkProtocolLimits(): WasmProtocolLimits;\n sdkPublicKeyFromHolderKey(holderSecret: Uint8Array): string;\n sdkSignApproval(\n session: WasmSession,\n tool: string,\n args: unknown,\n approverSecret: Uint8Array,\n externalId: string,\n asOf?: number,\n ): string;\n sdkSignApprovalForRequest(\n requestHashHex: string,\n approverSecret: Uint8Array,\n externalId: string,\n ttlSeconds?: number,\n warrantExpiresAt?: number,\n ): string;\n sdkInspectApproval(envelope: string | Uint8Array): WasmApprovalInfo;\n sdkSignRevocationList(ids: string[], issuerSecret: Uint8Array): string;\n sdkSignRevocationListVersioned(ids: string[], version: number | undefined, issuerSecret: Uint8Array): string;\n sdkSignPublishedRevocationList(ids: string[], version: number, issuerSecret: Uint8Array): string;\n sdkInspectRevocationList(wire: string): WasmSrlInfo;\n sdkVerifyReceipt(wire: string): WasmReceipt;\n sdkVerifyReceiptChain(wire: string, roots: string[]): WasmReceiptChain;\n approval_requirement(\n warrantB64: string,\n tool: string,\n args: unknown,\n ): ApprovalRequirement & { error?: string };\n inspect_approval_gate(\n warrantB64: string,\n tool: string,\n ): ApprovalGateInspection & { error?: string };\n evaluate_approval_gates(\n warrantB64: string,\n tool: string,\n args: unknown,\n ): { approval_required: boolean; tool: string; error?: string };\n parse_strict_json(jsonText: string): void;\n shlex_inspect(allow: string[], command: string): ShlexCheck;\n};\n\n/** Decision from the core Shlex check. The same object Python `Shlex.check` returns. */\nexport interface ShlexCheck {\n allowed: boolean;\n reason: string;\n tokens: string[];\n operators: string[];\n expansion: string[];\n controls: string[];\n binary_allowed: boolean;\n}\n\nlet loaded: Generated | undefined;\n\nfunction generatedPath(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n return join(here, \"generated\", \"tenuo_wasm.js\");\n}\n\nexport function wasmAvailable(): boolean {\n return existsSync(generatedPath());\n}\n\nconst WASM_LOAD_HINT =\n \"WASM core is missing from this @tenuo/core install. @tenuo/core is Node 20+ only (not a bundler target). If this is Next.js/webpack, set serverExternalPackages: ['@tenuo/core']. Do not run wasm-pack in the consuming app.\";\n\nexport function loadWasm(): Generated {\n if (loaded) {\n return loaded;\n }\n const path = generatedPath();\n if (!existsSync(path)) {\n throw new TenuoConfigurationError(WASM_LOAD_HINT, \"TENUO_NOT_READY\");\n }\n try {\n const require = createRequire(import.meta.url);\n loaded = require(path) as Generated;\n return loaded;\n } catch (error) {\n const wrapped = new TenuoConfigurationError(WASM_LOAD_HINT, \"TENUO_NOT_READY\");\n wrapped.cause = error;\n throw wrapped;\n }\n}\n\nexport function createDevContext(receiptSigner?: Uint8Array): WasmContext {\n const { SdkContext } = loadWasm();\n let context: WasmContext = new SdkContext();\n if (receiptSigner !== undefined) {\n context = context.withReceiptSigner(receiptSigner);\n }\n return context;\n}\n\nexport function protocolLimits(): WasmProtocolLimits {\n return loadWasm().sdkProtocolLimits();\n}\n\nexport function createVerifierContext(\n rootHexes: readonly string[],\n revocationList?: string,\n receiptSigner?: Uint8Array,\n): WasmContext {\n const { SdkContext } = loadWasm();\n let context = SdkContext.fromTrustedRoots([...rootHexes]);\n if (receiptSigner !== undefined) {\n context = context.withReceiptSigner(receiptSigner);\n }\n if (revocationList !== undefined && revocationList.length > 0) {\n context.loadRevocationList(revocationList);\n }\n return context;\n}\n\nexport function createIssuerContext(\n secret: Uint8Array,\n extraRootHexes: readonly string[],\n receiptSigner?: Uint8Array,\n): WasmContext {\n const { SdkContext } = loadWasm();\n let context = SdkContext.fromIssuerSecret(secret, [...extraRootHexes]);\n if (receiptSigner !== undefined) {\n context = context.withReceiptSigner(receiptSigner);\n }\n return context;\n}\n\nexport function importSessionFromWire(warrant: string, holderKey: Uint8Array): WasmSession {\n const { SdkSession } = loadWasm();\n return SdkSession.fromWire(warrant, holderKey);\n}\n\nexport function importSessionFromParts(\n payloadHex: string,\n signatureHex: string,\n holderKey: Uint8Array,\n): WasmSession {\n const { SdkSession } = loadWasm();\n return SdkSession.fromParts(payloadHex, signatureHex, holderKey);\n}\n\nexport function importSessionFromChain(parts: unknown, holderKey: Uint8Array): WasmSession {\n const { SdkSession } = loadWasm();\n return SdkSession.fromChain(parts, holderKey);\n}\n\nexport function inspectWarrant(wire: string): WasmInspect {\n return loadWasm().sdkInspectWarrant(wire);\n}\n\n/**\n * List every capability-constraint failure in deterministic order.\n * Diagnostic only: this does not verify signatures, expiry, revocation,\n * approvals, or proof-of-possession, and must not be used to authorize.\n */\nexport function diagnoseConstraints(\n wire: string,\n tool: string,\n args: unknown,\n): ConstraintDiagnostics {\n const result = loadWasm().sdkDiagnoseConstraints(wire, tool, args);\n return { closedWorld: result.closed_world, violations: result.violations };\n}\n\nexport function inspectParts(payloadHex: string, signatureHex: string): WasmInspect {\n return loadWasm().sdkInspectParts(payloadHex, signatureHex);\n}\n\n/** Hex public key for a 32-byte holder secret. Ed25519, derived in Rust. */\nexport function publicKeyHexFromHolderKey(holderSecret: Uint8Array): string {\n return loadWasm().sdkPublicKeyFromHolderKey(holderSecret);\n}\n\nexport type ApprovalRequirementStatus = \"not_gated\" | \"exempt\" | \"required\" | \"denied\";\n\nexport type ApprovalRequirement = {\n status: ApprovalRequirementStatus;\n tool: string;\n kind?: \"whole_tool\" | \"argument\";\n argument?: string;\n arguments: string[];\n message?: string;\n code?: string;\n reason?: string;\n};\n\nexport type ApprovalGateInspection = {\n kind: \"none\" | \"whole_tool\" | \"conditional\" | \"unknown\";\n tool: string;\n arguments: string[];\n message?: string;\n};\n\nfunction loadApprovalWasm() {\n return loadWasm();\n}\n\nfunction throwIfGateError(error: string | undefined): void {\n if (error) {\n throw new TenuoConfigurationError(error);\n }\n}\n\n/**\n * Parse JSON text and reject a repeated key in any object.\n *\n * `verify()` receives an object the host already parsed. A duplicate key is\n * gone by then. Call this while the text is still available. After the check,\n * the value is `JSON.parse` of the original text, so each key is an own data\n * property and `null` stays `null`.\n */\nexport function parseStrictJson(text: string): unknown {\n loadWasm().parse_strict_json(text);\n return JSON.parse(text);\n}\n\n/**\n * The core's Shlex decision for one command.\n *\n * `allow` is the binary allowlist. Each entry matches the command word\n * literally, and any command word containing `..` is rejected. The reason is\n * the same string the warrant uses.\n */\nexport function checkShlex(allow: readonly string[], command: string): ShlexCheck {\n return loadWasm().shlex_inspect([...allow], command);\n}\n\n/**\n * Typed preflight of a warrant's approval gates for `(tool, args)`.\n *\n * Capability constraints are checked first. `denied` means the authorizer\n * will refuse the call — do not collect approval. Malformed encodings throw\n * (fail-closed).\n */\nexport function approvalRequirement(\n warrantB64: string,\n tool: string,\n args: Record<string, unknown>,\n): ApprovalRequirement {\n const result = loadApprovalWasm().approval_requirement(warrantB64, tool, args);\n throwIfGateError(result.error);\n return result;\n}\n\n/** Inspect how a warrant gates `tool`, without evaluating arguments. */\nexport function inspectApprovalGate(warrantB64: string, tool: string): ApprovalGateInspection {\n const result = loadApprovalWasm().inspect_approval_gate(warrantB64, tool);\n throwIfGateError(result.error);\n return result;\n}\n\n/**\n * Gate-map-only boolean. Does not run capability checks, so split-view\n * callers (PoP args vs constraint args) still see a firing gate. Prefer\n * {@link approvalRequirement} when the caller must distinguish `denied`.\n */\nexport function evaluateApprovalGates(\n warrantB64: string,\n tool: string,\n args: Record<string, unknown>,\n): boolean {\n const result = loadApprovalWasm().evaluate_approval_gates(warrantB64, tool, args);\n throwIfGateError(result.error);\n return result.approval_required;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"wasm.js","sourceRoot":"","sources":["../src/wasm.ts"],"names":[],"mappings":"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","sourcesContent":["import { createRequire } from \"node:module\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { TenuoConfigurationError } from \"./errors.ts\";\nimport type { TenuoErrorCode } from \"./api.ts\";\n\nexport type WasmDecision = {\n outcome: \"allow\" | \"deny\" | \"approval_required\";\n code?: TenuoErrorCode;\n field?: string;\n message?: string;\n args?: Record<string, unknown>;\n tool?: string;\n required?: number;\n received?: number;\n receipt?: string;\n};\n\nexport type WasmInspect = {\n payload_hex: string;\n signature_hex: string;\n id: string;\n};\n\nexport type ConstraintViolationKind =\n | \"tool_not_authorized\"\n | \"unknown_field\"\n | \"missing_required\"\n | \"constraint_mismatch\";\n\nexport type ConstraintDiagnostics = {\n closedWorld: boolean;\n violations: Array<{\n field: string;\n kind: ConstraintViolationKind;\n reason: string;\n }>;\n};\n\ntype WasmConstraintDiagnostics = Omit<ConstraintDiagnostics, \"closedWorld\"> & {\n closed_world: boolean;\n};\n\nexport type WasmReceipt = {\n authentic: true;\n /** Hex key the receipt is signed under — resolve against your authorizer set. */\n signer_key: string;\n outcome: \"allow\" | \"deny\";\n action: string;\n decision_code?: string;\n request_id: string;\n /** Version of the revocation list in force, when it carried one. */\n srl_version?: number;\n /**\n * SHA-256 (hex) of the revocation list bytes in force at decision time.\n * Absent means no revocation data was loaded — a different claim from a\n * loaded list that revoked nothing.\n */\n srl_hash?: string;\n /**\n * SHA-256 (hex) commitment to the canonical invocation this decision was\n * made over. Absent when the arguments could not be canonicalized — never\n * zero-filled, so absence is a claim rather than a value.\n */\n request_hash?: string;\n /** SHA-256 (hex) of the host ceiling applied to this decision. */\n policy_definition_hash?: string;\n /**\n * SHA-256 (hex) of the previous receipt from this signer. Absent on the\n * first receipt, or when the deployment does not chain. A broken link means\n * a receipt was removed from the stream.\n */\n prev_receipt_hash?: string;\n /** SHA-256 (hex) of the trusted root set in force at decision time. */\n trusted_roots_hash?: string;\n};\n\nexport type WasmReceiptChain = {\n signer_key: string;\n outcome: \"allow\" | \"deny\";\n decision_code?: string;\n timestamp: number;\n /** The embedded chain verifies to a supplied root at the decision instant. */\n chain_valid: boolean;\n /** Canonical error name when it does not. */\n chain_error?: string;\n /**\n * Deny receipts only: the chain failure matches the stated decision_code,\n * so the embedded authority independently corroborates the refusal.\n */\n corroborates_denial?: boolean;\n root_issuer?: string;\n leaf_holder?: string;\n};\n\nexport type WasmSession = object;\n\n/** Mirrors `SessionInfoDto` in tenuo-wasm. Snake case is the WASM boundary. */\nexport type WasmSessionInfo = {\n kind: \"execution\" | \"issuer\";\n holder_public_key: string;\n root_public_key: string;\n depth: number;\n max_depth: number;\n terminal: boolean;\n expires_at: number;\n tools: string[];\n warrant_ids: string[];\n can_authorize: boolean;\n clearance?: number;\n session_id?: string;\n agent_id?: string;\n issuable_tools?: string[];\n max_issue_depth?: number;\n required_approvers?: string[];\n min_approvals?: number;\n approval_gated_tools: string[];\n};\n\n/** Security limits exported by tenuo-core; TypeScript must not redefine them. */\nexport type WasmProtocolLimits = {\n max_delegation_depth: number;\n max_warrant_ttl_seconds: number;\n};\n\n/** Mirrors `NarrowOptions` in tenuo-wasm. Unknown keys are rejected there. */\nexport type WasmNarrowOptions = {\n holder?: string;\n ttlSeconds?: number;\n terminal?: boolean;\n maxDepth?: number;\n clearance?: number | string;\n agentId?: string;\n addApprovers?: string[];\n minApprovals?: number;\n};\n\nexport type WasmRequireApproval = {\n approvers: string[];\n min: number;\n tools?: string[];\n gates?: Record<string, { message?: string; args?: Record<string, unknown> }>;\n};\n\n/** Mirrors `MintOptions` in tenuo-wasm. */\nexport type WasmMintOptions = {\n kind?: \"execution\" | \"issuer\";\n allow?: unknown;\n ttlSeconds?: number;\n holder?: string;\n maxDepth?: number;\n clearance?: number | string;\n sessionId?: string;\n agentId?: string;\n requireApproval?: WasmRequireApproval;\n issuableTools?: string[];\n constraintBounds?: unknown;\n maxIssueDepth?: number;\n};\n\n/** Mirrors `IssueOptions` in tenuo-wasm. */\nexport type WasmIssueOptions = {\n allow: unknown;\n holder: string;\n ttlSeconds?: number;\n maxDepth?: number;\n clearance?: number | string;\n sessionId?: string;\n agentId?: string;\n requireApproval?: { approvers: string[]; min: number };\n};\n\nexport type WasmExplainField = {\n field: string;\n kind: string;\n constraint: unknown;\n value?: unknown;\n satisfied: boolean;\n reason_code?: string;\n reason?: string;\n};\n\nexport type WasmExplain = {\n tool: string;\n kind: \"execution\" | \"issuer\";\n outcome: \"allow\" | \"deny\";\n code?: TenuoErrorCode;\n field?: string;\n message?: string;\n tool_granted: boolean;\n fields: WasmExplainField[];\n unknown_fields: string[];\n missing_fields: string[];\n expired: boolean;\n expires_at: number;\n chain_valid: boolean;\n chain_error?: TenuoErrorCode;\n};\n\nexport type WasmApprovalRequest = {\n request_id: string;\n warrant_id: string;\n tool: string;\n args: Record<string, unknown>;\n request_hash: string;\n holder_public_key: string;\n required_approvers: string[];\n min_approvals: number;\n warrant_expires_at: number;\n created_at: number;\n message: string;\n};\n\nexport type WasmAttestation = {\n version: number;\n canonicalization: string;\n warrant_id: string;\n tool: string;\n request_hash: string;\n holder_key_hex: string;\n args_canonical_cbor_b64: string;\n signer_key_hex: string;\n signature_b64: string;\n};\n\nexport type WasmApprovalInfo = {\n approver_public_key: string;\n request_hash: string;\n nonce: string;\n external_id: string;\n approved_at: number;\n expires_at: number;\n expired: boolean;\n signature_valid: boolean;\n error?: string;\n};\n\nexport type WasmSrlInfo = {\n version: number;\n issued_at: number;\n issuer_public_key: string;\n revoked_ids: string[];\n signature_valid: boolean;\n};\n\nexport type WasmContext = {\n withReceiptSigner(secret: Uint8Array): WasmContext;\n mint(\n allow: unknown,\n ttlSeconds: number,\n requireApproval?: unknown,\n holderHex?: string,\n maxDepth?: number,\n ): WasmSession;\n mintExtended(options: WasmMintOptions): WasmSession;\n narrow(session: WasmSession, allow: unknown, options?: WasmNarrowOptions): WasmSession;\n issue(issuer: WasmSession, options: WasmIssueOptions): WasmSession;\n issuerPublicKey(): string;\n explain(session: WasmSession, tool: string, args: unknown): WasmExplain;\n approvalRequest(session: WasmSession, tool: string, args: unknown): WasmApprovalRequest;\n approvalContextAttestation(session: WasmSession, tool: string, args: unknown): WasmAttestation;\n signRevocationListVersioned(ids: string[], version?: number): string;\n authorize(\n session: WasmSession,\n tool: string,\n args: unknown,\n approvals?: unknown,\n toolAllow?: unknown,\n requestId?: string,\n ): WasmDecision;\n authorizeAsOf(\n session: WasmSession,\n tool: string,\n args: unknown,\n asOf: number,\n approvals?: unknown,\n toolAllow?: unknown,\n ): WasmDecision;\n loadRevocationList(srl: string): void;\n signRevocationList(ids: string[]): string;\n signPop(session: WasmSession, tool: string, args: unknown): string;\n signMeta(\n session: WasmSession,\n tool: string,\n argsJson: string,\n timestamp: number,\n approvals?: unknown,\n ): { warrant: string; signature: string; approvals?: string[] };\n /** Holder proof only; does not authorize execution. */\n verifyMetaPop(\n warrant: string,\n signature: string,\n tool: string,\n argsJson: string,\n timestamp: number,\n ): boolean;\n /** Compatibility alias for verifyMetaPop. */\n verifyMeta(\n warrant: string,\n signature: string,\n tool: string,\n argsJson: string,\n timestamp: number,\n ): boolean;\n authorizePresented(\n warrants: unknown,\n tool: string,\n args: unknown,\n pop: string,\n approvals?: unknown,\n toolAllow?: unknown,\n requestId?: string,\n ): WasmDecision;\n};\n\ntype Generated = {\n SdkContext: {\n new (): WasmContext;\n fromTrustedRoots(roots: string[]): WasmContext;\n fromIssuerSecret(secret: Uint8Array, extraRoots?: string[]): WasmContext;\n };\n SdkSession: {\n fromWire(warrant: string, holder: Uint8Array): WasmSession;\n fromParts(payloadHex: string, signatureHex: string, holder: Uint8Array): WasmSession;\n fromChain(parts: unknown, holder: Uint8Array): WasmSession;\n };\n sdkInspectWarrant(wire: string): WasmInspect;\n sdkDiagnoseConstraints(wire: string, tool: string, args: unknown): WasmConstraintDiagnostics;\n sdkInspectParts(payloadHex: string, signatureHex: string): WasmInspect;\n sdkCanonicalMetaSignature(signature: string): string;\n sdkProtocolLimits(): WasmProtocolLimits;\n sdkPublicKeyFromHolderKey(holderSecret: Uint8Array): string;\n sdkSignApproval(\n session: WasmSession,\n tool: string,\n args: unknown,\n approverSecret: Uint8Array,\n externalId: string,\n asOf?: number,\n ): string;\n sdkSignApprovalForRequest(\n requestHashHex: string,\n approverSecret: Uint8Array,\n externalId: string,\n ttlSeconds?: number,\n warrantExpiresAt?: number,\n ): string;\n sdkInspectApproval(envelope: string | Uint8Array): WasmApprovalInfo;\n sdkSignRevocationList(ids: string[], issuerSecret: Uint8Array): string;\n sdkSignRevocationListVersioned(ids: string[], version: number | undefined, issuerSecret: Uint8Array): string;\n sdkSignPublishedRevocationList(ids: string[], version: number, issuerSecret: Uint8Array): string;\n sdkInspectRevocationList(wire: string): WasmSrlInfo;\n sdkVerifyReceipt(wire: string): WasmReceipt;\n sdkVerifyReceiptChain(wire: string, roots: string[]): WasmReceiptChain;\n approval_requirement(\n warrantB64: string,\n tool: string,\n args: unknown,\n ): ApprovalRequirement & { error?: string };\n inspect_approval_gate(\n warrantB64: string,\n tool: string,\n ): ApprovalGateInspection & { error?: string };\n evaluate_approval_gates(\n warrantB64: string,\n tool: string,\n args: unknown,\n ): { approval_required: boolean; tool: string; error?: string };\n parse_strict_json(jsonText: string): void;\n shlex_inspect(allow: string[], command: string): ShlexCheck;\n};\n\n/** Decision from the core Shlex check. The same object Python `Shlex.check` returns. */\nexport interface ShlexCheck {\n allowed: boolean;\n reason: string;\n tokens: string[];\n operators: string[];\n expansion: string[];\n controls: string[];\n binary_allowed: boolean;\n}\n\nlet loaded: Generated | undefined;\n\nfunction generatedPath(): string {\n const here = dirname(fileURLToPath(import.meta.url));\n return join(here, \"generated\", \"tenuo_wasm.js\");\n}\n\nexport function wasmAvailable(): boolean {\n return existsSync(generatedPath());\n}\n\nconst WASM_LOAD_HINT =\n \"WASM core is missing from this @tenuo/core install. @tenuo/core is Node 20+ only (not a bundler target). If this is Next.js/webpack, set serverExternalPackages: ['@tenuo/core']. Do not run wasm-pack in the consuming app.\";\n\nexport function loadWasm(): Generated {\n if (loaded) {\n return loaded;\n }\n const path = generatedPath();\n if (!existsSync(path)) {\n throw new TenuoConfigurationError(WASM_LOAD_HINT, \"TENUO_NOT_READY\");\n }\n try {\n const require = createRequire(import.meta.url);\n loaded = require(path) as Generated;\n return loaded;\n } catch (error) {\n const wrapped = new TenuoConfigurationError(WASM_LOAD_HINT, \"TENUO_NOT_READY\");\n wrapped.cause = error;\n throw wrapped;\n }\n}\n\nexport function createDevContext(receiptSigner?: Uint8Array): WasmContext {\n const { SdkContext } = loadWasm();\n let context: WasmContext = new SdkContext();\n if (receiptSigner !== undefined) {\n context = context.withReceiptSigner(receiptSigner);\n }\n return context;\n}\n\nexport function protocolLimits(): WasmProtocolLimits {\n return loadWasm().sdkProtocolLimits();\n}\n\nexport function createVerifierContext(\n rootHexes: readonly string[],\n revocationList?: string,\n receiptSigner?: Uint8Array,\n): WasmContext {\n const { SdkContext } = loadWasm();\n let context = SdkContext.fromTrustedRoots([...rootHexes]);\n if (receiptSigner !== undefined) {\n context = context.withReceiptSigner(receiptSigner);\n }\n if (revocationList !== undefined && revocationList.length > 0) {\n context.loadRevocationList(revocationList);\n }\n return context;\n}\n\nexport function createIssuerContext(\n secret: Uint8Array,\n extraRootHexes: readonly string[],\n receiptSigner?: Uint8Array,\n): WasmContext {\n const { SdkContext } = loadWasm();\n let context = SdkContext.fromIssuerSecret(secret, [...extraRootHexes]);\n if (receiptSigner !== undefined) {\n context = context.withReceiptSigner(receiptSigner);\n }\n return context;\n}\n\nexport function importSessionFromWire(warrant: string, holderKey: Uint8Array): WasmSession {\n const { SdkSession } = loadWasm();\n return SdkSession.fromWire(warrant, holderKey);\n}\n\nexport function importSessionFromParts(\n payloadHex: string,\n signatureHex: string,\n holderKey: Uint8Array,\n): WasmSession {\n const { SdkSession } = loadWasm();\n return SdkSession.fromParts(payloadHex, signatureHex, holderKey);\n}\n\nexport function importSessionFromChain(parts: unknown, holderKey: Uint8Array): WasmSession {\n const { SdkSession } = loadWasm();\n return SdkSession.fromChain(parts, holderKey);\n}\n\nexport function inspectWarrant(wire: string): WasmInspect {\n return loadWasm().sdkInspectWarrant(wire);\n}\n\n/**\n * List every capability-constraint failure in deterministic order.\n * Diagnostic only: this does not verify signatures, expiry, revocation,\n * approvals, or proof-of-possession, and must not be used to authorize.\n */\nexport function diagnoseConstraints(\n wire: string,\n tool: string,\n args: unknown,\n): ConstraintDiagnostics {\n const result = loadWasm().sdkDiagnoseConstraints(wire, tool, args);\n return { closedWorld: result.closed_world, violations: result.violations };\n}\n\nexport function inspectParts(payloadHex: string, signatureHex: string): WasmInspect {\n return loadWasm().sdkInspectParts(payloadHex, signatureHex);\n}\n\n/** Hex public key for a 32-byte holder secret. Ed25519, derived in Rust. */\nexport function publicKeyHexFromHolderKey(holderSecret: Uint8Array): string {\n return loadWasm().sdkPublicKeyFromHolderKey(holderSecret);\n}\n\nexport type ApprovalRequirementStatus = \"not_gated\" | \"exempt\" | \"required\" | \"denied\";\n\nexport type ApprovalRequirement = {\n status: ApprovalRequirementStatus;\n tool: string;\n kind?: \"whole_tool\" | \"argument\";\n argument?: string;\n arguments: string[];\n message?: string;\n code?: string;\n reason?: string;\n};\n\nexport type ApprovalGateInspection = {\n kind: \"none\" | \"whole_tool\" | \"conditional\" | \"unknown\";\n tool: string;\n arguments: string[];\n message?: string;\n};\n\nfunction loadApprovalWasm() {\n return loadWasm();\n}\n\nfunction throwIfGateError(error: string | undefined): void {\n if (error) {\n throw new TenuoConfigurationError(error);\n }\n}\n\n/**\n * Parse JSON text and reject a repeated key in any object.\n *\n * `verify()` receives an object the host already parsed. A duplicate key is\n * gone by then. Call this while the text is still available. After the check,\n * the value is `JSON.parse` of the original text, so each key is an own data\n * property and `null` stays `null`.\n */\nexport function parseStrictJson(text: string): unknown {\n loadWasm().parse_strict_json(text);\n return JSON.parse(text);\n}\n\n/**\n * The core's Shlex decision for one command.\n *\n * `allow` is the binary allowlist. Each entry matches the command word\n * literally, and any command word containing `..` is rejected. The reason is\n * the same string the warrant uses.\n */\nexport function checkShlex(allow: readonly string[], command: string): ShlexCheck {\n return loadWasm().shlex_inspect([...allow], command);\n}\n\n/**\n * Typed preflight of a warrant's approval gates for `(tool, args)`.\n *\n * Capability constraints are checked first. `denied` means the authorizer\n * will refuse the call — do not collect approval. Malformed encodings throw\n * (fail-closed).\n */\nexport function approvalRequirement(\n warrantB64: string,\n tool: string,\n args: Record<string, unknown>,\n): ApprovalRequirement {\n const result = loadApprovalWasm().approval_requirement(warrantB64, tool, args);\n throwIfGateError(result.error);\n return result;\n}\n\n/** Inspect how a warrant gates `tool`, without evaluating arguments. */\nexport function inspectApprovalGate(warrantB64: string, tool: string): ApprovalGateInspection {\n const result = loadApprovalWasm().inspect_approval_gate(warrantB64, tool);\n throwIfGateError(result.error);\n return result;\n}\n\n/**\n * Gate-map-only boolean. Does not run capability checks, so split-view\n * callers (PoP args vs constraint args) still see a firing gate. Prefer\n * {@link approvalRequirement} when the caller must distinguish `denied`.\n */\nexport function evaluateApprovalGates(\n warrantB64: string,\n tool: string,\n args: Record<string, unknown>,\n): boolean {\n const result = loadApprovalWasm().evaluate_approval_gates(warrantB64, tool, args);\n throwIfGateError(result.error);\n return result.approval_required;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenuo/core",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6-beta.0",
|
|
4
4
|
"description": "Task-scoped authorization for AI agents in TypeScript: signed warrants limit which tools an agent can call and with which arguments, verified by the Tenuo Rust core compiled to WASM (beta).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Tenuo Contributors",
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
"node": ">=20"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@modelcontextprotocol/sdk": "1.
|
|
65
|
+
"@modelcontextprotocol/sdk": "1.32.2",
|
|
66
66
|
"@types/node": "^22.13.10",
|
|
67
67
|
"fast-check": "4.9.0",
|
|
68
68
|
"typescript": "~5.8.2",
|
|
69
|
-
"vitest": "^
|
|
70
|
-
"zod": "
|
|
69
|
+
"vitest": "^4.1.12",
|
|
70
|
+
"zod": "4.6.7"
|
|
71
71
|
}
|
|
72
72
|
}
|