@nexart/ai-execution 0.5.0 → 0.7.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 +238 -9
- package/dist/index.cjs +660 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +267 -3
- package/dist/index.d.ts +267 -3
- package/dist/index.mjs +649 -10
- package/dist/index.mjs.map +1 -1
- package/dist/providers/anthropic.cjs +7 -1
- package/dist/providers/anthropic.cjs.map +1 -1
- package/dist/providers/anthropic.d.cts +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.mjs +7 -1
- package/dist/providers/anthropic.mjs.map +1 -1
- package/dist/providers/openai.cjs +7 -1
- package/dist/providers/openai.cjs.map +1 -1
- package/dist/providers/openai.d.cts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.mjs +7 -1
- package/dist/providers/openai.mjs.map +1 -1
- package/dist/providers/wrap.cjs +7 -1
- package/dist/providers/wrap.cjs.map +1 -1
- package/dist/providers/wrap.d.cts +1 -1
- package/dist/providers/wrap.d.ts +1 -1
- package/dist/providers/wrap.mjs +7 -1
- package/dist/providers/wrap.mjs.map +1 -1
- package/dist/{types-BjEqrksn.d.cts → types-CcqCDPrD.d.cts} +119 -1
- package/dist/{types-BjEqrksn.d.ts → types-CcqCDPrD.d.ts} +119 -1
- package/fixtures/v060/legacy-attestation.json +32 -0
- package/fixtures/v060/original-meta-bundle.json +36 -0
- package/fixtures/v060/pre-v05-bundle.json +29 -0
- package/fixtures/v060/redacted-bundle.json +36 -0
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -12,7 +12,13 @@ var CerVerifyCode = {
|
|
|
12
12
|
ATTESTATION_MISSING: "ATTESTATION_MISSING",
|
|
13
13
|
ATTESTATION_KEY_NOT_FOUND: "ATTESTATION_KEY_NOT_FOUND",
|
|
14
14
|
ATTESTATION_INVALID_SIGNATURE: "ATTESTATION_INVALID_SIGNATURE",
|
|
15
|
-
ATTESTATION_KEY_FORMAT_UNSUPPORTED: "ATTESTATION_KEY_FORMAT_UNSUPPORTED"
|
|
15
|
+
ATTESTATION_KEY_FORMAT_UNSUPPORTED: "ATTESTATION_KEY_FORMAT_UNSUPPORTED",
|
|
16
|
+
// v0.7.0 — Level 4 + AIEF interop codes
|
|
17
|
+
CHAIN_BREAK_DETECTED: "CHAIN_BREAK_DETECTED",
|
|
18
|
+
INCOMPLETE_ARTIFACT: "INCOMPLETE_ARTIFACT",
|
|
19
|
+
VERIFICATION_MATERIAL_UNAVAILABLE: "VERIFICATION_MATERIAL_UNAVAILABLE",
|
|
20
|
+
TOOL_EVIDENCE_MISSING: "TOOL_EVIDENCE_MISSING",
|
|
21
|
+
TOOL_OUTPUT_HASH_MISMATCH: "TOOL_OUTPUT_HASH_MISMATCH"
|
|
16
22
|
};
|
|
17
23
|
|
|
18
24
|
// src/errors.ts
|
|
@@ -108,7 +114,7 @@ function computeOutputHash(output) {
|
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
// src/snapshot.ts
|
|
111
|
-
var PACKAGE_VERSION = "0.
|
|
117
|
+
var PACKAGE_VERSION = "0.7.0";
|
|
112
118
|
function validateParameters(params) {
|
|
113
119
|
const errors = [];
|
|
114
120
|
if (typeof params.temperature !== "number" || !Number.isFinite(params.temperature)) {
|
|
@@ -161,6 +167,9 @@ function createSnapshot(params) {
|
|
|
161
167
|
if (params.workflowId !== void 0) snapshot.workflowId = params.workflowId ?? null;
|
|
162
168
|
if (params.conversationId !== void 0) snapshot.conversationId = params.conversationId ?? null;
|
|
163
169
|
if (params.prevStepHash !== void 0) snapshot.prevStepHash = params.prevStepHash ?? null;
|
|
170
|
+
if (params.toolCalls !== void 0 && params.toolCalls.length > 0) {
|
|
171
|
+
snapshot.toolCalls = params.toolCalls;
|
|
172
|
+
}
|
|
164
173
|
return snapshot;
|
|
165
174
|
}
|
|
166
175
|
function verifySnapshot(snapshot) {
|
|
@@ -268,6 +277,9 @@ function sealCer(snapshot, options) {
|
|
|
268
277
|
if (options?.meta) {
|
|
269
278
|
bundle.meta = options.meta;
|
|
270
279
|
}
|
|
280
|
+
if (options?.declaration) {
|
|
281
|
+
bundle.declaration = options.declaration;
|
|
282
|
+
}
|
|
271
283
|
return bundle;
|
|
272
284
|
}
|
|
273
285
|
function verifyCer(bundle) {
|
|
@@ -459,9 +471,45 @@ function deepRemoveUndefined(value) {
|
|
|
459
471
|
}
|
|
460
472
|
return value;
|
|
461
473
|
}
|
|
474
|
+
function redactPath(obj, path, replacement) {
|
|
475
|
+
const parts = path.split(".");
|
|
476
|
+
const clone = { ...obj };
|
|
477
|
+
let cursor = clone;
|
|
478
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
479
|
+
const key = parts[i];
|
|
480
|
+
if (typeof cursor[key] !== "object" || cursor[key] === null) return clone;
|
|
481
|
+
cursor[key] = { ...cursor[key] };
|
|
482
|
+
cursor = cursor[key];
|
|
483
|
+
}
|
|
484
|
+
const last = parts[parts.length - 1];
|
|
485
|
+
if (last in cursor) cursor[last] = replacement;
|
|
486
|
+
return clone;
|
|
487
|
+
}
|
|
462
488
|
function sanitizeForAttestation(bundle) {
|
|
463
489
|
return deepRemoveUndefined(bundle);
|
|
464
490
|
}
|
|
491
|
+
function sanitizeForStorage(bundle, options) {
|
|
492
|
+
let cleaned = deepRemoveUndefined(bundle);
|
|
493
|
+
if (options?.redactPaths && options.redactPaths.length > 0) {
|
|
494
|
+
const replacement = options.redactWith ?? "[REDACTED]";
|
|
495
|
+
let obj = cleaned;
|
|
496
|
+
for (const path of options.redactPaths) {
|
|
497
|
+
obj = redactPath(obj, path, replacement);
|
|
498
|
+
}
|
|
499
|
+
cleaned = obj;
|
|
500
|
+
}
|
|
501
|
+
return cleaned;
|
|
502
|
+
}
|
|
503
|
+
function sanitizeForStamp(bundle) {
|
|
504
|
+
const core = {
|
|
505
|
+
bundleType: bundle.bundleType,
|
|
506
|
+
certificateHash: bundle.certificateHash,
|
|
507
|
+
createdAt: bundle.createdAt,
|
|
508
|
+
version: bundle.version,
|
|
509
|
+
snapshot: bundle.snapshot
|
|
510
|
+
};
|
|
511
|
+
return deepRemoveUndefined(core);
|
|
512
|
+
}
|
|
465
513
|
function hasAttestation(bundle) {
|
|
466
514
|
if (typeof bundle !== "object" || bundle === null) return false;
|
|
467
515
|
const b = bundle;
|
|
@@ -780,10 +828,10 @@ var M = (a, b = P) => {
|
|
|
780
828
|
return r >= 0n ? r : b + r;
|
|
781
829
|
};
|
|
782
830
|
var modN = (a) => M(a, N);
|
|
783
|
-
var invert = (
|
|
784
|
-
if (
|
|
785
|
-
err("no inverse n=" +
|
|
786
|
-
let a = M(
|
|
831
|
+
var invert = (num2, md) => {
|
|
832
|
+
if (num2 === 0n || md <= 0n)
|
|
833
|
+
err("no inverse n=" + num2 + " mod=" + md);
|
|
834
|
+
let a = M(num2, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;
|
|
787
835
|
while (a !== 0n) {
|
|
788
836
|
const q = b / a, r = b % a;
|
|
789
837
|
const m = x - u * q, n = y - v * q;
|
|
@@ -1000,7 +1048,7 @@ var G = new Point(Gx, Gy, 1n, M(Gx * Gy));
|
|
|
1000
1048
|
var I = new Point(0n, 1n, 1n, 0n);
|
|
1001
1049
|
Point.BASE = G;
|
|
1002
1050
|
Point.ZERO = I;
|
|
1003
|
-
var numTo32bLE = (
|
|
1051
|
+
var numTo32bLE = (num2) => hexToBytes(padh(assertRange(num2, 0n, B256), L2)).reverse();
|
|
1004
1052
|
var bytesToNumLE = (b) => big("0x" + bytesToHex(u8fr(abytes(b)).reverse()));
|
|
1005
1053
|
var pow2 = (x, power) => {
|
|
1006
1054
|
let r = x;
|
|
@@ -1173,10 +1221,10 @@ function clean(...arrays) {
|
|
|
1173
1221
|
function createView(arr) {
|
|
1174
1222
|
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
1175
1223
|
}
|
|
1176
|
-
function utf8ToBytes(
|
|
1177
|
-
if (typeof
|
|
1224
|
+
function utf8ToBytes(str2) {
|
|
1225
|
+
if (typeof str2 !== "string")
|
|
1178
1226
|
throw new Error("string expected");
|
|
1179
|
-
return new Uint8Array(new TextEncoder().encode(
|
|
1227
|
+
return new Uint8Array(new TextEncoder().encode(str2));
|
|
1180
1228
|
}
|
|
1181
1229
|
function toBytes(data) {
|
|
1182
1230
|
if (typeof data === "string")
|
|
@@ -1782,6 +1830,586 @@ async function verifyBundleAttestation(bundle, options) {
|
|
|
1782
1830
|
if (contextLines.length === 0) return sigResult;
|
|
1783
1831
|
return sigResult.ok ? { ok: true, code: CerVerifyCode.OK, details: contextLines } : { ...sigResult, details: [...contextLines, ...sigResult.details ?? []] };
|
|
1784
1832
|
}
|
|
1833
|
+
|
|
1834
|
+
// src/certifyFromProvider.ts
|
|
1835
|
+
import * as crypto5 from "crypto";
|
|
1836
|
+
|
|
1837
|
+
// src/providerExtract.ts
|
|
1838
|
+
function str(v) {
|
|
1839
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
1840
|
+
}
|
|
1841
|
+
function num(v, fallback) {
|
|
1842
|
+
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
1843
|
+
}
|
|
1844
|
+
function numOrNull(v) {
|
|
1845
|
+
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
1846
|
+
}
|
|
1847
|
+
function extractChoicesOutput(response) {
|
|
1848
|
+
const choices = response.choices;
|
|
1849
|
+
if (!Array.isArray(choices) || choices.length === 0) return null;
|
|
1850
|
+
const first = choices[0];
|
|
1851
|
+
if (!first || typeof first !== "object") return null;
|
|
1852
|
+
const msg = first.message;
|
|
1853
|
+
if (!msg || typeof msg !== "object") return null;
|
|
1854
|
+
if (typeof msg.content === "string") return msg.content;
|
|
1855
|
+
if (Array.isArray(msg.content)) {
|
|
1856
|
+
const texts = msg.content.filter((p) => typeof p === "object" && p !== null).map((p) => str(p.text)).filter((t) => t !== null);
|
|
1857
|
+
return texts.length > 0 ? texts.join("\n") : null;
|
|
1858
|
+
}
|
|
1859
|
+
return null;
|
|
1860
|
+
}
|
|
1861
|
+
function extractAnthropicOutput(response) {
|
|
1862
|
+
const content = response.content;
|
|
1863
|
+
if (!Array.isArray(content) || content.length === 0) return null;
|
|
1864
|
+
const first = content[0];
|
|
1865
|
+
if (!first || typeof first !== "object") return null;
|
|
1866
|
+
return str(first.text);
|
|
1867
|
+
}
|
|
1868
|
+
function extractGeminiOutput(response) {
|
|
1869
|
+
const candidates = response.candidates;
|
|
1870
|
+
if (!Array.isArray(candidates) || candidates.length === 0) return null;
|
|
1871
|
+
const first = candidates[0];
|
|
1872
|
+
if (!first || typeof first !== "object") return null;
|
|
1873
|
+
const contentObj = first.content;
|
|
1874
|
+
if (!contentObj || typeof contentObj !== "object") return null;
|
|
1875
|
+
const parts = contentObj.parts;
|
|
1876
|
+
if (!Array.isArray(parts) || parts.length === 0) return null;
|
|
1877
|
+
const part = parts[0];
|
|
1878
|
+
if (!part || typeof part !== "object") return null;
|
|
1879
|
+
return str(part.text);
|
|
1880
|
+
}
|
|
1881
|
+
function extractGenericOutput(response) {
|
|
1882
|
+
return str(response.text) ?? str(response.output_text) ?? (typeof response.output === "string" ? response.output : null) ?? str(response.result) ?? null;
|
|
1883
|
+
}
|
|
1884
|
+
function extractOutput(response) {
|
|
1885
|
+
return extractChoicesOutput(response) ?? extractAnthropicOutput(response) ?? extractGeminiOutput(response) ?? extractGenericOutput(response);
|
|
1886
|
+
}
|
|
1887
|
+
function extractInput(request) {
|
|
1888
|
+
if (Array.isArray(request.messages) && request.messages.length > 0) {
|
|
1889
|
+
return { messages: request.messages };
|
|
1890
|
+
}
|
|
1891
|
+
if (Array.isArray(request.contents) && request.contents.length > 0) {
|
|
1892
|
+
return { contents: request.contents };
|
|
1893
|
+
}
|
|
1894
|
+
if (typeof request.prompt === "string") return request.prompt;
|
|
1895
|
+
if (typeof request.input === "string") return request.input;
|
|
1896
|
+
if (typeof request.input === "object" && request.input !== null) {
|
|
1897
|
+
return request.input;
|
|
1898
|
+
}
|
|
1899
|
+
return null;
|
|
1900
|
+
}
|
|
1901
|
+
function derivePrompt(request) {
|
|
1902
|
+
if (typeof request.prompt === "string") return request.prompt;
|
|
1903
|
+
if (Array.isArray(request.messages)) {
|
|
1904
|
+
const msgs = request.messages;
|
|
1905
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
1906
|
+
const msg = msgs[i];
|
|
1907
|
+
if (msg.role === "user" || msg.role === "human") {
|
|
1908
|
+
const content = msg.content;
|
|
1909
|
+
if (typeof content === "string") return content;
|
|
1910
|
+
if (Array.isArray(content)) {
|
|
1911
|
+
const text = content.filter((p) => typeof p === "object" && p !== null).map((p) => str(p.text)).filter((t) => t !== null).join("\n");
|
|
1912
|
+
if (text) return text;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
if (Array.isArray(request.contents)) {
|
|
1918
|
+
const contents = request.contents;
|
|
1919
|
+
for (let i = contents.length - 1; i >= 0; i--) {
|
|
1920
|
+
const c = contents[i];
|
|
1921
|
+
if (c.role === "user") {
|
|
1922
|
+
const parts = c.parts;
|
|
1923
|
+
if (Array.isArray(parts)) {
|
|
1924
|
+
const text = parts.map((p) => str(p.text)).filter((t) => t !== null).join("\n");
|
|
1925
|
+
if (text) return text;
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
return null;
|
|
1931
|
+
}
|
|
1932
|
+
function extractParams(request) {
|
|
1933
|
+
const cfg = typeof request.generationConfig === "object" && request.generationConfig !== null ? request.generationConfig : request;
|
|
1934
|
+
return {
|
|
1935
|
+
temperature: num(cfg.temperature, 1),
|
|
1936
|
+
maxTokens: num(cfg.max_tokens ?? cfg.maxTokens ?? cfg.maxOutputTokens ?? cfg.max_output_tokens, 1024),
|
|
1937
|
+
topP: numOrNull(cfg.top_p ?? cfg.topP),
|
|
1938
|
+
seed: numOrNull(cfg.seed)
|
|
1939
|
+
};
|
|
1940
|
+
}
|
|
1941
|
+
function extractModel(providerHint, request, response, override) {
|
|
1942
|
+
const raw = override ?? str(request.model) ?? str(request.modelId) ?? // Bedrock
|
|
1943
|
+
str(response.model) ?? str(response.modelId) ?? null;
|
|
1944
|
+
if (!raw) return null;
|
|
1945
|
+
const parts = raw.split("/");
|
|
1946
|
+
const modelName = parts[parts.length - 1];
|
|
1947
|
+
const modelVersion = str(response.model_version ?? response.modelVersion) ?? null;
|
|
1948
|
+
return { model: modelName, modelVersion };
|
|
1949
|
+
}
|
|
1950
|
+
function tryUnwrapBedrock(request) {
|
|
1951
|
+
const modelId = str(request.modelId);
|
|
1952
|
+
if (!modelId) return null;
|
|
1953
|
+
let body = {};
|
|
1954
|
+
if (typeof request.body === "string") {
|
|
1955
|
+
try {
|
|
1956
|
+
body = JSON.parse(request.body);
|
|
1957
|
+
} catch {
|
|
1958
|
+
body = {};
|
|
1959
|
+
}
|
|
1960
|
+
} else if (typeof request.body === "object" && request.body !== null) {
|
|
1961
|
+
body = request.body;
|
|
1962
|
+
}
|
|
1963
|
+
return { req: { ...body, modelId }, modelId };
|
|
1964
|
+
}
|
|
1965
|
+
function extractFromProviderCall(provider, modelOverride, rawRequest, rawResponse) {
|
|
1966
|
+
let request = rawRequest;
|
|
1967
|
+
if (provider === "bedrock" || str(rawRequest.modelId)) {
|
|
1968
|
+
const unwrapped = tryUnwrapBedrock(rawRequest);
|
|
1969
|
+
if (unwrapped) request = unwrapped.req;
|
|
1970
|
+
}
|
|
1971
|
+
const modelResult = extractModel(provider, request, rawResponse, modelOverride);
|
|
1972
|
+
if (!modelResult) {
|
|
1973
|
+
return {
|
|
1974
|
+
ok: false,
|
|
1975
|
+
reason: "Could not determine model name. Provide it via the `model` field, or ensure request.model / request.modelId is present."
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
const input = extractInput(request);
|
|
1979
|
+
if (input === null) {
|
|
1980
|
+
return {
|
|
1981
|
+
ok: false,
|
|
1982
|
+
reason: "Could not extract input. Expected request.messages (OpenAI/Anthropic/Mistral), request.contents (Gemini), or request.prompt/request.input (generic)."
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
const prompt = derivePrompt(request) ?? (typeof input === "string" ? input : "[structured input]");
|
|
1986
|
+
const output = extractOutput(rawResponse);
|
|
1987
|
+
if (output === null) {
|
|
1988
|
+
return {
|
|
1989
|
+
ok: false,
|
|
1990
|
+
reason: "Could not extract output text. Expected response.choices[0].message.content (OpenAI/Mistral), response.content[0].text (Anthropic), response.candidates[0].content.parts[0].text (Gemini), or response.text / response.output_text (generic)."
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
const parameters = extractParams(request);
|
|
1994
|
+
return {
|
|
1995
|
+
ok: true,
|
|
1996
|
+
data: {
|
|
1997
|
+
model: modelResult.model,
|
|
1998
|
+
modelVersion: modelResult.modelVersion,
|
|
1999
|
+
prompt,
|
|
2000
|
+
input,
|
|
2001
|
+
output,
|
|
2002
|
+
parameters
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// src/certifyFromProvider.ts
|
|
2008
|
+
function certifyDecisionFromProviderCall(params) {
|
|
2009
|
+
const extracted = extractFromProviderCall(
|
|
2010
|
+
params.provider,
|
|
2011
|
+
params.model,
|
|
2012
|
+
params.request,
|
|
2013
|
+
params.response
|
|
2014
|
+
);
|
|
2015
|
+
if (!extracted.ok) {
|
|
2016
|
+
return { ok: false, code: CerVerifyCode.SCHEMA_ERROR, reason: extracted.reason };
|
|
2017
|
+
}
|
|
2018
|
+
const { model, modelVersion, prompt, input, output, parameters } = extracted.data;
|
|
2019
|
+
try {
|
|
2020
|
+
const snapshot = createSnapshot({
|
|
2021
|
+
executionId: params.executionId ?? crypto5.randomUUID(),
|
|
2022
|
+
timestamp: params.timestamp,
|
|
2023
|
+
provider: params.provider,
|
|
2024
|
+
model,
|
|
2025
|
+
modelVersion,
|
|
2026
|
+
prompt,
|
|
2027
|
+
input,
|
|
2028
|
+
parameters,
|
|
2029
|
+
output,
|
|
2030
|
+
appId: params.appId ?? null,
|
|
2031
|
+
workflowId: params.workflowId ?? null,
|
|
2032
|
+
conversationId: params.conversationId ?? null
|
|
2033
|
+
});
|
|
2034
|
+
const bundle = sealCer(snapshot, { meta: params.meta, createdAt: params.createdAt });
|
|
2035
|
+
return { ok: true, bundle };
|
|
2036
|
+
} catch (err2) {
|
|
2037
|
+
return {
|
|
2038
|
+
ok: false,
|
|
2039
|
+
code: CerVerifyCode.SCHEMA_ERROR,
|
|
2040
|
+
reason: err2 instanceof Error ? err2.message : String(err2)
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
// src/client.ts
|
|
2046
|
+
async function resolveApiKey(key) {
|
|
2047
|
+
if (typeof key === "function") return key();
|
|
2048
|
+
return key ?? "";
|
|
2049
|
+
}
|
|
2050
|
+
function mergeDefaultMeta(defaults, meta) {
|
|
2051
|
+
const base = {};
|
|
2052
|
+
if (defaults.tags && defaults.tags.length > 0) base.tags = defaults.tags;
|
|
2053
|
+
if (defaults.source) base.source = defaults.source;
|
|
2054
|
+
if (!meta && Object.keys(base).length === 0) return void 0;
|
|
2055
|
+
return { ...base, ...meta };
|
|
2056
|
+
}
|
|
2057
|
+
function createClient(defaults = {}) {
|
|
2058
|
+
return {
|
|
2059
|
+
certifyDecision(params) {
|
|
2060
|
+
return certifyDecision({
|
|
2061
|
+
appId: defaults.appId ?? null,
|
|
2062
|
+
workflowId: defaults.workflowId ?? null,
|
|
2063
|
+
...params,
|
|
2064
|
+
meta: mergeDefaultMeta(defaults, params.meta)
|
|
2065
|
+
});
|
|
2066
|
+
},
|
|
2067
|
+
async certifyAndAttestDecision(params, options) {
|
|
2068
|
+
const nodeUrl = options?.nodeUrl ?? defaults.nodeUrl;
|
|
2069
|
+
if (!nodeUrl) {
|
|
2070
|
+
throw new Error("certifyAndAttestDecision requires nodeUrl (set in defaults or options)");
|
|
2071
|
+
}
|
|
2072
|
+
const apiKey = options?.apiKey ?? await resolveApiKey(defaults.apiKey);
|
|
2073
|
+
const mergedParams = {
|
|
2074
|
+
appId: defaults.appId ?? null,
|
|
2075
|
+
workflowId: defaults.workflowId ?? null,
|
|
2076
|
+
...params,
|
|
2077
|
+
meta: mergeDefaultMeta(defaults, params.meta)
|
|
2078
|
+
};
|
|
2079
|
+
return certifyAndAttestDecision(mergedParams, {
|
|
2080
|
+
nodeUrl,
|
|
2081
|
+
apiKey,
|
|
2082
|
+
timeoutMs: options?.timeoutMs
|
|
2083
|
+
});
|
|
2084
|
+
},
|
|
2085
|
+
verify(bundle) {
|
|
2086
|
+
return verifyCer(bundle);
|
|
2087
|
+
},
|
|
2088
|
+
async verifyBundleAttestation(bundle, options) {
|
|
2089
|
+
const nodeUrl = options?.nodeUrl ?? defaults.nodeUrl;
|
|
2090
|
+
if (!nodeUrl) {
|
|
2091
|
+
throw new Error("verifyBundleAttestation requires nodeUrl (set in defaults or options)");
|
|
2092
|
+
}
|
|
2093
|
+
return verifyBundleAttestation(bundle, { nodeUrl, kid: options?.kid });
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
// src/aief.ts
|
|
2099
|
+
var AIEF_REASON_MAP = {
|
|
2100
|
+
[CerVerifyCode.OK]: "ok",
|
|
2101
|
+
[CerVerifyCode.CERTIFICATE_HASH_MISMATCH]: "integrityProofMismatch",
|
|
2102
|
+
[CerVerifyCode.SNAPSHOT_HASH_MISMATCH]: "integrityProofMismatch",
|
|
2103
|
+
[CerVerifyCode.INPUT_HASH_MISMATCH]: "integrityProofMismatch",
|
|
2104
|
+
[CerVerifyCode.OUTPUT_HASH_MISMATCH]: "integrityProofMismatch",
|
|
2105
|
+
[CerVerifyCode.TOOL_OUTPUT_HASH_MISMATCH]: "integrityProofMismatch",
|
|
2106
|
+
[CerVerifyCode.SCHEMA_ERROR]: "unsupportedSchema",
|
|
2107
|
+
[CerVerifyCode.CANONICALIZATION_ERROR]: "malformedArtifact",
|
|
2108
|
+
[CerVerifyCode.INVALID_SHA256_FORMAT]: "malformedArtifact",
|
|
2109
|
+
[CerVerifyCode.UNKNOWN_ERROR]: "malformedArtifact",
|
|
2110
|
+
[CerVerifyCode.INCOMPLETE_ARTIFACT]: "incompleteArtifact",
|
|
2111
|
+
[CerVerifyCode.CHAIN_BREAK_DETECTED]: "chainBreakDetected",
|
|
2112
|
+
[CerVerifyCode.VERIFICATION_MATERIAL_UNAVAILABLE]: "verificationMaterialUnavailable",
|
|
2113
|
+
[CerVerifyCode.TOOL_EVIDENCE_MISSING]: "incompleteArtifact",
|
|
2114
|
+
[CerVerifyCode.ATTESTATION_INVALID_SIGNATURE]: "signatureInvalid",
|
|
2115
|
+
[CerVerifyCode.ATTESTATION_MISSING]: "verificationMaterialUnavailable",
|
|
2116
|
+
[CerVerifyCode.ATTESTATION_KEY_NOT_FOUND]: "verificationMaterialUnavailable",
|
|
2117
|
+
[CerVerifyCode.ATTESTATION_KEY_FORMAT_UNSUPPORTED]: "verificationMaterialUnavailable"
|
|
2118
|
+
};
|
|
2119
|
+
var INTEGRITY_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
2120
|
+
CerVerifyCode.CERTIFICATE_HASH_MISMATCH,
|
|
2121
|
+
CerVerifyCode.SNAPSHOT_HASH_MISMATCH,
|
|
2122
|
+
CerVerifyCode.INPUT_HASH_MISMATCH,
|
|
2123
|
+
CerVerifyCode.OUTPUT_HASH_MISMATCH,
|
|
2124
|
+
CerVerifyCode.TOOL_OUTPUT_HASH_MISMATCH
|
|
2125
|
+
]);
|
|
2126
|
+
var SCHEMA_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
2127
|
+
CerVerifyCode.SCHEMA_ERROR,
|
|
2128
|
+
CerVerifyCode.CANONICALIZATION_ERROR,
|
|
2129
|
+
CerVerifyCode.INVALID_SHA256_FORMAT,
|
|
2130
|
+
CerVerifyCode.UNKNOWN_ERROR,
|
|
2131
|
+
CerVerifyCode.INCOMPLETE_ARTIFACT
|
|
2132
|
+
]);
|
|
2133
|
+
function mapToAiefReason(code) {
|
|
2134
|
+
return AIEF_REASON_MAP[code] ?? "malformedArtifact";
|
|
2135
|
+
}
|
|
2136
|
+
function verifyAief(bundle) {
|
|
2137
|
+
const inner = verifyCer(bundle);
|
|
2138
|
+
if (inner.ok) {
|
|
2139
|
+
return {
|
|
2140
|
+
result: "PASS",
|
|
2141
|
+
reason: null,
|
|
2142
|
+
checks: {
|
|
2143
|
+
schemaSupported: true,
|
|
2144
|
+
integrityValid: true,
|
|
2145
|
+
protectedSetValid: true,
|
|
2146
|
+
chainValid: true
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
}
|
|
2150
|
+
const aiefReason = mapToAiefReason(inner.code);
|
|
2151
|
+
const isIntegrityFailure = INTEGRITY_FAILURE_CODES.has(inner.code);
|
|
2152
|
+
const isSchemaFailure = SCHEMA_FAILURE_CODES.has(inner.code);
|
|
2153
|
+
const isChainFailure = inner.code === CerVerifyCode.CHAIN_BREAK_DETECTED;
|
|
2154
|
+
const result = {
|
|
2155
|
+
result: "FAIL",
|
|
2156
|
+
reason: aiefReason,
|
|
2157
|
+
checks: {
|
|
2158
|
+
schemaSupported: !isSchemaFailure,
|
|
2159
|
+
integrityValid: !isIntegrityFailure,
|
|
2160
|
+
protectedSetValid: !isIntegrityFailure,
|
|
2161
|
+
chainValid: !isChainFailure
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
if (inner.details && inner.details.length > 0) {
|
|
2165
|
+
result.notes = inner.details;
|
|
2166
|
+
} else if (inner.errors.length > 0) {
|
|
2167
|
+
result.notes = inner.errors;
|
|
2168
|
+
}
|
|
2169
|
+
return result;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// src/tools.ts
|
|
2173
|
+
function hashToolOutput(value) {
|
|
2174
|
+
if (typeof value === "string") {
|
|
2175
|
+
return hashUtf8(value);
|
|
2176
|
+
}
|
|
2177
|
+
return hashCanonicalJson(value);
|
|
2178
|
+
}
|
|
2179
|
+
function makeToolEvent(params) {
|
|
2180
|
+
const at = params.at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2181
|
+
const outputHash = hashToolOutput(params.output);
|
|
2182
|
+
const event = {
|
|
2183
|
+
toolId: params.toolId,
|
|
2184
|
+
at,
|
|
2185
|
+
outputHash
|
|
2186
|
+
};
|
|
2187
|
+
if (params.input !== void 0) {
|
|
2188
|
+
event.inputHash = hashToolOutput(params.input);
|
|
2189
|
+
}
|
|
2190
|
+
if (params.evidenceRef !== void 0) {
|
|
2191
|
+
event.evidenceRef = params.evidenceRef;
|
|
2192
|
+
}
|
|
2193
|
+
if (params.error !== void 0) {
|
|
2194
|
+
event.error = params.error;
|
|
2195
|
+
}
|
|
2196
|
+
return event;
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
// src/chain.ts
|
|
2200
|
+
function verifyRunSummary(summary, bundles, opts) {
|
|
2201
|
+
if (bundles.length !== summary.stepCount) {
|
|
2202
|
+
return {
|
|
2203
|
+
ok: false,
|
|
2204
|
+
code: CerVerifyCode.INCOMPLETE_ARTIFACT,
|
|
2205
|
+
errors: [
|
|
2206
|
+
`Step count mismatch: summary declares ${summary.stepCount} step(s), received ${bundles.length}`
|
|
2207
|
+
],
|
|
2208
|
+
details: ["Possible step deletion or insertion"]
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
if (bundles.length === 0) {
|
|
2212
|
+
return { ok: true, code: CerVerifyCode.OK, errors: [] };
|
|
2213
|
+
}
|
|
2214
|
+
let prevHash = null;
|
|
2215
|
+
for (let i = 0; i < bundles.length; i++) {
|
|
2216
|
+
const bundle = bundles[i];
|
|
2217
|
+
const summaryStep = summary.steps[i];
|
|
2218
|
+
if (!summaryStep) {
|
|
2219
|
+
return {
|
|
2220
|
+
ok: false,
|
|
2221
|
+
code: CerVerifyCode.INCOMPLETE_ARTIFACT,
|
|
2222
|
+
errors: [`Missing summary entry for step index ${i}`],
|
|
2223
|
+
breakAt: i
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
if (!opts?.skipBundleVerification) {
|
|
2227
|
+
const bundleResult = verifyCer(bundle);
|
|
2228
|
+
if (!bundleResult.ok) {
|
|
2229
|
+
return {
|
|
2230
|
+
ok: false,
|
|
2231
|
+
code: bundleResult.code,
|
|
2232
|
+
errors: [`Step ${i}: individual bundle verification failed: ${bundleResult.errors.join("; ")}`],
|
|
2233
|
+
details: bundleResult.details,
|
|
2234
|
+
breakAt: i
|
|
2235
|
+
};
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
const stepIndex = bundle.snapshot?.stepIndex;
|
|
2239
|
+
if (stepIndex !== i) {
|
|
2240
|
+
return {
|
|
2241
|
+
ok: false,
|
|
2242
|
+
code: CerVerifyCode.CHAIN_BREAK_DETECTED,
|
|
2243
|
+
errors: [`Step ${i}: expected stepIndex ${i}, got ${String(stepIndex)}`],
|
|
2244
|
+
details: ["stepIndex mismatch indicates insertion or reordering"],
|
|
2245
|
+
breakAt: i
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
const snapshotPrevHash = bundle.snapshot?.prevStepHash ?? null;
|
|
2249
|
+
if (i === 0) {
|
|
2250
|
+
if (snapshotPrevHash !== null) {
|
|
2251
|
+
return {
|
|
2252
|
+
ok: false,
|
|
2253
|
+
code: CerVerifyCode.CHAIN_BREAK_DETECTED,
|
|
2254
|
+
errors: [`Step 0: expected prevStepHash null, got "${snapshotPrevHash}"`],
|
|
2255
|
+
details: ["First step must have prevStepHash null"],
|
|
2256
|
+
breakAt: 0,
|
|
2257
|
+
expectedPrev: "null",
|
|
2258
|
+
observedPrev: snapshotPrevHash
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
} else {
|
|
2262
|
+
if (snapshotPrevHash !== prevHash) {
|
|
2263
|
+
return {
|
|
2264
|
+
ok: false,
|
|
2265
|
+
code: CerVerifyCode.CHAIN_BREAK_DETECTED,
|
|
2266
|
+
errors: [`Step ${i}: prevStepHash mismatch \u2014 chain break detected`],
|
|
2267
|
+
details: [
|
|
2268
|
+
`Expected prevStepHash "${prevHash ?? "null"}", got "${snapshotPrevHash ?? "null"}"`
|
|
2269
|
+
],
|
|
2270
|
+
breakAt: i,
|
|
2271
|
+
expectedPrev: prevHash ?? void 0,
|
|
2272
|
+
observedPrev: snapshotPrevHash ?? void 0
|
|
2273
|
+
};
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
if (bundle.certificateHash !== summaryStep.certificateHash) {
|
|
2277
|
+
return {
|
|
2278
|
+
ok: false,
|
|
2279
|
+
code: CerVerifyCode.CHAIN_BREAK_DETECTED,
|
|
2280
|
+
errors: [`Step ${i}: certificateHash does not match summary record`],
|
|
2281
|
+
details: [
|
|
2282
|
+
`Summary has "${summaryStep.certificateHash}", bundle has "${bundle.certificateHash}"`
|
|
2283
|
+
],
|
|
2284
|
+
breakAt: i
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
prevHash = bundle.certificateHash;
|
|
2288
|
+
}
|
|
2289
|
+
const lastBundle = bundles[bundles.length - 1];
|
|
2290
|
+
if (summary.finalStepHash !== lastBundle.certificateHash) {
|
|
2291
|
+
return {
|
|
2292
|
+
ok: false,
|
|
2293
|
+
code: CerVerifyCode.CHAIN_BREAK_DETECTED,
|
|
2294
|
+
errors: ["summary.finalStepHash does not match last step certificateHash"],
|
|
2295
|
+
details: [
|
|
2296
|
+
`Expected "${summary.finalStepHash ?? "null"}", got "${lastBundle.certificateHash}"`
|
|
2297
|
+
],
|
|
2298
|
+
breakAt: bundles.length - 1,
|
|
2299
|
+
expectedPrev: summary.finalStepHash ?? void 0,
|
|
2300
|
+
observedPrev: lastBundle.certificateHash
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
return { ok: true, code: CerVerifyCode.OK, errors: [] };
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
// src/redact.ts
|
|
2307
|
+
function hashValue(value) {
|
|
2308
|
+
if (typeof value === "string") return hashUtf8(value);
|
|
2309
|
+
return hashCanonicalJson(value);
|
|
2310
|
+
}
|
|
2311
|
+
function getNestedValue(obj, path) {
|
|
2312
|
+
const parts = path.split(".");
|
|
2313
|
+
let cursor = obj;
|
|
2314
|
+
for (const part of parts) {
|
|
2315
|
+
if (typeof cursor !== "object" || cursor === null) return void 0;
|
|
2316
|
+
cursor = cursor[part];
|
|
2317
|
+
}
|
|
2318
|
+
return cursor;
|
|
2319
|
+
}
|
|
2320
|
+
function setNestedPath(obj, path, value) {
|
|
2321
|
+
const parts = path.split(".");
|
|
2322
|
+
const clone = { ...obj };
|
|
2323
|
+
let cursor = clone;
|
|
2324
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
2325
|
+
const key = parts[i];
|
|
2326
|
+
const child = cursor[key];
|
|
2327
|
+
if (typeof child !== "object" || child === null) return clone;
|
|
2328
|
+
cursor[key] = { ...child };
|
|
2329
|
+
cursor = cursor[key];
|
|
2330
|
+
}
|
|
2331
|
+
const last = parts[parts.length - 1];
|
|
2332
|
+
if (last in cursor) {
|
|
2333
|
+
cursor[last] = value;
|
|
2334
|
+
}
|
|
2335
|
+
return clone;
|
|
2336
|
+
}
|
|
2337
|
+
function redactBeforeSeal(snapshot, policy) {
|
|
2338
|
+
let result = { ...snapshot };
|
|
2339
|
+
for (const path of policy.paths) {
|
|
2340
|
+
const original = getNestedValue(result, path);
|
|
2341
|
+
if (original === void 0) continue;
|
|
2342
|
+
const envelope = {
|
|
2343
|
+
_redacted: true,
|
|
2344
|
+
hash: hashValue(original)
|
|
2345
|
+
};
|
|
2346
|
+
result = setNestedPath(result, path, envelope);
|
|
2347
|
+
if (path === "input") {
|
|
2348
|
+
result["inputHash"] = computeInputHash(envelope);
|
|
2349
|
+
} else if (path === "output") {
|
|
2350
|
+
result["outputHash"] = computeOutputHash(envelope);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
return result;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
// src/profile.ts
|
|
2357
|
+
var SHA256_PATTERN2 = /^sha256:[0-9a-f]{64}$/;
|
|
2358
|
+
function validateToolEvent(event, index) {
|
|
2359
|
+
const errs = [];
|
|
2360
|
+
if (!event.toolId || typeof event.toolId !== "string") {
|
|
2361
|
+
errs.push(`toolCalls[${index}].toolId must be a non-empty string`);
|
|
2362
|
+
}
|
|
2363
|
+
if (!event.at || typeof event.at !== "string") {
|
|
2364
|
+
errs.push(`toolCalls[${index}].at must be a non-empty ISO 8601 string`);
|
|
2365
|
+
}
|
|
2366
|
+
if (!event.outputHash || !SHA256_PATTERN2.test(event.outputHash)) {
|
|
2367
|
+
errs.push(`toolCalls[${index}].outputHash must be in sha256:<64hex> format, got "${event.outputHash ?? ""}"`);
|
|
2368
|
+
}
|
|
2369
|
+
if (event.inputHash !== void 0 && !SHA256_PATTERN2.test(event.inputHash)) {
|
|
2370
|
+
errs.push(`toolCalls[${index}].inputHash must be in sha256:<64hex> format when present`);
|
|
2371
|
+
}
|
|
2372
|
+
return errs;
|
|
2373
|
+
}
|
|
2374
|
+
function validateL2(snapshot, label) {
|
|
2375
|
+
const errs = [];
|
|
2376
|
+
if (!snapshot.executionId) errs.push(`executionId is required for ${label}`);
|
|
2377
|
+
if (!snapshot.timestamp) errs.push(`timestamp is required for ${label}`);
|
|
2378
|
+
if (!snapshot.provider) errs.push(`provider is required for ${label}`);
|
|
2379
|
+
if (!snapshot.model) errs.push(`model is required for ${label}`);
|
|
2380
|
+
if (snapshot.input === void 0 || snapshot.input === null) errs.push(`input is required for ${label}`);
|
|
2381
|
+
if (snapshot.output === void 0 || snapshot.output === null) errs.push(`output is required for ${label}`);
|
|
2382
|
+
if (!snapshot.inputHash) errs.push(`inputHash is required for ${label}`);
|
|
2383
|
+
if (!snapshot.outputHash) errs.push(`outputHash is required for ${label}`);
|
|
2384
|
+
return errs;
|
|
2385
|
+
}
|
|
2386
|
+
function resolveSnapshot(target) {
|
|
2387
|
+
if ("snapshot" in target && target.snapshot) {
|
|
2388
|
+
return target.snapshot;
|
|
2389
|
+
}
|
|
2390
|
+
return target;
|
|
2391
|
+
}
|
|
2392
|
+
function validateProfile(target, profile) {
|
|
2393
|
+
if (profile === "flexible") {
|
|
2394
|
+
return { ok: true, errors: [] };
|
|
2395
|
+
}
|
|
2396
|
+
const snapshot = resolveSnapshot(target);
|
|
2397
|
+
const errors = [];
|
|
2398
|
+
if (profile === "AIEF_L2" || profile === "AIEF_L3" || profile === "AIEF_L4") {
|
|
2399
|
+
errors.push(...validateL2(snapshot, profile));
|
|
2400
|
+
}
|
|
2401
|
+
if (profile === "AIEF_L4") {
|
|
2402
|
+
if (snapshot.toolCalls && snapshot.toolCalls.length > 0) {
|
|
2403
|
+
for (let i = 0; i < snapshot.toolCalls.length; i++) {
|
|
2404
|
+
errors.push(...validateToolEvent(snapshot.toolCalls[i], i));
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
if (snapshot.stepIndex !== null && snapshot.stepIndex !== void 0 && snapshot.stepIndex > 0 && !snapshot.prevStepHash) {
|
|
2408
|
+
errors.push("prevStepHash is required when stepIndex > 0 in AIEF_L4 profile");
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
return { ok: errors.length === 0, errors };
|
|
2412
|
+
}
|
|
1785
2413
|
export {
|
|
1786
2414
|
CerAttestationError,
|
|
1787
2415
|
CerVerificationError,
|
|
@@ -1791,25 +2419,36 @@ export {
|
|
|
1791
2419
|
attestIfNeeded,
|
|
1792
2420
|
certifyAndAttestDecision,
|
|
1793
2421
|
certifyDecision,
|
|
2422
|
+
certifyDecisionFromProviderCall,
|
|
1794
2423
|
computeInputHash,
|
|
1795
2424
|
computeOutputHash,
|
|
2425
|
+
createClient,
|
|
1796
2426
|
createSnapshot,
|
|
1797
2427
|
exportCer,
|
|
1798
2428
|
fetchNodeKeys,
|
|
1799
2429
|
getAttestationReceipt,
|
|
1800
2430
|
hasAttestation,
|
|
1801
2431
|
hashCanonicalJson,
|
|
2432
|
+
hashToolOutput,
|
|
1802
2433
|
hashUtf8,
|
|
1803
2434
|
importCer,
|
|
2435
|
+
makeToolEvent,
|
|
2436
|
+
mapToAiefReason,
|
|
2437
|
+
redactBeforeSeal,
|
|
1804
2438
|
sanitizeForAttestation,
|
|
2439
|
+
sanitizeForStamp,
|
|
2440
|
+
sanitizeForStorage,
|
|
1805
2441
|
sealCer,
|
|
1806
2442
|
selectNodeKey,
|
|
1807
2443
|
sha256Hex,
|
|
1808
2444
|
toCanonicalJson,
|
|
2445
|
+
validateProfile,
|
|
1809
2446
|
verifyCer as verify,
|
|
2447
|
+
verifyAief,
|
|
1810
2448
|
verifyBundleAttestation,
|
|
1811
2449
|
verifyCer,
|
|
1812
2450
|
verifyNodeReceiptSignature,
|
|
2451
|
+
verifyRunSummary,
|
|
1813
2452
|
verifySnapshot,
|
|
1814
2453
|
wrapProvider
|
|
1815
2454
|
};
|