@mcp-audit-gateway/core 0.2.0 → 0.4.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/.github/workflows/ci.yml +37 -0
- package/README.md +31 -3
- package/dist/attestation/audit-log.d.ts +34 -3
- package/dist/attestation/audit-log.d.ts.map +1 -1
- package/dist/attestation/audit-log.js +286 -10
- package/dist/attestation/audit-log.js.map +1 -1
- package/dist/attestation/checkpoint.test.d.ts +2 -0
- package/dist/attestation/checkpoint.test.d.ts.map +1 -0
- package/dist/attestation/checkpoint.test.js +870 -0
- package/dist/attestation/checkpoint.test.js.map +1 -0
- package/dist/attestation/signer.d.ts +24 -9
- package/dist/attestation/signer.d.ts.map +1 -1
- package/dist/attestation/signer.js +145 -11
- package/dist/attestation/signer.js.map +1 -1
- package/dist/attestation/signer.test.js +11 -0
- package/dist/attestation/signer.test.js.map +1 -1
- package/dist/attestation/verify.d.ts +23 -2
- package/dist/attestation/verify.d.ts.map +1 -1
- package/dist/attestation/verify.js +219 -2
- package/dist/attestation/verify.js.map +1 -1
- package/dist/integration.test.js +1 -0
- package/dist/integration.test.js.map +1 -1
- package/dist/proxy/gateway.d.ts +4 -0
- package/dist/proxy/gateway.d.ts.map +1 -1
- package/dist/proxy/gateway.js +4 -1
- package/dist/proxy/gateway.js.map +1 -1
- package/dist/proxy/gateway.test.js +19 -0
- package/dist/proxy/gateway.test.js.map +1 -1
- package/dist/proxy/mcp-server-adapter.d.ts +1 -0
- package/dist/proxy/mcp-server-adapter.d.ts.map +1 -1
- package/dist/proxy/mcp-server-adapter.js +28 -1
- package/dist/proxy/mcp-server-adapter.js.map +1 -1
- package/dist/proxy/mcp-server-adapter.test.js +1 -0
- package/dist/proxy/mcp-server-adapter.test.js.map +1 -1
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -1
- package/dist/wrap/proxy.test.js +2 -2
- package/dist/wrap/proxy.test.js.map +1 -1
- package/docs/BACKLOG.md +33 -0
- package/docs/SECURITY-DESIGN.md +126 -0
- package/docs/v0.4.0-patch-audit.md +115 -0
- package/package.json +1 -1
- package/src/attestation/audit-log.ts +336 -15
- package/src/attestation/checkpoint.test.ts +956 -0
- package/src/attestation/signer.test.ts +14 -0
- package/src/attestation/signer.ts +152 -19
- package/src/attestation/verify.ts +270 -4
- package/src/integration.test.ts +1 -0
- package/src/proxy/gateway.test.ts +18 -0
- package/src/proxy/gateway.ts +4 -0
- package/src/proxy/mcp-server-adapter.test.ts +1 -0
- package/src/proxy/mcp-server-adapter.ts +26 -0
- package/src/types.ts +48 -0
- package/src/wrap/proxy.test.ts +2 -2
- package/test/vectors/aps-action-ref-v1-vectors.json +351 -0
- package/test/vectors/aps-action-ref-v1.mjs +145 -0
- package/test/vectors/canonicalization.json +182 -0
- package/test/vectors/checkpoint.json +450 -0
- package/test/vectors/verify-checkpoint.mjs +344 -0
- package/test/vectors/verify-checkpoint.py +358 -0
- package/test/vectors/verify.mjs +74 -1
- package/test/vectors/verify.py +78 -1
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* APS action-ref-v1 conformance runner.
|
|
4
|
+
* Adapted from: https://github.com/Agent-Authority-Conformance/aps-conformance-suite/tree/main/fixtures/cross-stack/action-ref-v1-negatives
|
|
5
|
+
*
|
|
6
|
+
* Tests JCS (RFC 8785) canonical recomputation and fail-closed digest comparison.
|
|
7
|
+
* No APS SDK dependency — uses the same SHA-256 + canonical-sort primitives
|
|
8
|
+
* that back our attestation layer.
|
|
9
|
+
*
|
|
10
|
+
* Property under test: a verifier recomputes action_ref from the invocation
|
|
11
|
+
* payload exactly once via JCS canonicalization, then rejects on mismatch.
|
|
12
|
+
* No retries, no coercion, no normalization.
|
|
13
|
+
*
|
|
14
|
+
* Scope relative to the full APS conformance suite: we extract the fail-closed
|
|
15
|
+
* digest recomputation property, which our attestation layer shares. The
|
|
16
|
+
* aae-envelope interop vectors test delegation chain semantics (scope narrowing,
|
|
17
|
+
* expiry cascade, revocation cascade) that this system does not implement — we
|
|
18
|
+
* provide audit trail attestation, not delegation verification. The one
|
|
19
|
+
* aae-envelope concept that applies is signature substitution (valid signature
|
|
20
|
+
* from key A rejected when verified against key B), tested directly in
|
|
21
|
+
* src/attestation/signer.test.ts.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
25
|
+
import { readFileSync } from "node:fs";
|
|
26
|
+
import { fileURLToPath } from "node:url";
|
|
27
|
+
import { dirname, join } from "node:path";
|
|
28
|
+
|
|
29
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
const fixture = JSON.parse(
|
|
31
|
+
readFileSync(join(__dirname, "aps-action-ref-v1-vectors.json"), "utf8")
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const sha256hex = (s) => createHash("sha256").update(s, "utf8").digest("hex");
|
|
35
|
+
|
|
36
|
+
// RFC 8785 (JCS) for flat objects: keys sorted lexicographically,
|
|
37
|
+
// values serialized per ECMA-262. For these fixtures all values are
|
|
38
|
+
// strings or safe integers.
|
|
39
|
+
function jcsFlat(obj) {
|
|
40
|
+
const parts = Object.keys(obj)
|
|
41
|
+
.sort()
|
|
42
|
+
.map((k) => `${JSON.stringify(k)}:${jcsValue(obj[k])}`);
|
|
43
|
+
return `{${parts.join(",")}}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function jcsValue(v) {
|
|
47
|
+
if (typeof v === "string") return JSON.stringify(v);
|
|
48
|
+
if (typeof v === "number" && Number.isSafeInteger(v)) return String(v);
|
|
49
|
+
throw new Error(`jcsFlat: unsupported value type for ${JSON.stringify(v)}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Canonical timestamp grammar: RFC 3339 UTC, exactly three fractional digits, Z suffix.
|
|
53
|
+
const CANONICAL_TS = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
54
|
+
|
|
55
|
+
// Single-path verifier: grammar gate, one recomputation, one comparison.
|
|
56
|
+
function verifyClaim(payload, claimedActionRef) {
|
|
57
|
+
for (const field of ["action_type", "agent_id", "scope", "timestamp"]) {
|
|
58
|
+
if (!(field in payload)) {
|
|
59
|
+
return { ok: false, stage: "grammar", reason: `missing field: ${field}` };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const ts = payload.timestamp;
|
|
63
|
+
if (typeof ts !== "string" || !CANONICAL_TS.test(ts)) {
|
|
64
|
+
return { ok: false, stage: "grammar", reason: "timestamp grammar rejected" };
|
|
65
|
+
}
|
|
66
|
+
const recomputed = sha256hex(jcsFlat(payload));
|
|
67
|
+
if (recomputed !== claimedActionRef) {
|
|
68
|
+
return { ok: false, stage: "recompute", reason: "digest mismatch", recomputed };
|
|
69
|
+
}
|
|
70
|
+
return { ok: true, stage: "recompute", reason: "match", recomputed };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let passed = 0;
|
|
74
|
+
let failed = 0;
|
|
75
|
+
|
|
76
|
+
function check(condition, name, detail) {
|
|
77
|
+
if (condition) {
|
|
78
|
+
passed++;
|
|
79
|
+
console.log(` PASS: ${name}`);
|
|
80
|
+
} else {
|
|
81
|
+
failed++;
|
|
82
|
+
console.log(` FAIL: ${name}`);
|
|
83
|
+
if (detail) console.log(` ${detail}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// === Positive vectors: recomputation must match ===
|
|
88
|
+
console.log("\n=== action-ref-v1 Positive Recomputation ===");
|
|
89
|
+
for (const v of fixture.positive_fixture.vectors) {
|
|
90
|
+
const jcs = jcsFlat(v.preimage);
|
|
91
|
+
check(
|
|
92
|
+
jcs === v.jcs_payload,
|
|
93
|
+
`${v.id} JCS canonical form`,
|
|
94
|
+
`expected: ${v.jcs_payload}\n got: ${jcs}`
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const digest = sha256hex(jcs);
|
|
98
|
+
check(
|
|
99
|
+
digest === v.action_ref,
|
|
100
|
+
`${v.id} SHA-256 recomputation`,
|
|
101
|
+
`expected: ${v.action_ref}\n got: ${digest}`
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const verdict = verifyClaim(v.preimage, v.action_ref);
|
|
105
|
+
check(verdict.ok, `${v.id} verifier accepts`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// === Negative vectors: must fail-closed ===
|
|
109
|
+
console.log("\n=== action-ref-v1 Negative (Fail-Closed) ===");
|
|
110
|
+
const stageMap = { grammar_reject: "grammar", recompute_mismatch: "recompute" };
|
|
111
|
+
|
|
112
|
+
for (const v of fixture.negative_fixture.vectors) {
|
|
113
|
+
const verdict = verifyClaim(v.invocation_payload, v.claimed_action_ref);
|
|
114
|
+
const expectedStage = stageMap[v.expected_failure_stage];
|
|
115
|
+
|
|
116
|
+
check(
|
|
117
|
+
!verdict.ok,
|
|
118
|
+
`${v.id} rejected`,
|
|
119
|
+
verdict.ok ? "verifier accepted (BUG)" : undefined
|
|
120
|
+
);
|
|
121
|
+
check(
|
|
122
|
+
verdict.stage === expectedStage,
|
|
123
|
+
`${v.id} failure stage = ${expectedStage}`,
|
|
124
|
+
`got: ${verdict.stage}`
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Fixture integrity: drifted digest is byte-derived (not invented)
|
|
128
|
+
const drifted = v.drifted_serialization ?? v.drifted_jcs_payload;
|
|
129
|
+
if (drifted) {
|
|
130
|
+
check(
|
|
131
|
+
sha256hex(drifted) === v.claimed_action_ref,
|
|
132
|
+
`${v.id} fixture integrity (drifted digest is real)`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Invariant: claimed != correct (they're genuinely different digests)
|
|
137
|
+
check(
|
|
138
|
+
v.claimed_action_ref !== v.correct_action_ref,
|
|
139
|
+
`${v.id} invariant (claimed != correct)`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// === Summary ===
|
|
144
|
+
console.log(`\n=== Results: ${passed} passed, ${failed} failed (${passed + failed} total) ===`);
|
|
145
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
@@ -578,5 +578,187 @@
|
|
|
578
578
|
}
|
|
579
579
|
]
|
|
580
580
|
}
|
|
581
|
+
},
|
|
582
|
+
"ai_invocation_signing": {
|
|
583
|
+
"description": "aiInvocation is signature-covered: inserted after extensionsDigest, before parties, as its canonicalizeValue (M/L-tagged) form. Keys sort by UTF-16 code units.",
|
|
584
|
+
"vectors": [
|
|
585
|
+
{
|
|
586
|
+
"name": "ai_invocation_full",
|
|
587
|
+
"record": {
|
|
588
|
+
"id": "aivec-0001",
|
|
589
|
+
"timestamp": "2026-08-23T00:00:00.000Z",
|
|
590
|
+
"method": "tools/call",
|
|
591
|
+
"toolName": "github/create_pr",
|
|
592
|
+
"namespace": "github",
|
|
593
|
+
"upstream": "gh",
|
|
594
|
+
"principal": "user-1",
|
|
595
|
+
"durationMs": 42,
|
|
596
|
+
"success": true,
|
|
597
|
+
"errorCode": null,
|
|
598
|
+
"previousHash": "genesis",
|
|
599
|
+
"aiInvocation": {
|
|
600
|
+
"turnId": "t1",
|
|
601
|
+
"invocationReason": "user asked",
|
|
602
|
+
"model": "claude-4"
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
"canonical": "[[\"id\",\"aivec-0001\"],[\"timestamp\",\"2026-08-23T00:00:00.000Z\"],[\"method\",\"tools/call\"],[\"toolName\",\"github/create_pr\"],[\"namespace\",\"github\"],[\"upstream\",\"gh\"],[\"principal\",\"user-1\"],[\"durationMs\",42],[\"success\",true],[\"errorCode\",null],[\"previousHash\",\"genesis\"],[\"aiInvocation\",[\"M\",[[\"invocationReason\",\"user asked\"],[\"model\",\"claude-4\"],[\"turnId\",\"t1\"]]]]]",
|
|
606
|
+
"sha256_canonical": "fddd4a4043f5403a731c116051fb182018176618edb17d3e5d020083e8ff33cf"
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
"name": "ai_invocation_partial_turnid_only",
|
|
610
|
+
"record": {
|
|
611
|
+
"id": "aivec-0001",
|
|
612
|
+
"timestamp": "2026-08-23T00:00:00.000Z",
|
|
613
|
+
"method": "tools/call",
|
|
614
|
+
"toolName": "github/create_pr",
|
|
615
|
+
"namespace": "github",
|
|
616
|
+
"upstream": "gh",
|
|
617
|
+
"principal": "user-1",
|
|
618
|
+
"durationMs": 42,
|
|
619
|
+
"success": true,
|
|
620
|
+
"errorCode": null,
|
|
621
|
+
"previousHash": "genesis",
|
|
622
|
+
"aiInvocation": {
|
|
623
|
+
"turnId": "t1"
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
"canonical": "[[\"id\",\"aivec-0001\"],[\"timestamp\",\"2026-08-23T00:00:00.000Z\"],[\"method\",\"tools/call\"],[\"toolName\",\"github/create_pr\"],[\"namespace\",\"github\"],[\"upstream\",\"gh\"],[\"principal\",\"user-1\"],[\"durationMs\",42],[\"success\",true],[\"errorCode\",null],[\"previousHash\",\"genesis\"],[\"aiInvocation\",[\"M\",[[\"turnId\",\"t1\"]]]]]",
|
|
627
|
+
"sha256_canonical": "7e8627013a6a2430b0fb308fa493e3f6a7b552385734621bb1b8cb4587d4d1f3"
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"name": "ai_invocation_with_all_optionals",
|
|
631
|
+
"record": {
|
|
632
|
+
"id": "aivec-0001",
|
|
633
|
+
"timestamp": "2026-08-23T00:00:00.000Z",
|
|
634
|
+
"method": "tools/call",
|
|
635
|
+
"toolName": "github/create_pr",
|
|
636
|
+
"namespace": "github",
|
|
637
|
+
"upstream": "gh",
|
|
638
|
+
"principal": "user-1",
|
|
639
|
+
"durationMs": 42,
|
|
640
|
+
"success": true,
|
|
641
|
+
"errorCode": null,
|
|
642
|
+
"previousHash": "genesis",
|
|
643
|
+
"decisionContextDigest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
|
644
|
+
"extensionsDigest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
645
|
+
"aiInvocation": {
|
|
646
|
+
"turnId": "t1",
|
|
647
|
+
"model": "claude-4"
|
|
648
|
+
},
|
|
649
|
+
"parties": [
|
|
650
|
+
{
|
|
651
|
+
"party": "gateway",
|
|
652
|
+
"role": "witness",
|
|
653
|
+
"scope": [
|
|
654
|
+
"id",
|
|
655
|
+
"timestamp",
|
|
656
|
+
"method",
|
|
657
|
+
"toolName",
|
|
658
|
+
"namespace",
|
|
659
|
+
"upstream",
|
|
660
|
+
"principal",
|
|
661
|
+
"durationMs",
|
|
662
|
+
"success",
|
|
663
|
+
"errorCode",
|
|
664
|
+
"previousHash"
|
|
665
|
+
]
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
"party": "client",
|
|
669
|
+
"role": "asserter",
|
|
670
|
+
"scope": [
|
|
671
|
+
"aiInvocation"
|
|
672
|
+
]
|
|
673
|
+
}
|
|
674
|
+
]
|
|
675
|
+
},
|
|
676
|
+
"canonical": "[[\"id\",\"aivec-0001\"],[\"timestamp\",\"2026-08-23T00:00:00.000Z\"],[\"method\",\"tools/call\"],[\"toolName\",\"github/create_pr\"],[\"namespace\",\"github\"],[\"upstream\",\"gh\"],[\"principal\",\"user-1\"],[\"durationMs\",42],[\"success\",true],[\"errorCode\",null],[\"decisionContextDigest\",\"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"],[\"previousHash\",\"genesis\"],[\"extensionsDigest\",\"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\"],[\"aiInvocation\",[\"M\",[[\"model\",\"claude-4\"],[\"turnId\",\"t1\"]]]],[\"parties\",[{\"party\":\"gateway\",\"role\":\"witness\",\"scope\":[\"id\",\"timestamp\",\"method\",\"toolName\",\"namespace\",\"upstream\",\"principal\",\"durationMs\",\"success\",\"errorCode\",\"previousHash\"]},{\"party\":\"client\",\"role\":\"asserter\",\"scope\":[\"aiInvocation\"]}]]]",
|
|
677
|
+
"sha256_canonical": "cc6cc5a9146f4c5cf5952e354288705cb67a642f5790fc2fec7acd6bb3c5e682"
|
|
678
|
+
}
|
|
679
|
+
],
|
|
680
|
+
"mutation_negative": {
|
|
681
|
+
"description": "Mutating any aiInvocation field changes the signing digest; a signature over the original record must fail against the mutated record.",
|
|
682
|
+
"original": {
|
|
683
|
+
"name": "original",
|
|
684
|
+
"record": {
|
|
685
|
+
"id": "aivec-0001",
|
|
686
|
+
"timestamp": "2026-08-23T00:00:00.000Z",
|
|
687
|
+
"method": "tools/call",
|
|
688
|
+
"toolName": "github/create_pr",
|
|
689
|
+
"namespace": "github",
|
|
690
|
+
"upstream": "gh",
|
|
691
|
+
"principal": "user-1",
|
|
692
|
+
"durationMs": 42,
|
|
693
|
+
"success": true,
|
|
694
|
+
"errorCode": null,
|
|
695
|
+
"previousHash": "genesis",
|
|
696
|
+
"aiInvocation": {
|
|
697
|
+
"turnId": "t1",
|
|
698
|
+
"invocationReason": "user asked",
|
|
699
|
+
"model": "claude-4"
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
"canonical": "[[\"id\",\"aivec-0001\"],[\"timestamp\",\"2026-08-23T00:00:00.000Z\"],[\"method\",\"tools/call\"],[\"toolName\",\"github/create_pr\"],[\"namespace\",\"github\"],[\"upstream\",\"gh\"],[\"principal\",\"user-1\"],[\"durationMs\",42],[\"success\",true],[\"errorCode\",null],[\"previousHash\",\"genesis\"],[\"aiInvocation\",[\"M\",[[\"invocationReason\",\"user asked\"],[\"model\",\"claude-4\"],[\"turnId\",\"t1\"]]]]]",
|
|
703
|
+
"sha256_canonical": "fddd4a4043f5403a731c116051fb182018176618edb17d3e5d020083e8ff33cf"
|
|
704
|
+
},
|
|
705
|
+
"mutated": {
|
|
706
|
+
"name": "mutated_turnId",
|
|
707
|
+
"record": {
|
|
708
|
+
"id": "aivec-0001",
|
|
709
|
+
"timestamp": "2026-08-23T00:00:00.000Z",
|
|
710
|
+
"method": "tools/call",
|
|
711
|
+
"toolName": "github/create_pr",
|
|
712
|
+
"namespace": "github",
|
|
713
|
+
"upstream": "gh",
|
|
714
|
+
"principal": "user-1",
|
|
715
|
+
"durationMs": 42,
|
|
716
|
+
"success": true,
|
|
717
|
+
"errorCode": null,
|
|
718
|
+
"previousHash": "genesis",
|
|
719
|
+
"aiInvocation": {
|
|
720
|
+
"turnId": "t2",
|
|
721
|
+
"invocationReason": "user asked",
|
|
722
|
+
"model": "claude-4"
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
"canonical": "[[\"id\",\"aivec-0001\"],[\"timestamp\",\"2026-08-23T00:00:00.000Z\"],[\"method\",\"tools/call\"],[\"toolName\",\"github/create_pr\"],[\"namespace\",\"github\"],[\"upstream\",\"gh\"],[\"principal\",\"user-1\"],[\"durationMs\",42],[\"success\",true],[\"errorCode\",null],[\"previousHash\",\"genesis\"],[\"aiInvocation\",[\"M\",[[\"invocationReason\",\"user asked\"],[\"model\",\"claude-4\"],[\"turnId\",\"t2\"]]]]]",
|
|
726
|
+
"sha256_canonical": "960ffc250afd098da527c99dd932fd6d4cc3c1c51283c69861facda20db7f438"
|
|
727
|
+
},
|
|
728
|
+
"digests_differ": true
|
|
729
|
+
}
|
|
730
|
+
},
|
|
731
|
+
"extensions_digest_base": {
|
|
732
|
+
"description": "Base-suite exercise of extensionsDigest insertion order (between decisionContextDigest slot and parties).",
|
|
733
|
+
"vectors": [
|
|
734
|
+
{
|
|
735
|
+
"name": "extensions_digest_with_parties",
|
|
736
|
+
"record": {
|
|
737
|
+
"id": "aivec-0001",
|
|
738
|
+
"timestamp": "2026-08-23T00:00:00.000Z",
|
|
739
|
+
"method": "tools/call",
|
|
740
|
+
"toolName": "github/create_pr",
|
|
741
|
+
"namespace": "github",
|
|
742
|
+
"upstream": "gh",
|
|
743
|
+
"principal": "user-1",
|
|
744
|
+
"durationMs": 42,
|
|
745
|
+
"success": true,
|
|
746
|
+
"errorCode": null,
|
|
747
|
+
"previousHash": "genesis",
|
|
748
|
+
"extensionsDigest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
749
|
+
"parties": [
|
|
750
|
+
{
|
|
751
|
+
"party": "gateway",
|
|
752
|
+
"role": "witness",
|
|
753
|
+
"scope": [
|
|
754
|
+
"id"
|
|
755
|
+
]
|
|
756
|
+
}
|
|
757
|
+
]
|
|
758
|
+
},
|
|
759
|
+
"canonical": "[[\"id\",\"aivec-0001\"],[\"timestamp\",\"2026-08-23T00:00:00.000Z\"],[\"method\",\"tools/call\"],[\"toolName\",\"github/create_pr\"],[\"namespace\",\"github\"],[\"upstream\",\"gh\"],[\"principal\",\"user-1\"],[\"durationMs\",42],[\"success\",true],[\"errorCode\",null],[\"previousHash\",\"genesis\"],[\"extensionsDigest\",\"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\"],[\"parties\",[{\"party\":\"gateway\",\"role\":\"witness\",\"scope\":[\"id\"]}]]]",
|
|
760
|
+
"sha256_canonical": "0fb68b55f31aabe40cea3ab15962aa4ea348c148b9c85ed6cad5a522e7ac1b34"
|
|
761
|
+
}
|
|
762
|
+
]
|
|
581
763
|
}
|
|
582
764
|
}
|