blun-king-cli 9.1.390 → 9.1.391
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.
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
|
|
4
4
|
|
|
5
|
-
const COGNITIVE_MEMORY_ADAPTER_VERSION =
|
|
5
|
+
const COGNITIVE_MEMORY_ADAPTER_VERSION = 6;
|
|
6
6
|
const KIND_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
7
7
|
const RETENTION_CLASSES = new Set(['operational', 'durable', 'relationship', 'audit']);
|
|
8
|
-
const
|
|
8
|
+
const ACCESS_REQUIRED_KEYS = Object.freeze([
|
|
9
9
|
'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
|
|
10
10
|
'portalId', 'requestedScope', 'tenantId', 'userId',
|
|
11
11
|
]);
|
|
12
|
-
const
|
|
12
|
+
const ACCESS_OPTIONAL_KEYS = Object.freeze(['identityLink']);
|
|
13
|
+
const PERMISSION_REQUIRED_KEYS = Object.freeze(['authority', 'decision', 'receiptId']);
|
|
14
|
+
const PERMISSION_OPTIONAL_KEYS = Object.freeze(['identityReceiptId']);
|
|
15
|
+
const IDENTITY_LINK_KEYS = Object.freeze([
|
|
16
|
+
'authority', 'canonicalUserId', 'confirmedAt', 'method', 'receiptId',
|
|
17
|
+
'sourcePortal', 'sourceSubjectId', 'status', 'tenantId', 'version',
|
|
18
|
+
]);
|
|
19
|
+
const IDENTITY_LINK_AUTHORITIES = new Map([
|
|
20
|
+
['verified_oauth', 'oauth_verifier'],
|
|
21
|
+
['secure_account_link', 'account_link_service'],
|
|
22
|
+
['explicit_confirmed', 'identity_confirmation_service'],
|
|
23
|
+
]);
|
|
13
24
|
const REQUIRED_METHODS = Object.freeze([
|
|
14
25
|
'commit',
|
|
15
26
|
'read',
|
|
@@ -31,13 +42,70 @@ function exactKeys(value, expected) {
|
|
|
31
42
|
&& Object.keys(value).sort().join('\0') === [...expected].sort().join('\0');
|
|
32
43
|
}
|
|
33
44
|
|
|
45
|
+
function requiredAndOptionalKeys(value, required, optional) {
|
|
46
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
47
|
+
const allowed = new Set([...required, ...optional]);
|
|
48
|
+
return required.every((key) => Object.prototype.hasOwnProperty.call(value, key))
|
|
49
|
+
&& Object.keys(value).every((key) => allowed.has(key));
|
|
50
|
+
}
|
|
51
|
+
|
|
34
52
|
function safeId(value) {
|
|
35
53
|
const text = String(value ?? '').trim();
|
|
36
54
|
return KIND_RE.test(text) ? text : '';
|
|
37
55
|
}
|
|
38
56
|
|
|
57
|
+
function normalizeIdentityLink(access, normalized) {
|
|
58
|
+
const link = access.identityLink;
|
|
59
|
+
const identityReceiptId = normalized.permissionContext.identityReceiptId;
|
|
60
|
+
if (normalized.userId === normalized.actorId) {
|
|
61
|
+
if (link !== undefined || identityReceiptId !== undefined) fail('COGNITIVE_IDENTITY_LINK_INVALID');
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (link === undefined || link === null) fail('COGNITIVE_IDENTITY_LINK_REQUIRED');
|
|
65
|
+
if (!exactKeys(link, IDENTITY_LINK_KEYS)) fail('COGNITIVE_IDENTITY_LINK_INVALID');
|
|
66
|
+
if (String(link.status ?? '') === 'revoked') fail('COGNITIVE_IDENTITY_LINK_REVOKED');
|
|
67
|
+
const method = String(link.method ?? '');
|
|
68
|
+
const normalizedLink = {
|
|
69
|
+
version: Number(link.version),
|
|
70
|
+
tenantId: safeId(link.tenantId),
|
|
71
|
+
canonicalUserId: safeId(link.canonicalUserId),
|
|
72
|
+
sourcePortal: safeId(link.sourcePortal),
|
|
73
|
+
sourceSubjectId: safeId(link.sourceSubjectId),
|
|
74
|
+
method,
|
|
75
|
+
status: String(link.status ?? ''),
|
|
76
|
+
confirmedAt: String(link.confirmedAt ?? '').trim(),
|
|
77
|
+
authority: safeId(link.authority),
|
|
78
|
+
receiptId: safeId(link.receiptId),
|
|
79
|
+
};
|
|
80
|
+
if (normalizedLink.version !== 1 || normalizedLink.status !== 'active'
|
|
81
|
+
|| Number.isNaN(Date.parse(normalizedLink.confirmedAt))
|
|
82
|
+
|| IDENTITY_LINK_AUTHORITIES.get(method) !== normalizedLink.authority
|
|
83
|
+
|| normalizedLink.tenantId !== normalized.tenantId
|
|
84
|
+
|| normalizedLink.canonicalUserId !== normalized.userId
|
|
85
|
+
|| normalizedLink.sourcePortal !== normalized.portalId
|
|
86
|
+
|| normalizedLink.sourceSubjectId !== normalized.actorId
|
|
87
|
+
|| !identityReceiptId || normalizedLink.receiptId !== identityReceiptId) {
|
|
88
|
+
fail('COGNITIVE_IDENTITY_LINK_INVALID');
|
|
89
|
+
}
|
|
90
|
+
const canonicalScope = `relationship:${normalized.userId}:private`;
|
|
91
|
+
const personalScope = `user:${normalized.userId}:private`;
|
|
92
|
+
if ((normalized.requestedScope.startsWith('relationship:') && normalized.requestedScope !== canonicalScope)
|
|
93
|
+
|| (normalized.requestedScope.startsWith('user:') && normalized.requestedScope !== personalScope)) {
|
|
94
|
+
fail('COGNITIVE_IDENTITY_SCOPE_MISMATCH');
|
|
95
|
+
}
|
|
96
|
+
return Object.freeze({
|
|
97
|
+
...normalizedLink,
|
|
98
|
+
confirmedAt: new Date(normalizedLink.confirmedAt).toISOString(),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
39
102
|
function normalizeMemoryAccess(access, request) {
|
|
40
|
-
if (!
|
|
103
|
+
if (!requiredAndOptionalKeys(access, ACCESS_REQUIRED_KEYS, ACCESS_OPTIONAL_KEYS)
|
|
104
|
+
|| !requiredAndOptionalKeys(
|
|
105
|
+
access.permissionContext,
|
|
106
|
+
PERMISSION_REQUIRED_KEYS,
|
|
107
|
+
PERMISSION_OPTIONAL_KEYS,
|
|
108
|
+
)) {
|
|
41
109
|
fail('COGNITIVE_MEMORY_ACCESS_INVALID');
|
|
42
110
|
}
|
|
43
111
|
const normalized = {
|
|
@@ -53,6 +121,9 @@ function normalizeMemoryAccess(access, request) {
|
|
|
53
121
|
authority: safeId(access.permissionContext.authority),
|
|
54
122
|
decision: String(access.permissionContext.decision ?? ''),
|
|
55
123
|
receiptId: safeId(access.permissionContext.receiptId),
|
|
124
|
+
...(Object.prototype.hasOwnProperty.call(access.permissionContext, 'identityReceiptId')
|
|
125
|
+
? { identityReceiptId: safeId(access.permissionContext.identityReceiptId) }
|
|
126
|
+
: {}),
|
|
56
127
|
},
|
|
57
128
|
};
|
|
58
129
|
if (!normalized.tenantId || !normalized.userId || !normalized.actorId || !normalized.agentId
|
|
@@ -66,6 +137,8 @@ function normalizeMemoryAccess(access, request) {
|
|
|
66
137
|
|| requestTenant !== normalized.tenantId || requestAgent !== normalized.agentId) {
|
|
67
138
|
fail('COGNITIVE_MEMORY_ACCESS_SCOPE_MISMATCH');
|
|
68
139
|
}
|
|
140
|
+
const identityLink = normalizeIdentityLink(access, normalized);
|
|
141
|
+
if (identityLink) normalized.identityLink = identityLink;
|
|
69
142
|
normalized.permissionContext = Object.freeze(normalized.permissionContext);
|
|
70
143
|
return Object.freeze(normalized);
|
|
71
144
|
}
|
|
@@ -473,7 +473,7 @@ function createCognitiveTurnLifecycle({
|
|
|
473
473
|
const authorization = input?.authorization;
|
|
474
474
|
const memoryAccess = {
|
|
475
475
|
tenantId: tenant,
|
|
476
|
-
userId:
|
|
476
|
+
userId: agent,
|
|
477
477
|
actorId: agent,
|
|
478
478
|
agentId: agent,
|
|
479
479
|
portalId: 'cli',
|