@adastracomputing/ink 0.3.0 → 0.5.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/CHANGELOG.md +75 -0
- package/README.md +14 -1
- package/bin/verify-inclusion-impl.mjs +171 -23
- package/dist/audit/inclusion-receipt.d.ts +33 -8
- package/dist/audit/inclusion-receipt.js +125 -5
- package/dist/crypto/ink.js +12 -4
- package/dist/crypto/keys.d.ts +19 -0
- package/dist/crypto/keys.js +39 -0
- package/dist/crypto/sign.d.ts +21 -0
- package/dist/crypto/sign.js +26 -2
- package/dist/discovery/agent-card.d.ts +9 -7
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -6
- package/dist/ink/checkpoint.d.ts +21 -0
- package/dist/ink/checkpoint.js +79 -0
- package/dist/ink/discovery-gating.js +4 -4
- package/dist/ink/receipts.d.ts +33 -1
- package/dist/ink/receipts.js +45 -1
- package/dist/middleware/ink-auth.d.ts +1 -0
- package/dist/middleware/ink-auth.js +7 -4
- package/dist/models/agent-card.js +22 -22
- package/dist/models/ink-audit.js +40 -36
- package/dist/models/ink-handshake.js +13 -13
- package/dist/models/intent.d.ts +2 -2
- package/dist/models/intent.js +9 -0
- package/docs/maturity.md +7 -1
- package/package.json +8 -7
package/dist/models/ink-audit.js
CHANGED
|
@@ -60,18 +60,18 @@ export const InkAuditEventTypeSchema = z.enum([
|
|
|
60
60
|
]);
|
|
61
61
|
// ── INK Audit Event (hash-chained, signed) ──
|
|
62
62
|
export const InkAuditEventSchema = z.object({
|
|
63
|
-
id: z.string().min(1),
|
|
63
|
+
id: z.string().min(1).max(256),
|
|
64
64
|
version: z.literal("ink-audit/1"),
|
|
65
|
-
agentId: z.string().min(1),
|
|
66
|
-
agentSignature: z.string().min(1),
|
|
65
|
+
agentId: z.string().min(1).max(512),
|
|
66
|
+
agentSignature: z.string().min(1).max(256),
|
|
67
67
|
sequence: z.number().int().positive(),
|
|
68
68
|
previousEventHash: z.string().regex(/^[0-9a-f]{64}$/).nullable(),
|
|
69
69
|
eventType: InkAuditEventTypeSchema,
|
|
70
70
|
timestamp: z.string().datetime(),
|
|
71
|
-
messageId: z.string().min(1).optional(),
|
|
72
|
-
correlationId: z.string().min(1).optional(),
|
|
73
|
-
counterpartyId: z.string().min(1).optional(),
|
|
74
|
-
signingKeyId: z.string().min(1).optional(),
|
|
71
|
+
messageId: z.string().min(1).max(256).optional(),
|
|
72
|
+
correlationId: z.string().min(1).max(256).optional(),
|
|
73
|
+
counterpartyId: z.string().min(1).max(512).optional(),
|
|
74
|
+
signingKeyId: z.string().min(1).max(128).optional(),
|
|
75
75
|
data: z.record(z.string(), z.unknown()).optional(),
|
|
76
76
|
});
|
|
77
77
|
// ── Receipt (INK Auditability §1) ──
|
|
@@ -85,34 +85,38 @@ export const InkReceiptDispositionSchema = z.enum([
|
|
|
85
85
|
export const InkReceiptSchema = z.object({
|
|
86
86
|
protocol: z.literal("ink/0.1"),
|
|
87
87
|
type: z.literal("network.tulpa.receipt"),
|
|
88
|
-
from: z.string(),
|
|
89
|
-
to: z.string(),
|
|
90
|
-
messageId: z.string(),
|
|
88
|
+
from: z.string().max(512),
|
|
89
|
+
to: z.string().max(512),
|
|
90
|
+
messageId: z.string().max(256),
|
|
91
91
|
disposition: InkReceiptDispositionSchema,
|
|
92
92
|
dispositionAt: z.string().datetime(),
|
|
93
93
|
note: z.string().max(500).optional(),
|
|
94
|
-
messageHash: z.string(),
|
|
95
|
-
nonce: z.string(),
|
|
94
|
+
messageHash: z.string().max(256),
|
|
95
|
+
nonce: z.string().max(256),
|
|
96
96
|
timestamp: z.string().datetime(),
|
|
97
|
-
signature: z.string(),
|
|
97
|
+
signature: z.string().max(256),
|
|
98
98
|
});
|
|
99
99
|
// ── Audit Query (INK Auditability §3) ──
|
|
100
100
|
export const InkAuditQuerySchema = z.object({
|
|
101
101
|
protocol: z.literal("ink/0.1"),
|
|
102
102
|
type: z.literal("network.tulpa.audit_query"),
|
|
103
|
-
from: z.string(),
|
|
104
|
-
to: z.string(),
|
|
105
|
-
messageId: z.string(),
|
|
106
|
-
nonce: z.string(),
|
|
103
|
+
from: z.string().max(512),
|
|
104
|
+
to: z.string().max(512),
|
|
105
|
+
messageId: z.string().max(256),
|
|
106
|
+
nonce: z.string().max(256),
|
|
107
107
|
timestamp: z.string().datetime(),
|
|
108
108
|
});
|
|
109
109
|
// ── Audit Response (INK Auditability §3) ──
|
|
110
110
|
export const InkAuditResponseSchema = z.object({
|
|
111
111
|
protocol: z.literal("ink/0.1"),
|
|
112
112
|
type: z.literal("network.tulpa.audit_response"),
|
|
113
|
-
messageId: z.string(),
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
messageId: z.string().max(256),
|
|
114
|
+
// Bound both the event count and (via InkAuditEventSchema's per-field caps)
|
|
115
|
+
// each event, so an audit response from an untrusted witness cannot force
|
|
116
|
+
// unbounded buffering. A single response that needs more than this should
|
|
117
|
+
// page rather than return one giant array.
|
|
118
|
+
events: z.array(InkAuditEventSchema).max(1000),
|
|
119
|
+
responseSignature: z.string().max(256),
|
|
116
120
|
});
|
|
117
121
|
// ── Third-Party Audit Submit (INK Auditability §7.2) ──
|
|
118
122
|
export const InkAuditSubmitSchema = z.object({
|
|
@@ -128,10 +132,10 @@ export const InkAuditSubmitSchema = z.object({
|
|
|
128
132
|
export const InkAuditInclusionSchema = z.object({
|
|
129
133
|
protocol: z.literal("ink/0.1"),
|
|
130
134
|
type: z.literal("network.tulpa.audit_inclusion"),
|
|
131
|
-
eventId: z.string(),
|
|
135
|
+
eventId: z.string().max(256),
|
|
132
136
|
treeSize: z.number().int().positive(),
|
|
133
137
|
leafIndex: z.number().int().min(0),
|
|
134
|
-
rootHash: z.string(),
|
|
138
|
+
rootHash: z.string().max(128),
|
|
135
139
|
/** Optional Merkle inclusion proof — array of 64-character lowercase hex
|
|
136
140
|
* hash siblings on the path from the leaf to the root. Consumers that
|
|
137
141
|
* verify proofs (third-party auditor clients) read this field; consumers
|
|
@@ -141,7 +145,7 @@ export const InkAuditInclusionSchema = z.object({
|
|
|
141
145
|
* force the parser to allocate megabytes of garbage proof data. */
|
|
142
146
|
inclusionProof: z.array(z.string().regex(/^[0-9a-f]{64}$/)).max(64).optional(),
|
|
143
147
|
timestamp: z.string().datetime(),
|
|
144
|
-
serviceSignature: z.string(),
|
|
148
|
+
serviceSignature: z.string().max(256),
|
|
145
149
|
});
|
|
146
150
|
// ── Introduction Receipt (INK Introduction Receipts Extension §4) ──
|
|
147
151
|
export const InkIntroductionReceiptStatusSchema = z.enum([
|
|
@@ -154,22 +158,22 @@ export const InkIntroductionReceiptStatusSchema = z.enum([
|
|
|
154
158
|
export const InkIntroductionReceiptSchema = z.object({
|
|
155
159
|
protocol: z.literal("ink/0.1"),
|
|
156
160
|
type: z.literal("network.tulpa.introduction_receipt"),
|
|
157
|
-
id: z.string(),
|
|
158
|
-
correlationId: z.string(),
|
|
159
|
-
from: z.string(),
|
|
160
|
-
to: z.string(),
|
|
161
|
-
requesterDid: z.string(),
|
|
162
|
-
introducerDid: z.string(),
|
|
163
|
-
beneficiaryDid: z.string(),
|
|
164
|
-
targetDid: z.string(),
|
|
161
|
+
id: z.string().max(256),
|
|
162
|
+
correlationId: z.string().max(256),
|
|
163
|
+
from: z.string().max(512),
|
|
164
|
+
to: z.string().max(512),
|
|
165
|
+
requesterDid: z.string().max(512),
|
|
166
|
+
introducerDid: z.string().max(512),
|
|
167
|
+
beneficiaryDid: z.string().max(512),
|
|
168
|
+
targetDid: z.string().max(512),
|
|
165
169
|
status: InkIntroductionReceiptStatusSchema,
|
|
166
170
|
purpose: z.string().min(1).max(500),
|
|
167
|
-
nonce: z.string(),
|
|
171
|
+
nonce: z.string().max(256),
|
|
168
172
|
timestamp: z.string().datetime(),
|
|
169
|
-
relatedIntentId: z.string().optional(),
|
|
170
|
-
relatedResolutionId: z.string().optional(),
|
|
173
|
+
relatedIntentId: z.string().max(256).optional(),
|
|
174
|
+
relatedResolutionId: z.string().max(256).optional(),
|
|
171
175
|
note: z.string().max(500).optional(),
|
|
172
|
-
contextHash: z.string().optional(),
|
|
173
|
-
authorizationChainRef: z.string().optional(),
|
|
176
|
+
contextHash: z.string().max(256).optional(),
|
|
177
|
+
authorizationChainRef: z.string().max(512).optional(),
|
|
174
178
|
expiresAt: z.string().datetime().optional(),
|
|
175
179
|
});
|
|
@@ -32,12 +32,12 @@ export const ChallengeTypeSchema = z.enum([
|
|
|
32
32
|
export const InkChallengeSchema = z.object({
|
|
33
33
|
protocol: z.literal("ink/0.1"),
|
|
34
34
|
type: z.literal("network.tulpa.challenge"),
|
|
35
|
-
intentRef: z.string(),
|
|
35
|
+
intentRef: z.string().max(256),
|
|
36
36
|
challengeType: ChallengeTypeSchema,
|
|
37
|
-
fields: z.array(z.string()).optional(),
|
|
38
|
-
availableWindows: z.array(z.string()).optional(),
|
|
39
|
-
contextFields: z.array(z.string()).optional(),
|
|
40
|
-
nonce: z.string(),
|
|
37
|
+
fields: z.array(z.string().max(256)).max(32).optional(),
|
|
38
|
+
availableWindows: z.array(z.string().max(64)).max(32).optional(),
|
|
39
|
+
contextFields: z.array(z.string().max(256)).max(32).optional(),
|
|
40
|
+
nonce: z.string().max(256),
|
|
41
41
|
timestamp: z.string().datetime(),
|
|
42
42
|
});
|
|
43
43
|
// ── Rejection (network.tulpa.rejection) — Stage 2b ──
|
|
@@ -58,12 +58,12 @@ export const RejectionReasonSchema = z.enum([
|
|
|
58
58
|
export const InkRejectionSchema = z.object({
|
|
59
59
|
protocol: z.literal("ink/0.1"),
|
|
60
60
|
type: z.literal("network.tulpa.rejection"),
|
|
61
|
-
intentRef: z.string(),
|
|
61
|
+
intentRef: z.string().max(256),
|
|
62
62
|
reason: RejectionReasonSchema,
|
|
63
63
|
detail: z.string().max(500).optional(),
|
|
64
|
-
retryAfter: z.string().optional(),
|
|
64
|
+
retryAfter: z.string().max(64).optional(),
|
|
65
65
|
backoffHint: InkBackoffHintSchema.optional(),
|
|
66
|
-
nonce: z.string(),
|
|
66
|
+
nonce: z.string().max(256),
|
|
67
67
|
timestamp: z.string().datetime(),
|
|
68
68
|
});
|
|
69
69
|
// ── Resolution (network.tulpa.resolution) — Stage 3 ──
|
|
@@ -74,16 +74,16 @@ export const ResolutionOutcomeSchema = z.enum([
|
|
|
74
74
|
"expired",
|
|
75
75
|
]);
|
|
76
76
|
export const ResolutionDetailsSchema = z.object({
|
|
77
|
-
scheduledAt: z.string().optional(),
|
|
78
|
-
duration: z.string().optional(),
|
|
77
|
+
scheduledAt: z.string().max(64).optional(),
|
|
78
|
+
duration: z.string().max(64).optional(),
|
|
79
79
|
}).passthrough();
|
|
80
80
|
export const InkResolutionSchema = z.object({
|
|
81
81
|
protocol: z.literal("ink/0.1"),
|
|
82
82
|
type: z.literal("network.tulpa.resolution"),
|
|
83
|
-
intentRef: z.string(),
|
|
83
|
+
intentRef: z.string().max(256),
|
|
84
84
|
outcome: ResolutionOutcomeSchema,
|
|
85
85
|
details: ResolutionDetailsSchema.optional(),
|
|
86
|
-
counterpartyDid: z.string().optional(),
|
|
87
|
-
nonce: z.string(),
|
|
86
|
+
counterpartyDid: z.string().max(512).optional(),
|
|
87
|
+
nonce: z.string().max(256),
|
|
88
88
|
timestamp: z.string().datetime(),
|
|
89
89
|
});
|
package/dist/models/intent.d.ts
CHANGED
|
@@ -223,14 +223,14 @@ export declare const MessageProvenanceSchema: z.ZodOptional<z.ZodObject<{
|
|
|
223
223
|
*/
|
|
224
224
|
export declare const INK_PROTOCOL_VERSIONS: readonly ["ink/0.1", "ink/0.2"];
|
|
225
225
|
export declare const ProtocolVersionSchema: z.ZodEnum<{
|
|
226
|
-
"ink/0.1": "ink/0.1";
|
|
227
226
|
"ink/0.2": "ink/0.2";
|
|
227
|
+
"ink/0.1": "ink/0.1";
|
|
228
228
|
}>;
|
|
229
229
|
export type ProtocolVersion = z.infer<typeof ProtocolVersionSchema>;
|
|
230
230
|
export declare const MessageEnvelopeSchema: z.ZodObject<{
|
|
231
231
|
protocol: z.ZodEnum<{
|
|
232
|
-
"ink/0.1": "ink/0.1";
|
|
233
232
|
"ink/0.2": "ink/0.2";
|
|
233
|
+
"ink/0.1": "ink/0.1";
|
|
234
234
|
}>;
|
|
235
235
|
id: z.ZodString;
|
|
236
236
|
correlationId: z.ZodString;
|
package/dist/models/intent.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ProfileSnapshotSchema } from "./profile.js";
|
|
3
|
+
import { isWithinBounds } from "../crypto/sign.js";
|
|
3
4
|
// --- Intent Types ---
|
|
4
5
|
export const IntentTypeSchema = z.enum([
|
|
5
6
|
"schedule_meeting",
|
|
@@ -191,6 +192,14 @@ export const MessageEnvelopeSchema = z.object({
|
|
|
191
192
|
* Returns the validated message or throws a ZodError.
|
|
192
193
|
*/
|
|
193
194
|
export function validateMessage(raw) {
|
|
195
|
+
// Bound the raw object's complexity BEFORE Zod walks it. A strict-mode parse
|
|
196
|
+
// must enumerate every key to reject unknowns, so a million-key object would
|
|
197
|
+
// otherwise burn hundreds of ms of CPU before being rejected. This also
|
|
198
|
+
// rejects JCS-unsafe numbers so a validated envelope is always one a
|
|
199
|
+
// canonicalizer can sign unambiguously.
|
|
200
|
+
if (!isWithinBounds(raw)) {
|
|
201
|
+
throw new Error("message exceeds complexity bounds");
|
|
202
|
+
}
|
|
194
203
|
const envelope = MessageEnvelopeSchema.parse(raw);
|
|
195
204
|
const payloadSchema = payloadSchemas[envelope.intent];
|
|
196
205
|
// Validate payload strictly — reject unknown fields
|
package/docs/maturity.md
CHANGED
|
@@ -28,7 +28,13 @@
|
|
|
28
28
|
|
|
29
29
|
These hold across major version 0 (`ink/0.1` and `ink/0.2`):
|
|
30
30
|
|
|
31
|
-
- Envelope structure (fields, canonicalization with JCS / RFC 8785)
|
|
31
|
+
- Envelope structure (fields, canonicalization with JCS / RFC 8785).
|
|
32
|
+
Signed bodies are restricted to JSON numbers that every conforming
|
|
33
|
+
canonicalizer serializes identically: non-finite values, negative zero,
|
|
34
|
+
and values whose shortest form uses exponential notation (for example
|
|
35
|
+
`1e21` or `1e-7`) are rejected at sign and verify time. INK payloads
|
|
36
|
+
carry only small integers and plain decimals, so this keeps the signed
|
|
37
|
+
bytes unambiguous across implementations.
|
|
32
38
|
- Ed25519 signing base: `ink/0.1\nMETHOD\nPATH\nrecipientDid\nJCS(body)\ntimestamp`
|
|
33
39
|
- Agent Card schema for `keys.signing` and `keys.encryption`
|
|
34
40
|
- Key rotation authority rule (see `key-rotation-rule.md`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adastracomputing/ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Library and specification for the INK (Inter-agent Networking Kernel) protocol",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"author": "Ad Astra Computing Inc.",
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"check:pack": "./scripts/check-pack.sh",
|
|
52
52
|
"gen:body-vectors": "tsx scripts/gen-body-signature-vectors.ts",
|
|
53
53
|
"prepack": "npm run build",
|
|
54
|
-
"prepublishOnly": "npm run build"
|
|
54
|
+
"prepublishOnly": "npm run build",
|
|
55
|
+
"audit:all": "bash scripts/audit-npm-projects.sh"
|
|
55
56
|
},
|
|
56
57
|
"dependencies": {
|
|
57
58
|
"@noble/curves": "^2.2.0",
|
|
@@ -61,14 +62,14 @@
|
|
|
61
62
|
"zod": "^4.4.3"
|
|
62
63
|
},
|
|
63
64
|
"devDependencies": {
|
|
64
|
-
"@cloudflare/workers-types": "^4.
|
|
65
|
-
"@types/node": "^24.
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
67
|
-
"@typescript-eslint/parser": "^8.
|
|
65
|
+
"@cloudflare/workers-types": "^4.20260610.1",
|
|
66
|
+
"@types/node": "^24.13.1",
|
|
67
|
+
"@typescript-eslint/eslint-plugin": "^8.61.0",
|
|
68
|
+
"@typescript-eslint/parser": "^8.61.0",
|
|
68
69
|
"eslint": "^10.4.1",
|
|
69
70
|
"tsx": "^4.22.4",
|
|
70
71
|
"typescript": "^6.0.3",
|
|
71
|
-
"vitest": "^4.1.
|
|
72
|
+
"vitest": "^4.1.8"
|
|
72
73
|
},
|
|
73
74
|
"keywords": [
|
|
74
75
|
"ink",
|