@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/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.5.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 = (num, md) => {
784
- if (num === 0n || md <= 0n)
785
- err("no inverse n=" + num + " mod=" + md);
786
- let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;
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 = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse();
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(str) {
1177
- if (typeof str !== "string")
1224
+ function utf8ToBytes(str2) {
1225
+ if (typeof str2 !== "string")
1178
1226
  throw new Error("string expected");
1179
- return new Uint8Array(new TextEncoder().encode(str));
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
  };