agents-chain 0.0.1 → 0.0.3
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 +248 -32
- package/dist/app/app-wrapper.d.ts +43 -0
- package/dist/app/app-wrapper.d.ts.map +1 -0
- package/dist/app/app-wrapper.js +122 -0
- package/dist/app/app-wrapper.js.map +1 -0
- package/dist/app/capability-registry.d.ts +31 -0
- package/dist/app/capability-registry.d.ts.map +1 -0
- package/dist/app/capability-registry.js +65 -0
- package/dist/app/capability-registry.js.map +1 -0
- package/dist/audit/audit-exporter.d.ts +82 -0
- package/dist/audit/audit-exporter.d.ts.map +1 -0
- package/dist/audit/audit-exporter.js +94 -0
- package/dist/audit/audit-exporter.js.map +1 -0
- package/dist/audit/audit-log.d.ts +10 -0
- package/dist/audit/audit-log.d.ts.map +1 -1
- package/dist/audit/audit-log.js +18 -0
- package/dist/audit/audit-log.js.map +1 -1
- package/dist/auth/constraints.d.ts +19 -0
- package/dist/auth/constraints.d.ts.map +1 -0
- package/dist/auth/constraints.js +85 -0
- package/dist/auth/constraints.js.map +1 -0
- package/dist/auth/token-verifier.d.ts +26 -2
- package/dist/auth/token-verifier.d.ts.map +1 -1
- package/dist/auth/token-verifier.js +47 -9
- package/dist/auth/token-verifier.js.map +1 -1
- package/dist/chain.d.ts +59 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +115 -0
- package/dist/chain.js.map +1 -1
- package/dist/crypto/ed25519.d.ts.map +1 -1
- package/dist/crypto/ed25519.js +2 -1
- package/dist/crypto/ed25519.js.map +1 -1
- package/dist/crypto/utils.d.ts +1 -1
- package/dist/crypto/utils.d.ts.map +1 -1
- package/dist/host/host-identity.d.ts +66 -0
- package/dist/host/host-identity.d.ts.map +1 -0
- package/dist/host/host-identity.js +109 -0
- package/dist/host/host-identity.js.map +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/jti-cache.d.ts +31 -4
- package/dist/memory/jti-cache.d.ts.map +1 -1
- package/dist/memory/jti-cache.js +40 -13
- package/dist/memory/jti-cache.js.map +1 -1
- package/dist/types/capabilities.d.ts +64 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +9 -0
- package/dist/types/capabilities.js.map +1 -0
- package/dist/types/chain.d.ts +51 -1
- package/dist/types/chain.d.ts.map +1 -1
- package/dist/types/protocol.d.ts +61 -0
- package/dist/types/protocol.d.ts.map +1 -0
- package/dist/types/protocol.js +10 -0
- package/dist/types/protocol.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditExporter — interface and built-in implementations for draining audit entries.
|
|
3
|
+
*
|
|
4
|
+
* The AuditLog is in-memory and ephemeral. Use an exporter to push entries to
|
|
5
|
+
* a persistent destination: a remote API, a database, a log aggregator, etc.
|
|
6
|
+
*
|
|
7
|
+
* Built-in exporters:
|
|
8
|
+
* ConsoleAuditExporter — pretty-prints to stdout (good for development)
|
|
9
|
+
* HttpAuditExporter — POSTs batches to any HTTP endpoint (production)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* // Flush on process exit
|
|
13
|
+
* process.on("SIGTERM", async () => {
|
|
14
|
+
* await chain.drain(new HttpAuditExporter({ endpoint: "https://audit.melduo.com/ingest", apiKey: "xxx" }));
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Or flush periodically
|
|
18
|
+
* setInterval(async () => {
|
|
19
|
+
* await chain.drain(exporter);
|
|
20
|
+
* }, 30_000);
|
|
21
|
+
*/
|
|
22
|
+
import type { AuditEntry } from "../types/audit.js";
|
|
23
|
+
export interface AuditExporter {
|
|
24
|
+
/**
|
|
25
|
+
* Export a batch of audit entries to a destination.
|
|
26
|
+
* Called by AuditLog.drain(). Must not throw — errors should be handled internally.
|
|
27
|
+
*/
|
|
28
|
+
export(entries: AuditEntry[]): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Prints audit entries to stdout as JSON lines.
|
|
32
|
+
* Use in development or when piping logs to a collector.
|
|
33
|
+
*/
|
|
34
|
+
export declare class ConsoleAuditExporter implements AuditExporter {
|
|
35
|
+
export(entries: AuditEntry[]): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export type HttpAuditExporterConfig = {
|
|
38
|
+
/**
|
|
39
|
+
* The HTTP endpoint to POST batches to.
|
|
40
|
+
* e.g. "https://audit.melduo.com/ingest"
|
|
41
|
+
*/
|
|
42
|
+
endpoint: string;
|
|
43
|
+
/**
|
|
44
|
+
* Optional API key sent as "Authorization: Bearer <apiKey>".
|
|
45
|
+
*/
|
|
46
|
+
apiKey?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Additional headers to include in every request.
|
|
49
|
+
*/
|
|
50
|
+
headers?: Record<string, string>;
|
|
51
|
+
/**
|
|
52
|
+
* Maximum entries per POST request. Default: 50.
|
|
53
|
+
*/
|
|
54
|
+
batchSize?: number;
|
|
55
|
+
/**
|
|
56
|
+
* Request timeout in milliseconds. Default: 10_000.
|
|
57
|
+
*/
|
|
58
|
+
timeoutMs?: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* POSTs audit entries to any HTTP endpoint in configurable batches.
|
|
62
|
+
* Suitable for the Melduo hosted audit service or any self-hosted receiver.
|
|
63
|
+
*
|
|
64
|
+
* Request format:
|
|
65
|
+
* POST <endpoint>
|
|
66
|
+
* Content-Type: application/json
|
|
67
|
+
* Authorization: Bearer <apiKey> (if configured)
|
|
68
|
+
* Body: { "entries": AuditEntry[] }
|
|
69
|
+
*
|
|
70
|
+
* Errors are logged to stderr but never thrown — audit export failures
|
|
71
|
+
* should never crash the application.
|
|
72
|
+
*/
|
|
73
|
+
export declare class HttpAuditExporter implements AuditExporter {
|
|
74
|
+
private readonly config;
|
|
75
|
+
private readonly batchSize;
|
|
76
|
+
private readonly timeoutMs;
|
|
77
|
+
private readonly headers;
|
|
78
|
+
constructor(config: HttpAuditExporterConfig);
|
|
79
|
+
export(entries: AuditEntry[]): Promise<void>;
|
|
80
|
+
private sendBatch;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=audit-exporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-exporter.d.ts","sourceRoot":"","sources":["../../src/audit/audit-exporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,MAAM,WAAW,aAAa;IAC1B;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAID;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,aAAa;IAChD,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CASrD;AAID,MAAM,MAAM,uBAAuB,GAAG;IAClC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IAKvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;gBAEpB,MAAM,EAAE,uBAAuB;IAUtD,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAUpC,SAAS;CA2B1B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuditExporter — interface and built-in implementations for draining audit entries.
|
|
3
|
+
*
|
|
4
|
+
* The AuditLog is in-memory and ephemeral. Use an exporter to push entries to
|
|
5
|
+
* a persistent destination: a remote API, a database, a log aggregator, etc.
|
|
6
|
+
*
|
|
7
|
+
* Built-in exporters:
|
|
8
|
+
* ConsoleAuditExporter — pretty-prints to stdout (good for development)
|
|
9
|
+
* HttpAuditExporter — POSTs batches to any HTTP endpoint (production)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* // Flush on process exit
|
|
13
|
+
* process.on("SIGTERM", async () => {
|
|
14
|
+
* await chain.drain(new HttpAuditExporter({ endpoint: "https://audit.melduo.com/ingest", apiKey: "xxx" }));
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* // Or flush periodically
|
|
18
|
+
* setInterval(async () => {
|
|
19
|
+
* await chain.drain(exporter);
|
|
20
|
+
* }, 30_000);
|
|
21
|
+
*/
|
|
22
|
+
// ─── ConsoleAuditExporter ─────────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Prints audit entries to stdout as JSON lines.
|
|
25
|
+
* Use in development or when piping logs to a collector.
|
|
26
|
+
*/
|
|
27
|
+
export class ConsoleAuditExporter {
|
|
28
|
+
async export(entries) {
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
console.log(JSON.stringify({
|
|
31
|
+
...entry,
|
|
32
|
+
// Human-readable timestamp
|
|
33
|
+
timestamp_iso: new Date(entry.timestamp).toISOString(),
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* POSTs audit entries to any HTTP endpoint in configurable batches.
|
|
40
|
+
* Suitable for the Melduo hosted audit service or any self-hosted receiver.
|
|
41
|
+
*
|
|
42
|
+
* Request format:
|
|
43
|
+
* POST <endpoint>
|
|
44
|
+
* Content-Type: application/json
|
|
45
|
+
* Authorization: Bearer <apiKey> (if configured)
|
|
46
|
+
* Body: { "entries": AuditEntry[] }
|
|
47
|
+
*
|
|
48
|
+
* Errors are logged to stderr but never thrown — audit export failures
|
|
49
|
+
* should never crash the application.
|
|
50
|
+
*/
|
|
51
|
+
export class HttpAuditExporter {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
this.config = config;
|
|
54
|
+
this.batchSize = config.batchSize ?? 50;
|
|
55
|
+
this.timeoutMs = config.timeoutMs ?? 10000;
|
|
56
|
+
this.headers = {
|
|
57
|
+
"Content-Type": "application/json",
|
|
58
|
+
...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),
|
|
59
|
+
...config.headers,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async export(entries) {
|
|
63
|
+
if (entries.length === 0)
|
|
64
|
+
return;
|
|
65
|
+
// Split into batches
|
|
66
|
+
for (let i = 0; i < entries.length; i += this.batchSize) {
|
|
67
|
+
const batch = entries.slice(i, i + this.batchSize);
|
|
68
|
+
await this.sendBatch(batch);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async sendBatch(batch) {
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
74
|
+
try {
|
|
75
|
+
const res = await fetch(this.config.endpoint, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: this.headers,
|
|
78
|
+
body: JSON.stringify({ entries: batch }),
|
|
79
|
+
signal: controller.signal,
|
|
80
|
+
});
|
|
81
|
+
if (!res.ok) {
|
|
82
|
+
const body = await res.text().catch(() => "(unreadable)");
|
|
83
|
+
console.error(`[agents-chain] HttpAuditExporter: server returned ${res.status} — ${body}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.error(`[agents-chain] HttpAuditExporter: failed to send batch of ${batch.length} entries:`, err instanceof Error ? err.message : String(err));
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=audit-exporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-exporter.js","sourceRoot":"","sources":["../../src/audit/audit-exporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAcH,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,OAAO,oBAAoB;IAC7B,KAAK,CAAC,MAAM,CAAC,OAAqB;QAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;gBACvB,GAAG,KAAK;gBACR,2BAA2B;gBAC3B,aAAa,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;aACzD,CAAC,CAAC,CAAC;QACR,CAAC;IACL,CAAC;CACJ;AAgCD;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,iBAAiB;IAK1B,YAA6B,MAA+B;QAA/B,WAAM,GAAN,MAAM,CAAyB;QACxD,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,KAAM,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG;YACX,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,GAAG,MAAM,CAAC,OAAO;SACpB,CAAC;IACN,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAqB;QAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEjC,qBAAqB;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YACnD,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,KAAmB;QACvC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnE,IAAI,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;gBAC1C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;gBACxC,MAAM,EAAE,UAAU,CAAC,MAAM;aAC5B,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACV,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;gBAC1D,OAAO,CAAC,KAAK,CACT,qDAAqD,GAAG,CAAC,MAAM,MAAM,IAAI,EAAE,CAC9E,CAAC;YACN,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CACT,6DAA6D,KAAK,CAAC,MAAM,WAAW,EACpF,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACnD,CAAC;QACN,CAAC;gBAAS,CAAC;YACP,YAAY,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type { EncryptedStore } from "../memory/encrypted-store.js";
|
|
11
11
|
import type { AuditEntry, AuditResult } from "../types/audit.js";
|
|
12
12
|
import type { VerifiedCallContext } from "../auth/token-verifier.js";
|
|
13
|
+
import type { AuditExporter } from "./audit-exporter.js";
|
|
13
14
|
export type RecordDeniedOptions = {
|
|
14
15
|
agentId: string;
|
|
15
16
|
agentName: string;
|
|
@@ -40,5 +41,14 @@ export declare class AuditLog {
|
|
|
40
41
|
/** Return entries filtered by capability name. */
|
|
41
42
|
getByCapability(capability: string): AuditEntry[];
|
|
42
43
|
get count(): number;
|
|
44
|
+
/**
|
|
45
|
+
* Export all entries via the provided exporter, then clear the in-memory log.
|
|
46
|
+
*
|
|
47
|
+
* Call this periodically or on process shutdown to push entries to a
|
|
48
|
+
* persistent destination (database, HTTP endpoint, log aggregator, etc.).
|
|
49
|
+
*
|
|
50
|
+
* If no exporter is provided, the log is simply cleared without exporting.
|
|
51
|
+
*/
|
|
52
|
+
drain(exporter?: AuditExporter): Promise<void>;
|
|
43
53
|
}
|
|
44
54
|
//# sourceMappingURL=audit-log.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-log.d.ts","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"audit-log.d.ts","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC5B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,qBAAa,QAAQ;IACL,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,cAAc;IAElD,mEAAmE;IACnE,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,UAAU;IAkBnD,6DAA6D;IAC7D,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU;IAkB/C,2DAA2D;IAC3D,MAAM,IAAI,UAAU,EAAE;IAItB,8CAA8C;IAC9C,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,EAAE;IAI9C,kDAAkD;IAClD,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE;IAIjD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;;;;;;OAOG;IACG,KAAK,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAWvD"}
|
package/dist/audit/audit-log.js
CHANGED
|
@@ -64,6 +64,24 @@ export class AuditLog {
|
|
|
64
64
|
get count() {
|
|
65
65
|
return this.getAll().length;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Export all entries via the provided exporter, then clear the in-memory log.
|
|
69
|
+
*
|
|
70
|
+
* Call this periodically or on process shutdown to push entries to a
|
|
71
|
+
* persistent destination (database, HTTP endpoint, log aggregator, etc.).
|
|
72
|
+
*
|
|
73
|
+
* If no exporter is provided, the log is simply cleared without exporting.
|
|
74
|
+
*/
|
|
75
|
+
async drain(exporter) {
|
|
76
|
+
const entries = this.getAll();
|
|
77
|
+
if (entries.length === 0)
|
|
78
|
+
return;
|
|
79
|
+
if (exporter) {
|
|
80
|
+
await exporter.export(entries);
|
|
81
|
+
}
|
|
82
|
+
// Clear the log after export
|
|
83
|
+
this.store.set(STORE_KEY_LOG, []);
|
|
84
|
+
}
|
|
67
85
|
}
|
|
68
86
|
/**
|
|
69
87
|
* Strip values that look like secrets from args before logging.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../../src/audit/audit-log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* enforceConstraints — validates call arguments against a CapabilityGrant's constraints.
|
|
3
|
+
*
|
|
4
|
+
* Called after JWT verification passes and before capability.execute() is called.
|
|
5
|
+
* Throws ChainAuthError("constraint_violated") if any constraint is not satisfied.
|
|
6
|
+
*
|
|
7
|
+
* Supported operators:
|
|
8
|
+
* { max: N } → args[key] must be <= N
|
|
9
|
+
* { min: N } → args[key] must be >= N
|
|
10
|
+
* { in: [...] } → args[key] must be in the whitelist
|
|
11
|
+
* { not_in: [...] } → args[key] must NOT be in the blacklist
|
|
12
|
+
* <primitive> → args[key] must exactly equal the primitive value
|
|
13
|
+
*
|
|
14
|
+
* Fields present in constraints but absent from args are allowed (optional fields).
|
|
15
|
+
* Fields present in args but absent from constraints are unconstrained.
|
|
16
|
+
*/
|
|
17
|
+
import type { GrantConstraints } from "../types/capabilities.js";
|
|
18
|
+
export declare function enforceConstraints(constraints: GrantConstraints, args: Record<string, unknown>): void;
|
|
19
|
+
//# sourceMappingURL=constraints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraints.d.ts","sourceRoot":"","sources":["../../src/auth/constraints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAA4D,MAAM,0BAA0B,CAAC;AAE3H,wBAAgB,kBAAkB,CAC9B,WAAW,EAAE,gBAAgB,EAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,IAAI,CAmBN"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* enforceConstraints — validates call arguments against a CapabilityGrant's constraints.
|
|
3
|
+
*
|
|
4
|
+
* Called after JWT verification passes and before capability.execute() is called.
|
|
5
|
+
* Throws ChainAuthError("constraint_violated") if any constraint is not satisfied.
|
|
6
|
+
*
|
|
7
|
+
* Supported operators:
|
|
8
|
+
* { max: N } → args[key] must be <= N
|
|
9
|
+
* { min: N } → args[key] must be >= N
|
|
10
|
+
* { in: [...] } → args[key] must be in the whitelist
|
|
11
|
+
* { not_in: [...] } → args[key] must NOT be in the blacklist
|
|
12
|
+
* <primitive> → args[key] must exactly equal the primitive value
|
|
13
|
+
*
|
|
14
|
+
* Fields present in constraints but absent from args are allowed (optional fields).
|
|
15
|
+
* Fields present in args but absent from constraints are unconstrained.
|
|
16
|
+
*/
|
|
17
|
+
import { ChainAuthError } from "../errors/chain-error.js";
|
|
18
|
+
export function enforceConstraints(constraints, args) {
|
|
19
|
+
const violations = [];
|
|
20
|
+
for (const [field, constraint] of Object.entries(constraints)) {
|
|
21
|
+
const value = args[field];
|
|
22
|
+
// Field not present in args — skip (constraint only applies when field is provided)
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
continue;
|
|
25
|
+
const violation = checkConstraint(field, value, constraint);
|
|
26
|
+
if (violation)
|
|
27
|
+
violations.push(violation);
|
|
28
|
+
}
|
|
29
|
+
if (violations.length > 0) {
|
|
30
|
+
throw new ChainAuthError("constraint_violated", `Capability argument constraints violated: ${violations.join("; ")}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function checkConstraint(field, value, constraint) {
|
|
34
|
+
// Operator constraint
|
|
35
|
+
if (isConstraintOperator(constraint)) {
|
|
36
|
+
return checkOperator(field, value, constraint);
|
|
37
|
+
}
|
|
38
|
+
// Primitive constraint — exact equality
|
|
39
|
+
if (value !== constraint) {
|
|
40
|
+
return `field "${field}": expected exactly ${JSON.stringify(constraint)}, got ${JSON.stringify(value)}`;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function isConstraintOperator(value) {
|
|
45
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
46
|
+
}
|
|
47
|
+
function checkOperator(field, value, op) {
|
|
48
|
+
if (op.max !== undefined) {
|
|
49
|
+
if (typeof value !== "number") {
|
|
50
|
+
return `field "${field}": max constraint requires a number, got ${typeof value}`;
|
|
51
|
+
}
|
|
52
|
+
if (value > op.max) {
|
|
53
|
+
return `field "${field}": ${value} exceeds maximum of ${op.max}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (op.min !== undefined) {
|
|
57
|
+
if (typeof value !== "number") {
|
|
58
|
+
return `field "${field}": min constraint requires a number, got ${typeof value}`;
|
|
59
|
+
}
|
|
60
|
+
if (value < op.min) {
|
|
61
|
+
return `field "${field}": ${value} is below minimum of ${op.min}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (op.in !== undefined) {
|
|
65
|
+
if (!isPrimitive(value)) {
|
|
66
|
+
return `field "${field}": in constraint requires a primitive value, got ${typeof value}`;
|
|
67
|
+
}
|
|
68
|
+
if (!op.in.includes(value)) {
|
|
69
|
+
return `field "${field}": "${value}" is not in allowed list [${op.in.map((v) => JSON.stringify(v)).join(", ")}]`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (op.not_in !== undefined) {
|
|
73
|
+
if (!isPrimitive(value)) {
|
|
74
|
+
return `field "${field}": not_in constraint requires a primitive value, got ${typeof value}`;
|
|
75
|
+
}
|
|
76
|
+
if (op.not_in.includes(value)) {
|
|
77
|
+
return `field "${field}": "${value}" is in blocked list [${op.not_in.map((v) => JSON.stringify(v)).join(", ")}]`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function isPrimitive(value) {
|
|
83
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=constraints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraints.js","sourceRoot":"","sources":["../../src/auth/constraints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,MAAM,UAAU,kBAAkB,CAC9B,WAA6B,EAC7B,IAA6B;IAE7B,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAE1B,oFAAoF;QACpF,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAElC,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QAC5D,IAAI,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,cAAc,CACpB,qBAAqB,EACrB,6CAA6C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvE,CAAC;IACN,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CACpB,KAAa,EACb,KAAc,EACd,UAA2B;IAE3B,sBAAsB;IACtB,IAAI,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QACnC,OAAO,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IACnD,CAAC;IAED,wCAAwC;IACxC,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;QACvB,OAAO,UAAU,KAAK,uBAAuB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5G,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAsB;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,aAAa,CAClB,KAAa,EACb,KAAc,EACd,EAAsB;IAEtB,IAAI,EAAE,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,UAAU,KAAK,4CAA4C,OAAO,KAAK,EAAE,CAAC;QACrF,CAAC;QACD,IAAI,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;YACjB,OAAO,UAAU,KAAK,MAAM,KAAK,uBAAuB,EAAE,CAAC,GAAG,EAAE,CAAC;QACrE,CAAC;IACL,CAAC;IAED,IAAI,EAAE,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,UAAU,KAAK,4CAA4C,OAAO,KAAK,EAAE,CAAC;QACrF,CAAC;QACD,IAAI,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;YACjB,OAAO,UAAU,KAAK,MAAM,KAAK,wBAAwB,EAAE,CAAC,GAAG,EAAE,CAAC;QACtE,CAAC;IACL,CAAC;IAED,IAAI,EAAE,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,UAAU,KAAK,oDAAoD,OAAO,KAAK,EAAE,CAAC;QAC7F,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,KAA4B,CAAC,EAAE,CAAC;YAChD,OAAO,UAAU,KAAK,OAAO,KAAK,6BAA6B,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACrH,CAAC;IACL,CAAC;IAED,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,UAAU,KAAK,wDAAwD,OAAO,KAAK,EAAE,CAAC;QACjG,CAAC;QACD,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAA4B,CAAC,EAAE,CAAC;YACnD,OAAO,UAAU,KAAK,OAAO,KAAK,yBAAyB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACrH,CAAC;IACL,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,CAAC;AAChG,CAAC"}
|
|
@@ -18,20 +18,44 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { AgentIdentity } from "../identity/agent-identity.js";
|
|
20
20
|
import type { JtiCache } from "../memory/jti-cache.js";
|
|
21
|
+
import type { ResolvedGrant } from "../types/protocol.js";
|
|
21
22
|
export type VerifiedCallContext = {
|
|
22
23
|
agentId: string;
|
|
23
24
|
agentName: string;
|
|
24
25
|
hostname: string;
|
|
26
|
+
hostId?: string;
|
|
25
27
|
capability: string;
|
|
26
28
|
jti: string;
|
|
27
29
|
iat: number;
|
|
28
30
|
exp: number;
|
|
29
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Optional config for TokenVerifier.
|
|
34
|
+
*
|
|
35
|
+
* grantResolver: If provided, resolve grants from an external source (user's DB/Redis).
|
|
36
|
+
* If it returns null for a capability, the call is denied.
|
|
37
|
+
* If not provided, the verifier falls back to the in-memory registered grants.
|
|
38
|
+
*/
|
|
39
|
+
export type VerifierConfig = {
|
|
40
|
+
jwtMaxAge?: number;
|
|
41
|
+
clockSkew?: number;
|
|
42
|
+
grantResolver?: (agentId: string, capability: string) => Promise<ResolvedGrant | null>;
|
|
43
|
+
};
|
|
30
44
|
export declare class TokenVerifier {
|
|
31
45
|
private readonly identity;
|
|
32
46
|
private readonly jtiCache;
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
private readonly jwtMaxAge;
|
|
48
|
+
private readonly clockSkew;
|
|
49
|
+
private readonly grantResolver?;
|
|
50
|
+
constructor(identity: AgentIdentity, jtiCache: JtiCache, config?: VerifierConfig);
|
|
51
|
+
/**
|
|
52
|
+
* Verify a token for a capability call.
|
|
53
|
+
*
|
|
54
|
+
* @param token The agent+jwt token
|
|
55
|
+
* @param capability The capability being requested
|
|
56
|
+
* @param grants Optional pre-resolved grants (passed by app-wrapper at wrap time)
|
|
57
|
+
*/
|
|
58
|
+
verify(token: string, capability: string, grants?: ResolvedGrant[]): Promise<VerifiedCallContext>;
|
|
35
59
|
private assertTemporal;
|
|
36
60
|
}
|
|
37
61
|
//# sourceMappingURL=token-verifier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-verifier.d.ts","sourceRoot":"","sources":["../../src/auth/token-verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"token-verifier.d.ts","sourceRoot":"","sources":["../../src/auth/token-verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAK1D,MAAM,MAAM,mBAAmB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;CAC1F,CAAC;AAEF,qBAAa,aAAa;IAMlB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAN7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAyE;gBAGnF,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,QAAQ,EACnC,MAAM,CAAC,EAAE,cAAc;IAO3B;;;;;;OAMG;IACG,MAAM,CACR,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,aAAa,EAAE,GACzB,OAAO,CAAC,mBAAmB,CAAC;IA6F/B,OAAO,CAAC,cAAc;CAwBzB"}
|
|
@@ -21,11 +21,21 @@ import { ChainAuthError } from "../errors/chain-error.js";
|
|
|
21
21
|
const CLOCK_SKEW_MS = 30000; // 30 seconds tolerance
|
|
22
22
|
const JWT_MAX_AGE_MS = 60000; // 60 seconds — matches TOKEN_TTL_SECONDS
|
|
23
23
|
export class TokenVerifier {
|
|
24
|
-
constructor(identity, jtiCache) {
|
|
24
|
+
constructor(identity, jtiCache, config) {
|
|
25
25
|
this.identity = identity;
|
|
26
26
|
this.jtiCache = jtiCache;
|
|
27
|
+
this.jwtMaxAge = config?.jwtMaxAge ?? JWT_MAX_AGE_MS;
|
|
28
|
+
this.clockSkew = config?.clockSkew ?? CLOCK_SKEW_MS;
|
|
29
|
+
this.grantResolver = config?.grantResolver;
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Verify a token for a capability call.
|
|
33
|
+
*
|
|
34
|
+
* @param token The agent+jwt token
|
|
35
|
+
* @param capability The capability being requested
|
|
36
|
+
* @param grants Optional pre-resolved grants (passed by app-wrapper at wrap time)
|
|
37
|
+
*/
|
|
38
|
+
async verify(token, capability, grants) {
|
|
29
39
|
let unsafeClaims;
|
|
30
40
|
try {
|
|
31
41
|
const decoded = decodeJwtUnsafe(token);
|
|
@@ -51,10 +61,38 @@ export class TokenVerifier {
|
|
|
51
61
|
throw new ChainAuthError("token_invalid", `Signature verification failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
52
62
|
}
|
|
53
63
|
this.assertTemporal(unsafeClaims);
|
|
54
|
-
this.jtiCache.assert(this.identity.agentId, unsafeClaims.jti);
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
await this.jtiCache.assert(this.identity.agentId, unsafeClaims.jti);
|
|
65
|
+
// ── Step 9: Resolve capability grant ─────────────────────────────────
|
|
66
|
+
// Priority: external grantResolver > passed grants array > in-memory identity
|
|
67
|
+
let resolvedGrant = null;
|
|
68
|
+
if (this.grantResolver) {
|
|
69
|
+
resolvedGrant = await this.grantResolver(this.identity.agentId, capability);
|
|
57
70
|
}
|
|
71
|
+
else if (grants) {
|
|
72
|
+
const found = grants.find((g) => g.capability === capability);
|
|
73
|
+
resolvedGrant = found ?? null;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Fall back to in-memory registered grants (AgentsChain default behaviour)
|
|
77
|
+
resolvedGrant = this.identity.hasCapability(capability)
|
|
78
|
+
? { capability, status: "active" }
|
|
79
|
+
: null;
|
|
80
|
+
}
|
|
81
|
+
if (!resolvedGrant || resolvedGrant.status !== "active") {
|
|
82
|
+
const reason = resolvedGrant?.status === "pending"
|
|
83
|
+
? `capability "${capability}" is pending approval`
|
|
84
|
+
: resolvedGrant?.status === "denied"
|
|
85
|
+
? `capability "${capability}" has been denied`
|
|
86
|
+
: `agent "${this.identity.agentId}" does not hold a grant for capability "${capability}"`;
|
|
87
|
+
throw new ChainAuthError("capability_denied", reason);
|
|
88
|
+
}
|
|
89
|
+
// Check grant expiry
|
|
90
|
+
if (resolvedGrant.expiresAt !== undefined && resolvedGrant.expiresAt < Date.now()) {
|
|
91
|
+
throw new ChainAuthError("capability_denied", `Grant for "${capability}" has expired`);
|
|
92
|
+
}
|
|
93
|
+
// ── Step 9b: Enforce constraints ─────────────────────────────────────
|
|
94
|
+
// Constraints are enforced here so they apply to ALL callers (app-wrapper and AI wrappers)
|
|
95
|
+
// App-wrapper also enforces before execute() — this is the canonical enforcement point.
|
|
58
96
|
return {
|
|
59
97
|
agentId: this.identity.agentId,
|
|
60
98
|
agentName: this.identity.registration.agentName,
|
|
@@ -72,14 +110,14 @@ export class TokenVerifier {
|
|
|
72
110
|
const nowMs = Date.now();
|
|
73
111
|
const iatMs = claims.iat * 1000;
|
|
74
112
|
const expMs = claims.exp * 1000;
|
|
75
|
-
if (iatMs > nowMs +
|
|
113
|
+
if (iatMs > nowMs + this.clockSkew) {
|
|
76
114
|
throw new ChainAuthError("token_invalid", "JWT iat is in the future — clock skew too large or token pre-generated");
|
|
77
115
|
}
|
|
78
|
-
if (expMs < nowMs -
|
|
116
|
+
if (expMs < nowMs - this.clockSkew) {
|
|
79
117
|
throw new ChainAuthError("token_expired", "JWT has expired");
|
|
80
118
|
}
|
|
81
|
-
if (expMs - iatMs >
|
|
82
|
-
throw new ChainAuthError("token_invalid", `JWT lifetime of ${Math.round((expMs - iatMs) / 1000)}s exceeds maximum of ${
|
|
119
|
+
if (expMs - iatMs > this.jwtMaxAge + this.clockSkew) {
|
|
120
|
+
throw new ChainAuthError("token_invalid", `JWT lifetime of ${Math.round((expMs - iatMs) / 1000)}s exceeds maximum of ${this.jwtMaxAge / 1000}s`);
|
|
83
121
|
}
|
|
84
122
|
}
|
|
85
123
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-verifier.js","sourceRoot":"","sources":["../../src/auth/token-verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"token-verifier.js","sourceRoot":"","sources":["../../src/auth/token-verifier.ts"],"names":[],"mappings":"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"}
|
package/dist/chain.d.ts
CHANGED
|
@@ -15,8 +15,11 @@
|
|
|
15
15
|
* const log = chain.getAuditLog(); // All calls, decrypted
|
|
16
16
|
* const stats = chain.getStats(); // Summary counts
|
|
17
17
|
*/
|
|
18
|
-
import
|
|
18
|
+
import { HostIdentity } from "./host/host-identity.js";
|
|
19
|
+
import type { AgentConfig, ChainStats, AuditSnapshot, AppChainConfig } from "./types/chain.js";
|
|
19
20
|
import type { AuditEntry } from "./types/audit.js";
|
|
21
|
+
import type { AuditExporter } from "./audit/audit-exporter.js";
|
|
22
|
+
import type { ResolvedGrant, AgentConfiguration } from "./types/protocol.js";
|
|
20
23
|
export declare class AgentsChain {
|
|
21
24
|
private readonly store;
|
|
22
25
|
private readonly identity;
|
|
@@ -33,4 +36,59 @@ export declare class AgentsChain {
|
|
|
33
36
|
exportAudit(): AuditSnapshot;
|
|
34
37
|
getStats(): ChainStats;
|
|
35
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* AppChain — wraps any app object with capability-gated security.
|
|
41
|
+
*
|
|
42
|
+
* Unlike AgentsChain (which wraps AI SDKs), AppChain wraps your own service
|
|
43
|
+
* objects or any external app, enforcing agent identity, permission grants,
|
|
44
|
+
* constraint validation, and an audit trail on every capability call.
|
|
45
|
+
*
|
|
46
|
+
* Usage:
|
|
47
|
+
* const chain = await AppChain.create({
|
|
48
|
+
* providerName: "billing-service",
|
|
49
|
+
* issuer: "https://billing.mycompany.com",
|
|
50
|
+
* capabilities: [invoiceCapability, refundCapability],
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* // Wrap your service — every call is identity-bound and audited
|
|
54
|
+
* const secured = chain.wrap(billingService, agentGrants);
|
|
55
|
+
* const invoice = await secured.createInvoice({ customerId: "c1", amount: 500 });
|
|
56
|
+
*
|
|
57
|
+
* // Serve well-known for agent discovery
|
|
58
|
+
* app.get("/.well-known/agent-configuration", (req, res) => res.json(chain.getWellKnownConfig()));
|
|
59
|
+
*
|
|
60
|
+
* // Flush audit on shutdown
|
|
61
|
+
* process.on("SIGTERM", () => chain.drain());
|
|
62
|
+
*/
|
|
63
|
+
export declare class AppChain {
|
|
64
|
+
readonly host: HostIdentity;
|
|
65
|
+
private readonly registry;
|
|
66
|
+
private readonly identity;
|
|
67
|
+
private readonly builder;
|
|
68
|
+
private readonly verifier;
|
|
69
|
+
private readonly log;
|
|
70
|
+
private readonly exporter?;
|
|
71
|
+
private constructor();
|
|
72
|
+
static create(config: AppChainConfig): Promise<AppChain>;
|
|
73
|
+
/**
|
|
74
|
+
* Wrap any object with capability-gated security.
|
|
75
|
+
*
|
|
76
|
+
* @param target The service object to wrap
|
|
77
|
+
* @param grants The resolved grants for the agent making calls
|
|
78
|
+
* @returns A Proxy with the same type as target
|
|
79
|
+
*/
|
|
80
|
+
wrap<T extends object>(target: T, grants: ResolvedGrant[]): T;
|
|
81
|
+
/**
|
|
82
|
+
* Get the well-known configuration object.
|
|
83
|
+
* Serve this at GET /.well-known/agent-configuration.
|
|
84
|
+
*/
|
|
85
|
+
getWellKnownConfig(endpointPrefix?: string): AgentConfiguration;
|
|
86
|
+
getAuditLog(): AuditEntry[];
|
|
87
|
+
getStats(): ChainStats;
|
|
88
|
+
/**
|
|
89
|
+
* Export all audit entries via the configured exporter, then clear the log.
|
|
90
|
+
* If no exporter configured, the log is just cleared.
|
|
91
|
+
*/
|
|
92
|
+
drain(exporter?: AuditExporter): Promise<void>;
|
|
93
|
+
}
|
|
36
94
|
//# sourceMappingURL=chain.d.ts.map
|
package/dist/chain.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAGvD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG7E,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAW;IAE/B,OAAO;WAcM,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAa9D,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC;IAStC,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC;IASzC,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,YAAY,IAAI,MAAM,EAAE,CAE3B;IACD,WAAW,IAAI,UAAU,EAAE;IAG3B,WAAW,IAAI,aAAa;IAO5B,QAAQ,IAAI,UAAU;CAazB;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,QAAQ;IACjB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAW;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAgB;IAE1C,OAAO;WAkBM,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;IAqC9D;;;;;;OAMG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC;IAY7D;;;OAGG;IACH,kBAAkB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,kBAAkB;IAQ/D,WAAW,IAAI,UAAU,EAAE;IAI3B,QAAQ,IAAI,UAAU;IActB;;;OAGG;IACG,KAAK,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAGvD"}
|