@datacules/agent-identity 0.2.1
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/cjs/approval.js +157 -0
- package/dist/cjs/approval.js.map +1 -0
- package/dist/cjs/attestation.js +89 -0
- package/dist/cjs/attestation.js.map +1 -0
- package/dist/cjs/budget.js +110 -0
- package/dist/cjs/budget.js.map +1 -0
- package/dist/cjs/credentials.js +14 -0
- package/dist/cjs/credentials.js.map +1 -0
- package/dist/cjs/decision.js +30 -0
- package/dist/cjs/decision.js.map +1 -0
- package/dist/cjs/federation.js +55 -0
- package/dist/cjs/federation.js.map +1 -0
- package/dist/cjs/index.js +42 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/providers.js +97 -0
- package/dist/cjs/providers.js.map +1 -0
- package/dist/cjs/rotation.js +127 -0
- package/dist/cjs/rotation.js.map +1 -0
- package/dist/cjs/router.js +216 -0
- package/dist/cjs/router.js.map +1 -0
- package/dist/cjs/schemas.js +127 -0
- package/dist/cjs/schemas.js.map +1 -0
- package/dist/cjs/types.js +4 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/approval.js +150 -0
- package/dist/esm/approval.js.map +1 -0
- package/dist/esm/attestation.js +83 -0
- package/dist/esm/attestation.js.map +1 -0
- package/dist/esm/budget.js +105 -0
- package/dist/esm/budget.js.map +1 -0
- package/dist/esm/credentials.js +11 -0
- package/dist/esm/credentials.js.map +1 -0
- package/dist/esm/decision.js +27 -0
- package/dist/esm/decision.js.map +1 -0
- package/dist/esm/federation.js +50 -0
- package/dist/esm/federation.js.map +1 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/providers.js +92 -0
- package/dist/esm/providers.js.map +1 -0
- package/dist/esm/react/index.js +2 -0
- package/dist/esm/react/index.js.map +1 -0
- package/dist/esm/react/useAgentIdentity.js +100 -0
- package/dist/esm/react/useAgentIdentity.js.map +1 -0
- package/dist/esm/rotation.js +123 -0
- package/dist/esm/rotation.js.map +1 -0
- package/dist/esm/router.js +208 -0
- package/dist/esm/router.js.map +1 -0
- package/dist/esm/schemas.js +124 -0
- package/dist/esm/schemas.js.map +1 -0
- package/dist/esm/types.js +3 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/approval.d.ts +48 -0
- package/dist/types/approval.d.ts.map +1 -0
- package/dist/types/attestation.d.ts +36 -0
- package/dist/types/attestation.d.ts.map +1 -0
- package/dist/types/budget.d.ts +38 -0
- package/dist/types/budget.d.ts.map +1 -0
- package/dist/types/credentials.d.ts +4 -0
- package/dist/types/credentials.d.ts.map +1 -0
- package/dist/types/decision.d.ts +3 -0
- package/dist/types/decision.d.ts.map +1 -0
- package/dist/types/federation.d.ts +23 -0
- package/dist/types/federation.d.ts.map +1 -0
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/providers.d.ts +13 -0
- package/dist/types/providers.d.ts.map +1 -0
- package/dist/types/react/index.d.ts +3 -0
- package/dist/types/react/index.d.ts.map +1 -0
- package/dist/types/react/useAgentIdentity.d.ts +58 -0
- package/dist/types/react/useAgentIdentity.d.ts.map +1 -0
- package/dist/types/rotation.d.ts +51 -0
- package/dist/types/rotation.d.ts.map +1 -0
- package/dist/types/router.d.ts +48 -0
- package/dist/types/router.d.ts.map +1 -0
- package/dist/types/schemas.d.ts +434 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/types.d.ts +263 -0
- package/dist/types/types.d.ts.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAgentIdentity — production-safe React hook.
|
|
3
|
+
*
|
|
4
|
+
* Exported from @datacules/agent-identity/react.
|
|
5
|
+
*
|
|
6
|
+
* Unlike useCredentials (demo-only), this hook calls POST /api/resolve
|
|
7
|
+
* server-side. The raw credential never touches the browser.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Full loading / error / expiresAt lifecycle
|
|
11
|
+
* - Auto-refresh 60s before credential expiry
|
|
12
|
+
* - Configurable endpoint (works with custom Next.js routes or the Docker sidecar)
|
|
13
|
+
* - onError callback for integration with error boundaries / toast systems
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* import { useAgentIdentity } from '@datacules/agent-identity/react';
|
|
17
|
+
*
|
|
18
|
+
* function AiComposer({ userId }: { userId: string }) {
|
|
19
|
+
* const ctx = {
|
|
20
|
+
* userId,
|
|
21
|
+
* resourceId: 'knowledge-base',
|
|
22
|
+
* resourceKind: 'personal' as const,
|
|
23
|
+
* provider: 'anthropic' as const,
|
|
24
|
+
* model: 'claude-sonnet-4-20250514',
|
|
25
|
+
* action: 'read',
|
|
26
|
+
* traceId: crypto.randomUUID(),
|
|
27
|
+
* requestedAt: new Date().toISOString(),
|
|
28
|
+
* };
|
|
29
|
+
* const { resolvedFor, loading, error, expiresAt } = useAgentIdentity(ctx);
|
|
30
|
+
*
|
|
31
|
+
* if (loading) return <p>Resolving credentials…</p>;
|
|
32
|
+
* if (error) return <p>Auth error: {error.message}</p>;
|
|
33
|
+
* return <div>Ready — acting as {resolvedFor}</div>;
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
'use client'; // Next.js App Router compatibility
|
|
37
|
+
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
38
|
+
export function useAgentIdentity(ctx, options = {}) {
|
|
39
|
+
const { resolveEndpoint = '/api/resolve', refreshBeforeExpirySeconds = 60, onError, disableAutoRefresh = false, } = options;
|
|
40
|
+
const [state, setState] = useState({
|
|
41
|
+
resolvedFor: null,
|
|
42
|
+
expiresAt: null,
|
|
43
|
+
loading: false,
|
|
44
|
+
error: null,
|
|
45
|
+
});
|
|
46
|
+
const refreshTimerRef = useRef(null);
|
|
47
|
+
const clearRefreshTimer = () => {
|
|
48
|
+
if (refreshTimerRef.current !== null) {
|
|
49
|
+
clearTimeout(refreshTimerRef.current);
|
|
50
|
+
refreshTimerRef.current = null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const resolve = useCallback(async (context) => {
|
|
54
|
+
clearRefreshTimer();
|
|
55
|
+
setState((s) => ({ ...s, loading: true, error: null }));
|
|
56
|
+
try {
|
|
57
|
+
const res = await fetch(resolveEndpoint, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'Content-Type': 'application/json' },
|
|
60
|
+
body: JSON.stringify(context),
|
|
61
|
+
});
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
const body = await res.json().catch(() => ({}));
|
|
64
|
+
throw new Error(body.error ?? `HTTP ${res.status}`);
|
|
65
|
+
}
|
|
66
|
+
const data = await res.json();
|
|
67
|
+
setState({
|
|
68
|
+
resolvedFor: data.resolvedFor,
|
|
69
|
+
expiresAt: data.expiresAt ?? null,
|
|
70
|
+
loading: false,
|
|
71
|
+
error: null,
|
|
72
|
+
});
|
|
73
|
+
// Schedule auto-refresh before credential expires
|
|
74
|
+
if (!disableAutoRefresh && data.expiresAt) {
|
|
75
|
+
const msUntilRefresh = new Date(data.expiresAt).getTime() - Date.now() - refreshBeforeExpirySeconds * 1000;
|
|
76
|
+
if (msUntilRefresh > 0) {
|
|
77
|
+
refreshTimerRef.current = setTimeout(() => resolve(context), msUntilRefresh);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
83
|
+
setState((s) => ({ ...s, loading: false, error: e }));
|
|
84
|
+
onError?.(e);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
88
|
+
[resolveEndpoint, refreshBeforeExpirySeconds, disableAutoRefresh, onError]);
|
|
89
|
+
// Auto-resolve whenever ctx changes
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (!ctx)
|
|
92
|
+
return;
|
|
93
|
+
void resolve(ctx);
|
|
94
|
+
return clearRefreshTimer;
|
|
95
|
+
// ctx is intentionally compared by reference; callers should memoize it
|
|
96
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
97
|
+
}, [ctx]);
|
|
98
|
+
return { ...state, resolve };
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=useAgentIdentity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAgentIdentity.js","sourceRoot":"","sources":["../../../src/react/useAgentIdentity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// ─── CredentialRotationScheduler ─────────────────────────────────────────────
|
|
2
|
+
export class CredentialRotationScheduler {
|
|
3
|
+
constructor(repository, auditLogger) {
|
|
4
|
+
this.repository = repository;
|
|
5
|
+
this.auditLogger = auditLogger;
|
|
6
|
+
this.providers = new Map();
|
|
7
|
+
this.intervalHandle = null;
|
|
8
|
+
}
|
|
9
|
+
registerProvider(provider) {
|
|
10
|
+
this.providers.set(provider.id, provider);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check all active credentials for pending rotation and rotate them.
|
|
14
|
+
* Call this on a schedule (e.g. every hour via cron or setInterval).
|
|
15
|
+
*/
|
|
16
|
+
async runOnce() {
|
|
17
|
+
const credentials = await this.repository.listActive();
|
|
18
|
+
const now = new Date();
|
|
19
|
+
for (const cred of credentials) {
|
|
20
|
+
if (!cred.rotation)
|
|
21
|
+
continue;
|
|
22
|
+
const due = this.isRotationDue(cred, cred.rotation, now);
|
|
23
|
+
if (!due) {
|
|
24
|
+
await this.maybeEmitWarning(cred, cred.rotation, now);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const provider = cred.rotation.provisioner
|
|
28
|
+
? this.providers.get(cred.rotation.provisioner)
|
|
29
|
+
: null;
|
|
30
|
+
if (!provider) {
|
|
31
|
+
console.warn(`[RotationScheduler] No provider for credential ${cred.id} (provisioner: ${cred.rotation.provisioner ?? 'unset'})`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const { newRef, rotatedAt } = await provider.rotate(cred);
|
|
36
|
+
await this.repository.update(cred.id, { ref: newRef, lastRotated: rotatedAt });
|
|
37
|
+
if (this.auditLogger) {
|
|
38
|
+
await this.auditLogger.log({
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
traceId: `rotation-${cred.id}`,
|
|
41
|
+
userId: 'system',
|
|
42
|
+
action: 'credential.rotated',
|
|
43
|
+
resourceId: cred.id,
|
|
44
|
+
resourceKind: 'shared',
|
|
45
|
+
provider: 'local',
|
|
46
|
+
model: 'system',
|
|
47
|
+
credentialId: cred.id,
|
|
48
|
+
credentialKind: cred.kind,
|
|
49
|
+
resolvedFor: 'system',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`[RotationScheduler] Rotation failed for ${cred.id}:`, err);
|
|
55
|
+
if (this.auditLogger) {
|
|
56
|
+
await this.auditLogger.log({
|
|
57
|
+
timestamp: new Date().toISOString(),
|
|
58
|
+
traceId: `rotation-${cred.id}`,
|
|
59
|
+
userId: 'system',
|
|
60
|
+
action: 'credential.rotation_failed',
|
|
61
|
+
resourceId: cred.id,
|
|
62
|
+
resourceKind: 'shared',
|
|
63
|
+
provider: 'local',
|
|
64
|
+
model: 'system',
|
|
65
|
+
credentialId: cred.id,
|
|
66
|
+
credentialKind: cred.kind,
|
|
67
|
+
resolvedFor: 'system',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Start a background rotation loop at the given interval.
|
|
75
|
+
* @param intervalMs Check frequency in milliseconds (default: 3600000 = 1 hour)
|
|
76
|
+
*/
|
|
77
|
+
start(intervalMs = 3600000) {
|
|
78
|
+
if (this.intervalHandle !== null)
|
|
79
|
+
return;
|
|
80
|
+
this.intervalHandle = setInterval(() => {
|
|
81
|
+
this.runOnce().catch(console.error);
|
|
82
|
+
}, intervalMs);
|
|
83
|
+
}
|
|
84
|
+
stop() {
|
|
85
|
+
if (this.intervalHandle !== null) {
|
|
86
|
+
clearInterval(this.intervalHandle);
|
|
87
|
+
this.intervalHandle = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
isRotationDue(cred, policy, now) {
|
|
91
|
+
if (policy.rotateAfterDays !== undefined && cred.lastRotated) {
|
|
92
|
+
const lastRotated = new Date(cred.lastRotated);
|
|
93
|
+
const daysSince = (now.getTime() - lastRotated.getTime()) / 86400000;
|
|
94
|
+
if (daysSince >= policy.rotateAfterDays)
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
async maybeEmitWarning(cred, policy, now) {
|
|
100
|
+
if (!this.auditLogger)
|
|
101
|
+
return;
|
|
102
|
+
if (policy.notifyBeforeDays !== undefined && policy.rotateAfterDays !== undefined && cred.lastRotated) {
|
|
103
|
+
const lastRotated = new Date(cred.lastRotated);
|
|
104
|
+
const daysUntilDue = policy.rotateAfterDays - (now.getTime() - lastRotated.getTime()) / 86400000;
|
|
105
|
+
if (daysUntilDue > 0 && daysUntilDue <= policy.notifyBeforeDays) {
|
|
106
|
+
await this.auditLogger.log({
|
|
107
|
+
timestamp: new Date().toISOString(),
|
|
108
|
+
traceId: `rotation-warning-${cred.id}`,
|
|
109
|
+
userId: 'system',
|
|
110
|
+
action: 'credential.rotation_due',
|
|
111
|
+
resourceId: cred.id,
|
|
112
|
+
resourceKind: 'shared',
|
|
113
|
+
provider: 'local',
|
|
114
|
+
model: 'system',
|
|
115
|
+
credentialId: cred.id,
|
|
116
|
+
credentialKind: cred.kind,
|
|
117
|
+
resolvedFor: 'system',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation.js","sourceRoot":"","sources":["../../src/rotation.ts"],"names":[],"mappings":"AA+BA,gFAAgF;AAEhF,MAAM,OAAO,2BAA2B;IAItC,YACmB,UAA8B,EAC9B,WAAyB;QADzB,eAAU,GAAV,UAAU,CAAoB;QAC9B,gBAAW,GAAX,WAAW,CAAc;QAL3B,cAAS,GAAG,IAAI,GAAG,EAA4B,CAAC;QACzD,mBAAc,GAA0C,IAAI,CAAC;IAKlE,CAAC;IAEJ,gBAAgB,CAAC,QAA0B;QACzC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAEvB,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACzD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBACtD,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW;gBACxC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAC/C,CAAC,CAAC,IAAI,CAAC;YAET,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,kDAAkD,IAAI,CAAC,EAAE,kBAAkB,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,OAAO,GAAG,CAAC,CAAC;gBACjI,SAAS;YACX,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC1D,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;gBAE/E,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;wBACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACnC,OAAO,EAAE,YAAY,IAAI,CAAC,EAAE,EAAE;wBAC9B,MAAM,EAAE,QAAQ;wBAChB,MAAM,EAAE,oBAAoB;wBAC5B,UAAU,EAAE,IAAI,CAAC,EAAE;wBACnB,YAAY,EAAE,QAAQ;wBACtB,QAAQ,EAAE,OAAO;wBACjB,KAAK,EAAE,QAAQ;wBACf,YAAY,EAAE,IAAI,CAAC,EAAE;wBACrB,cAAc,EAAE,IAAI,CAAC,IAAI;wBACzB,WAAW,EAAE,QAAQ;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,2CAA2C,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC1E,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;wBACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACnC,OAAO,EAAE,YAAY,IAAI,CAAC,EAAE,EAAE;wBAC9B,MAAM,EAAE,QAAQ;wBAChB,MAAM,EAAE,4BAA4B;wBACpC,UAAU,EAAE,IAAI,CAAC,EAAE;wBACnB,YAAY,EAAE,QAAQ;wBACtB,QAAQ,EAAE,OAAO;wBACjB,KAAK,EAAE,QAAQ;wBACf,YAAY,EAAE,IAAI,CAAC,EAAE;wBACrB,cAAc,EAAE,IAAI,CAAC,IAAI;wBACzB,WAAW,EAAE,QAAQ;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,GAAG,OAAS;QAC1B,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI;YAAE,OAAO;QACzC,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACrC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACjC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACnC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,IAAgB,EAAE,MAAsB,EAAE,GAAS;QACvE,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7D,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/C,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,QAAU,CAAC;YACvE,IAAI,SAAS,IAAI,MAAM,CAAC,eAAe;gBAAE,OAAO,IAAI,CAAC;QACvD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,IAAgB,EAAE,MAAsB,EAAE,GAAS;QAChF,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO;QAC9B,IAAI,MAAM,CAAC,gBAAgB,KAAK,SAAS,IAAI,MAAM,CAAC,eAAe,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACtG,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/C,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,QAAU,CAAC;YACnG,IAAI,YAAY,GAAG,CAAC,IAAI,YAAY,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAChE,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;oBACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,OAAO,EAAE,oBAAoB,IAAI,CAAC,EAAE,EAAE;oBACtC,MAAM,EAAE,QAAQ;oBAChB,MAAM,EAAE,yBAAyB;oBACjC,UAAU,EAAE,IAAI,CAAC,EAAE;oBACnB,YAAY,EAAE,QAAQ;oBACtB,QAAQ,EAAE,OAAO;oBACjB,KAAK,EAAE,QAAQ;oBACf,YAAY,EAAE,IAAI,CAAC,EAAE;oBACrB,cAAc,EAAE,IAAI,CAAC,IAAI;oBACzB,WAAW,EAAE,QAAQ;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential Router — core of @datacules/agent-identity.
|
|
3
|
+
*
|
|
4
|
+
* Key features added in this version:
|
|
5
|
+
* - Canary routing: canaryRef + canaryWeight on RoutingRule
|
|
6
|
+
* - Attestation: optional AttestationSigner on router config
|
|
7
|
+
* - Budget enforcement: BudgetEnforcer check before resolving
|
|
8
|
+
* - Approval gate: ApprovalManager integration on rules with approval policy
|
|
9
|
+
*/
|
|
10
|
+
import { buildAttestation } from './attestation';
|
|
11
|
+
function isSyncCapable(store) {
|
|
12
|
+
return typeof store.findByRefSync === 'function';
|
|
13
|
+
}
|
|
14
|
+
export class MemoryCredentialStore {
|
|
15
|
+
constructor(credentials) {
|
|
16
|
+
this.reservations = new Map();
|
|
17
|
+
this.creds = credentials;
|
|
18
|
+
}
|
|
19
|
+
findByRefSync(ref) {
|
|
20
|
+
return this.creds.find((c) => c.ref === ref && c.status === 'active') ?? null;
|
|
21
|
+
}
|
|
22
|
+
async findByRef(ref) {
|
|
23
|
+
return this.findByRefSync(ref);
|
|
24
|
+
}
|
|
25
|
+
async listActive() {
|
|
26
|
+
return this.creds.filter((c) => c.status === 'active');
|
|
27
|
+
}
|
|
28
|
+
async listByKind(kind) {
|
|
29
|
+
return this.creds.filter((c) => c.kind === kind);
|
|
30
|
+
}
|
|
31
|
+
async reserve(ref, migrationId, ttlSeconds) {
|
|
32
|
+
const existing = this.reservations.get(ref);
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
if (existing && existing.migrationId !== migrationId && existing.expiresAt > now)
|
|
35
|
+
return false;
|
|
36
|
+
this.reservations.set(ref, { migrationId, expiresAt: now + ttlSeconds * 1000 });
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
async release(ref, migrationId) {
|
|
40
|
+
const existing = this.reservations.get(ref);
|
|
41
|
+
if (existing?.migrationId === migrationId)
|
|
42
|
+
this.reservations.delete(ref);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export class CredentialRouter {
|
|
46
|
+
constructor(config) {
|
|
47
|
+
this.config = config;
|
|
48
|
+
}
|
|
49
|
+
// ─── Sync resolve (requires SyncCapable store) ────────────────────────────
|
|
50
|
+
resolve(ctx) {
|
|
51
|
+
const { store, rules } = this.config;
|
|
52
|
+
const matching = rules
|
|
53
|
+
.filter((r) => this.ruleMatches(r, ctx))
|
|
54
|
+
.sort((a, b) => b.priority - a.priority);
|
|
55
|
+
const rule = matching[0];
|
|
56
|
+
if (!rule)
|
|
57
|
+
return null;
|
|
58
|
+
if (!isSyncCapable(store)) {
|
|
59
|
+
console.warn('[CredentialRouter] resolve() requires findByRefSync(). Use resolveAsync() for async stores.');
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
// Canary selection
|
|
63
|
+
const ref = this.selectRef(rule);
|
|
64
|
+
const isCanary = ref === rule.canaryRef;
|
|
65
|
+
const cred = store.findByRefSync(ref);
|
|
66
|
+
if (!cred)
|
|
67
|
+
return null;
|
|
68
|
+
if (cred.expiresAt && new Date(cred.expiresAt) < new Date())
|
|
69
|
+
return null;
|
|
70
|
+
if (rule.readOnly && !cred.scope.toLowerCase().includes('read'))
|
|
71
|
+
return null;
|
|
72
|
+
const resolved = {
|
|
73
|
+
credentialId: cred.id,
|
|
74
|
+
kind: cred.kind,
|
|
75
|
+
ref: cred.ref,
|
|
76
|
+
resolvedFor: cred.kind === 'user-delegated' ? ctx.userId : 'service',
|
|
77
|
+
expiresAt: cred.expiresAt,
|
|
78
|
+
isCanary,
|
|
79
|
+
};
|
|
80
|
+
if (this.config.logger) {
|
|
81
|
+
this.config.logger.log(this.buildAuditEntry(ctx, resolved, rule, isCanary)).catch(console.error);
|
|
82
|
+
}
|
|
83
|
+
return resolved;
|
|
84
|
+
}
|
|
85
|
+
// ─── Async resolve (all stores; supports approval + budget + attestation) ─
|
|
86
|
+
async resolveAsync(ctx) {
|
|
87
|
+
const { store, rules, approvalManager, budgetEnforcer, attestationSigner } = this.config;
|
|
88
|
+
const matching = rules
|
|
89
|
+
.filter((r) => this.ruleMatches(r, ctx))
|
|
90
|
+
.sort((a, b) => b.priority - a.priority);
|
|
91
|
+
const rule = matching[0];
|
|
92
|
+
if (!rule)
|
|
93
|
+
return null;
|
|
94
|
+
// Approval gate
|
|
95
|
+
if (rule.approval && approvalManager) {
|
|
96
|
+
const status = await approvalManager.request(ctx, rule.approval, rule.credentialRef, rule.id);
|
|
97
|
+
if (status !== 'approved' && status !== 'break_glass')
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const ref = this.selectRef(rule);
|
|
101
|
+
const isCanary = ref === rule.canaryRef;
|
|
102
|
+
const cred = await store.findByRef(ref);
|
|
103
|
+
if (!cred)
|
|
104
|
+
return null;
|
|
105
|
+
if (cred.expiresAt && new Date(cred.expiresAt) < new Date())
|
|
106
|
+
return null;
|
|
107
|
+
if (rule.readOnly && !cred.scope.toLowerCase().includes('read'))
|
|
108
|
+
return null;
|
|
109
|
+
// Budget check
|
|
110
|
+
if (budgetEnforcer) {
|
|
111
|
+
const budget = await budgetEnforcer.check(cred);
|
|
112
|
+
if (!budget.allowed)
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
const resolved = {
|
|
116
|
+
credentialId: cred.id,
|
|
117
|
+
kind: cred.kind,
|
|
118
|
+
ref: cred.ref,
|
|
119
|
+
resolvedFor: cred.kind === 'user-delegated' ? ctx.userId : 'service',
|
|
120
|
+
expiresAt: cred.expiresAt,
|
|
121
|
+
isCanary,
|
|
122
|
+
};
|
|
123
|
+
// Attestation
|
|
124
|
+
if (attestationSigner) {
|
|
125
|
+
resolved.credentialAttestation = await buildAttestation(ctx, resolved, {
|
|
126
|
+
signer: attestationSigner,
|
|
127
|
+
ruleId: rule.id,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (this.config.logger) {
|
|
131
|
+
await this.config.logger.log(this.buildAuditEntry(ctx, resolved, rule, isCanary));
|
|
132
|
+
}
|
|
133
|
+
return resolved;
|
|
134
|
+
}
|
|
135
|
+
// ─── Pair resolve for migration ───────────────────────────────────────────
|
|
136
|
+
resolvePair(ctx) {
|
|
137
|
+
const sourceCtx = { ...ctx, resourceId: ctx.sourceResourceId, action: 'read' };
|
|
138
|
+
const targetCtx = { ...ctx, resourceId: ctx.targetResourceId, action: ctx.dryRun ? 'read' : ctx.action };
|
|
139
|
+
const source = this.resolve(sourceCtx);
|
|
140
|
+
const target = this.resolve(targetCtx);
|
|
141
|
+
if (!source || !target)
|
|
142
|
+
return null;
|
|
143
|
+
return { source, target, migrationId: ctx.migrationId };
|
|
144
|
+
}
|
|
145
|
+
// ─── Canary selection ─────────────────────────────────────────────────────
|
|
146
|
+
selectRef(rule) {
|
|
147
|
+
if (rule.canaryRef && rule.canaryWeight && rule.canaryWeight > 0) {
|
|
148
|
+
const roll = Math.random() * 100;
|
|
149
|
+
if (roll < rule.canaryWeight)
|
|
150
|
+
return rule.canaryRef;
|
|
151
|
+
}
|
|
152
|
+
return rule.credentialRef;
|
|
153
|
+
}
|
|
154
|
+
// ─── Rule matching ────────────────────────────────────────────────────────
|
|
155
|
+
ruleMatches(rule, ctx) {
|
|
156
|
+
if (rule.matchResourceKind && rule.matchResourceKind !== ctx.resourceKind)
|
|
157
|
+
return false;
|
|
158
|
+
if (rule.matchProvider && rule.matchProvider !== ctx.provider)
|
|
159
|
+
return false;
|
|
160
|
+
if (rule.matchUserId && rule.matchUserId !== ctx.userId)
|
|
161
|
+
return false;
|
|
162
|
+
if (rule.matchSpiffeId && ctx.spiffeId !== rule.matchSpiffeId)
|
|
163
|
+
return false;
|
|
164
|
+
if (rule.matchAction) {
|
|
165
|
+
const actions = Array.isArray(rule.matchAction) ? rule.matchAction : [rule.matchAction];
|
|
166
|
+
if (!actions.includes(ctx.action))
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
if (rule.matchPhase) {
|
|
170
|
+
const migCtx = ctx;
|
|
171
|
+
if (!migCtx.phase)
|
|
172
|
+
return false;
|
|
173
|
+
const phases = Array.isArray(rule.matchPhase) ? rule.matchPhase : [rule.matchPhase];
|
|
174
|
+
if (!phases.includes(migCtx.phase))
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
// ─── Audit entry builder ─────────────────────────────────────────────────
|
|
180
|
+
buildAuditEntry(ctx, resolved, rule, isCanary) {
|
|
181
|
+
return {
|
|
182
|
+
timestamp: new Date().toISOString(),
|
|
183
|
+
traceId: ctx.traceId,
|
|
184
|
+
userId: ctx.userId,
|
|
185
|
+
action: ctx.action,
|
|
186
|
+
resourceId: ctx.resourceId,
|
|
187
|
+
resourceKind: ctx.resourceKind,
|
|
188
|
+
provider: ctx.provider,
|
|
189
|
+
model: ctx.model,
|
|
190
|
+
credentialId: resolved.credentialId,
|
|
191
|
+
credentialKind: resolved.kind,
|
|
192
|
+
resolvedFor: resolved.resolvedFor,
|
|
193
|
+
isCanary,
|
|
194
|
+
spiffeId: ctx.spiffeId,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// ─── Factory functions ────────────────────────────────────────────────────────
|
|
199
|
+
export function createRouter(credentials, rules, logger) {
|
|
200
|
+
return new CredentialRouter({ store: new MemoryCredentialStore(credentials), rules, logger });
|
|
201
|
+
}
|
|
202
|
+
export function createRouterFromStore(store, rules, logger) {
|
|
203
|
+
return new CredentialRouter({ store, rules, logger });
|
|
204
|
+
}
|
|
205
|
+
export function createRouterWithConfig(config) {
|
|
206
|
+
return new CredentialRouter(config);
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @datacules/agent-identity/schemas
|
|
3
|
+
*
|
|
4
|
+
* Zod schemas mirroring every public type. Three uses simultaneously:
|
|
5
|
+
* 1. Runtime validation in route handlers (replaces manual field loops)
|
|
6
|
+
* 2. TypeScript type inference via z.infer<>
|
|
7
|
+
* 3. JSON Schema / OpenAPI generation via zod-to-json-schema
|
|
8
|
+
*
|
|
9
|
+
* Since zod is already in dependencies, this costs nothing to ship.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
// ─── Primitives ───────────────────────────────────────────────────────────────
|
|
13
|
+
export const SupportedProviderSchema = z.enum([
|
|
14
|
+
'openai',
|
|
15
|
+
'anthropic',
|
|
16
|
+
'gemini',
|
|
17
|
+
'mistral',
|
|
18
|
+
'local',
|
|
19
|
+
]);
|
|
20
|
+
export const ResourceKindSchema = z.enum(['shared', 'personal']);
|
|
21
|
+
export const CredentialKindSchema = z.enum(['fixed', 'user-delegated']);
|
|
22
|
+
export const CredentialStatusSchema = z.enum(['active', 'pending', 'revoked']);
|
|
23
|
+
export const MigrationPhaseSchema = z.enum([
|
|
24
|
+
'dry-run',
|
|
25
|
+
'extract',
|
|
26
|
+
'transform',
|
|
27
|
+
'load',
|
|
28
|
+
'verify',
|
|
29
|
+
'rollback',
|
|
30
|
+
]);
|
|
31
|
+
export const ApproverKindSchema = z.enum(['webhook', 'email', 'slack']);
|
|
32
|
+
// ─── Rotation Policy ─────────────────────────────────────────────────────────
|
|
33
|
+
export const RotationPolicySchema = z.object({
|
|
34
|
+
rotateAfterDays: z.number().int().positive().optional(),
|
|
35
|
+
rotateAfterUses: z.number().int().positive().optional(),
|
|
36
|
+
gracePeriodSeconds: z.number().int().nonnegative().optional(),
|
|
37
|
+
notifyBeforeDays: z.number().int().positive().optional(),
|
|
38
|
+
provisioner: z.string().optional(),
|
|
39
|
+
});
|
|
40
|
+
// ─── Budget Policy ────────────────────────────────────────────────────────────
|
|
41
|
+
export const BudgetPolicySchema = z.object({
|
|
42
|
+
maxResolutionsPerHour: z.number().int().positive().optional(),
|
|
43
|
+
maxConcurrentSessions: z.number().int().positive().optional(),
|
|
44
|
+
maxDailySpendUsd: z.number().positive().optional(),
|
|
45
|
+
softThresholdPercent: z.number().min(0).max(100).optional(),
|
|
46
|
+
resetSchedule: z.string().optional(),
|
|
47
|
+
});
|
|
48
|
+
// ─── Approval Policy ─────────────────────────────────────────────────────────
|
|
49
|
+
export const ApproverSchema = z.object({
|
|
50
|
+
kind: ApproverKindSchema,
|
|
51
|
+
target: z.string().min(1),
|
|
52
|
+
});
|
|
53
|
+
export const ApprovalPolicySchema = z.object({
|
|
54
|
+
requiredApprovers: z.number().int().positive(),
|
|
55
|
+
approvers: z.array(ApproverSchema),
|
|
56
|
+
timeoutSeconds: z.number().int().positive().optional(),
|
|
57
|
+
breakGlass: z
|
|
58
|
+
.object({
|
|
59
|
+
approver: z.string().min(1),
|
|
60
|
+
requireJustification: z.boolean().optional(),
|
|
61
|
+
})
|
|
62
|
+
.optional(),
|
|
63
|
+
});
|
|
64
|
+
// ─── Credential ─────────────────────────────────────────────────────────────
|
|
65
|
+
export const CredentialSchema = z.object({
|
|
66
|
+
id: z.string().min(1),
|
|
67
|
+
kind: CredentialKindSchema,
|
|
68
|
+
name: z.string().min(1),
|
|
69
|
+
scope: z.string(),
|
|
70
|
+
status: CredentialStatusSchema,
|
|
71
|
+
provider: z.string().optional(),
|
|
72
|
+
ref: z.string().min(1),
|
|
73
|
+
expiresAt: z.string().datetime().optional(),
|
|
74
|
+
lastRotated: z.string().datetime().optional(),
|
|
75
|
+
refreshTokenRef: z.string().optional(),
|
|
76
|
+
rotationIntervalDays: z.number().int().nonnegative().optional(),
|
|
77
|
+
rotation: RotationPolicySchema.optional(),
|
|
78
|
+
budget: BudgetPolicySchema.optional(),
|
|
79
|
+
tags: z.array(z.string()).optional(),
|
|
80
|
+
});
|
|
81
|
+
// ─── Routing Rule ──────────────────────────────────────────────────────────
|
|
82
|
+
export const RoutingRuleSchema = z.object({
|
|
83
|
+
id: z.string().min(1),
|
|
84
|
+
description: z.string(),
|
|
85
|
+
credentialRef: z.string().min(1),
|
|
86
|
+
credentialKind: CredentialKindSchema,
|
|
87
|
+
priority: z.number().int(),
|
|
88
|
+
matchResourceKind: ResourceKindSchema.optional(),
|
|
89
|
+
matchAction: z.union([z.string(), z.array(z.string())]).optional(),
|
|
90
|
+
matchProvider: SupportedProviderSchema.optional(),
|
|
91
|
+
matchUserId: z.string().optional(),
|
|
92
|
+
matchPhase: z
|
|
93
|
+
.union([MigrationPhaseSchema, z.array(MigrationPhaseSchema)])
|
|
94
|
+
.optional(),
|
|
95
|
+
matchSpiffeId: z.string().optional(),
|
|
96
|
+
readOnly: z.boolean().optional(),
|
|
97
|
+
canaryRef: z.string().optional(),
|
|
98
|
+
canaryWeight: z.number().int().min(0).max(100).optional(),
|
|
99
|
+
approval: ApprovalPolicySchema.optional(),
|
|
100
|
+
});
|
|
101
|
+
// ─── Agent Request Context ───────────────────────────────────────────────
|
|
102
|
+
export const AgentRequestContextSchema = z.object({
|
|
103
|
+
userId: z.string().min(1),
|
|
104
|
+
resourceId: z.string().min(1),
|
|
105
|
+
resourceKind: ResourceKindSchema,
|
|
106
|
+
provider: SupportedProviderSchema,
|
|
107
|
+
model: z.string().min(1),
|
|
108
|
+
action: z.string().min(1),
|
|
109
|
+
traceId: z.string().min(1),
|
|
110
|
+
sessionId: z.string().optional(),
|
|
111
|
+
requestedAt: z.string().datetime(),
|
|
112
|
+
parentTraceId: z.string().optional(),
|
|
113
|
+
spiffeId: z.string().optional(),
|
|
114
|
+
});
|
|
115
|
+
export const MigrationContextSchema = AgentRequestContextSchema.extend({
|
|
116
|
+
migrationId: z.string().min(1),
|
|
117
|
+
phase: MigrationPhaseSchema,
|
|
118
|
+
sourceResourceId: z.string().min(1),
|
|
119
|
+
targetResourceId: z.string().min(1),
|
|
120
|
+
dryRun: z.boolean(),
|
|
121
|
+
batchIndex: z.number().int().nonnegative().optional(),
|
|
122
|
+
totalBatches: z.number().int().positive().optional(),
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,iFAAiF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-Party Approval Workflows — Feature #5 from FEATURE_SUGGESTIONS.md
|
|
3
|
+
*
|
|
4
|
+
* Intercepts resolve() when a RoutingRule has an ApprovalPolicy, holds
|
|
5
|
+
* resolution pending human sign-off, and fires notifiers.
|
|
6
|
+
*/
|
|
7
|
+
import type { AgentRequestContext, ApprovalPolicy, ApprovalRequest, ApprovalStatus, AuditLogger } from './types';
|
|
8
|
+
export interface ApprovalStore {
|
|
9
|
+
create(request: ApprovalRequest): Promise<void>;
|
|
10
|
+
get(requestId: string): Promise<ApprovalRequest | null>;
|
|
11
|
+
update(requestId: string, status: ApprovalStatus, resolvedBy?: string, justification?: string): Promise<void>;
|
|
12
|
+
listPending(): Promise<ApprovalRequest[]>;
|
|
13
|
+
}
|
|
14
|
+
export interface ApprovalNotifier {
|
|
15
|
+
notify(request: ApprovalRequest, policy: ApprovalPolicy): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare class MemoryApprovalStore implements ApprovalStore {
|
|
18
|
+
private readonly store;
|
|
19
|
+
create(request: ApprovalRequest): Promise<void>;
|
|
20
|
+
get(requestId: string): Promise<ApprovalRequest | null>;
|
|
21
|
+
update(requestId: string, status: ApprovalStatus, resolvedBy?: string, justification?: string): Promise<void>;
|
|
22
|
+
listPending(): Promise<ApprovalRequest[]>;
|
|
23
|
+
}
|
|
24
|
+
export declare class WebhookApprovalNotifier implements ApprovalNotifier {
|
|
25
|
+
private readonly webhookUrl;
|
|
26
|
+
private readonly secret?;
|
|
27
|
+
constructor(webhookUrl: string, secret?: string | undefined);
|
|
28
|
+
notify(request: ApprovalRequest, _policy: ApprovalPolicy): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
export declare class SlackApprovalNotifier implements ApprovalNotifier {
|
|
31
|
+
private readonly webhookUrl;
|
|
32
|
+
constructor(webhookUrl: string);
|
|
33
|
+
notify(request: ApprovalRequest, _policy: ApprovalPolicy): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export declare class ApprovalManager {
|
|
36
|
+
private readonly store;
|
|
37
|
+
private readonly notifiers;
|
|
38
|
+
private readonly auditLogger?;
|
|
39
|
+
constructor(store: ApprovalStore, notifiers?: ApprovalNotifier[], auditLogger?: AuditLogger | undefined);
|
|
40
|
+
/**
|
|
41
|
+
* Gate a resolve() call behind an approval policy.
|
|
42
|
+
* Returns 'approved' / 'break_glass' if the request was already
|
|
43
|
+
* approved, otherwise creates a new approval request, notifies approvers,
|
|
44
|
+
* and returns 'pending' (the router returns null — caller should retry).
|
|
45
|
+
*/
|
|
46
|
+
request(ctx: AgentRequestContext, policy: ApprovalPolicy, credentialId: string, ruleId: string): Promise<ApprovalStatus>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=approval.d.ts.map
|