rhf-b-kn1-delegation-retail.test.mjs
681 lines 24.8 KB
Raw
sha256:fbe982a22c05c6fe2e93876f250deecdb43d883f648b4e1810c7546caa9f17db docs: activate KNOWTATION- board identity and preserve livi… Human minor ⚠ breaking 2 days ago
1 /**
2 * RHF-b-KN1 — DelegationAuthorityStore retail routes (seven-tier).
3 *
4 * Frozen spec: ~/scooling/docs/reviews/2026-08-27-retail-helper-finish.md §B2–B7
5 */
6
7 import { test, describe } from 'node:test';
8 import assert from 'node:assert/strict';
9 import fs from 'node:fs';
10 import os from 'node:os';
11 import path from 'node:path';
12 import { performance } from 'node:perf_hooks';
13 import { fileURLToPath } from 'node:url';
14 import { createHash, randomBytes } from 'node:crypto';
15
16 import {
17 DELEGATION_CONSENT_SCHEMA,
18 hashPrincipalRef,
19 hashGrantBearer,
20 } from '../lib/agent/delegation.mjs';
21 import {
22 MemoryCasBlobStore,
23 createDelegationAuthorityStore,
24 seedActiveAuthorityEnvelope,
25 isConsentActiveStrict,
26 isGrantActiveStrict,
27 isStrictUtcTimestamp,
28 selectActivePersonalConsent,
29 buildAuthoritySubjects,
30 sealEnvelopeStateHash,
31 validateEnvelopeInternalIntegrity,
32 pruneAuthorityEnvelope,
33 principalActorKey,
34 authorityBlobGetOpts,
35 RETAIL_ACTOR_ID,
36 RENEW_RATE_LIMIT,
37 RENEW_RATE_WINDOW_MS,
38 MAX_GRANTS,
39 MAX_RATE_BUCKETS,
40 DELEGATION_HELPER_CONSENT_REQUIRED,
41 DELEGATION_HELPER_RENEW_RATE_LIMITED,
42 DELEGATION_AUTHORITY_DENIED,
43 DELEGATION_AUTHORITY_CONFLICT,
44 DELEGATION_VALIDATION_SCHEMA,
45 HELPER_ACCESS_SCHEMA,
46 UTC_TIMESTAMP_RE,
47 } from '../lib/agent/delegation-authority-store.mjs';
48 import { computeDelegationAuthorityStateHash } from '../lib/agent/delegation-authority-compat.mjs';
49
50 const __dirname = path.dirname(fileURLToPath(import.meta.url));
51 const ROOT = path.resolve(__dirname, '..');
52 const ROUTES_SRC = path.join(ROOT, 'hub/bridge/delegation-routes.mjs');
53 const GATEWAY_SRC = path.join(ROOT, 'hub/gateway/server.mjs');
54
55 const TEST_UID = 'github:kn1-learner';
56 const PRINCIPAL = hashPrincipalRef(TEST_UID);
57 const SESSION_SECRET = 'rhf-kn1-session-secret-for-tests';
58 const NOW = Date.parse('2026-08-27T12:00:00.000Z');
59
60 function mkDataDir() {
61 return fs.mkdtempSync(path.join(os.tmpdir(), 'kt-rhf-kn1-'));
62 }
63
64 function personalConsent(overrides = {}) {
65 return {
66 schema: DELEGATION_CONSENT_SCHEMA,
67 consent_id: overrides.consent_id || 'dcons_kn1retail01',
68 principal_ref: PRINCIPAL,
69 delegate_agent_id: RETAIL_ACTOR_ID,
70 scope: 'personal',
71 expires_at: '2026-12-31T23:59:59.000Z',
72 revoked_at: null,
73 evidence_ref: 'proposal:prop_kn1',
74 created: '2026-08-01T00:00:00.000Z',
75 audit_sequence: 0,
76 last_materialized_audit_sequence: 0,
77 pending_audit_count: 0,
78 ...overrides,
79 };
80 }
81
82 async function seededStore(envelopeOverrides = {}, storeOpts = {}) {
83 const dataDir = mkDataDir();
84 const cas = new MemoryCasBlobStore();
85 const { envelope } = await seedActiveAuthorityEnvelope({
86 dataDir,
87 vaultId: 'Business',
88 cas,
89 envelopeOverrides: {
90 consents_by_id: {
91 dcons_kn1retail01: personalConsent(),
92 },
93 ...envelopeOverrides,
94 },
95 });
96 const store = createDelegationAuthorityStore({
97 dataDir,
98 vaultId: 'Business',
99 blobStore: cas,
100 sessionSecret: SESSION_SECRET,
101 nowMs: NOW,
102 operatorAuthorizedMarker: storeOpts.operatorAuthorizedMarker === true,
103 ...storeOpts,
104 });
105 return { store, cas, dataDir, envelope };
106 }
107
108 describe('RHF-b-KN1 — unit', () => {
109 test('strict UTC regex + equal-to-expiry is expired', () => {
110 assert.equal(UTC_TIMESTAMP_RE.test('2026-08-27T12:00:00.000Z'), true);
111 assert.equal(isStrictUtcTimestamp('2026-08-27T12:00:00Z'), true);
112 assert.equal(isStrictUtcTimestamp('2026-08-27 12:00:00Z'), false);
113 const consent = personalConsent({ expires_at: '2026-08-27T12:00:00.000Z' });
114 assert.equal(isConsentActiveStrict(consent, NOW), false);
115 assert.equal(isConsentActiveStrict(consent, NOW - 1), true);
116 });
117
118 test('consent selection: newest created then consent_id ascending', () => {
119 const envelope = {
120 consents_by_id: {
121 dcons_b: personalConsent({
122 consent_id: 'dcons_b',
123 created: '2026-08-02T00:00:00.000Z',
124 }),
125 dcons_a: personalConsent({
126 consent_id: 'dcons_a',
127 created: '2026-08-02T00:00:00.000Z',
128 }),
129 dcons_old: personalConsent({
130 consent_id: 'dcons_old',
131 created: '2026-08-01T00:00:00.000Z',
132 }),
133 },
134 newest_active_consent_id_by_principal_actor: {},
135 };
136 const selected = selectActivePersonalConsent(envelope, PRINCIPAL, RETAIL_ACTOR_ID, NOW);
137 assert.equal(selected.consent_id, 'dcons_a');
138 });
139
140 test('authority subjects are 43-char base64url and rotate previous', () => {
141 const subjects = buildAuthoritySubjects({
142 sessionSecret: SESSION_SECRET,
143 sessionSecretPrevious: 'previous-secret-kn1',
144 uid: TEST_UID,
145 vaultId: 'Business',
146 actorId: RETAIL_ACTOR_ID,
147 });
148 assert.equal(subjects.length, 2);
149 assert.equal(subjects[0].key_id, 'current');
150 assert.equal(subjects[1].key_id, 'previous');
151 assert.equal(subjects[0].value.length, 43);
152 assert.match(subjects[0].value, /^[A-Za-z0-9_-]{43}$/);
153 assert.notEqual(subjects[0].value, subjects[1].value);
154 });
155
156 test('state hash seals and detects tamper', () => {
157 let envelope = {
158 schema: 'knowtation.delegation_authority_envelope/v1',
159 schema_version: 1,
160 vault_id: 'Business',
161 lineage_id: 'lineage_x',
162 origin_snapshot_hash:
163 'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
164 revision: 0,
165 previous_state_hash: null,
166 identities_by_id: {},
167 consents_by_id: {},
168 grants_by_id: {},
169 grant_id_by_bearer_hash: {},
170 newest_active_consent_id_by_principal_actor: {},
171 rate_buckets_by_principal_actor: {},
172 audit_outbox_by_id: {},
173 };
174 envelope = sealEnvelopeStateHash(envelope);
175 assert.equal(validateEnvelopeInternalIntegrity(envelope).ok, true);
176 const tampered = { ...envelope, revision: 99 };
177 tampered.state_hash = envelope.state_hash;
178 assert.equal(validateEnvelopeInternalIntegrity(tampered).ok, false);
179 assert.equal(computeDelegationAuthorityStateHash(envelope), envelope.state_hash);
180 });
181
182 test('bridge + gateway source register renew/validate/helper-access', () => {
183 const routes = fs.readFileSync(ROUTES_SRC, 'utf8');
184 assert.match(routes, /grants\/renew-personal/);
185 assert.match(routes, /grants\/validate/);
186 assert.match(routes, /helper-access/);
187 assert.match(routes, /requireStrictSessionToken/);
188 const gateway = fs.readFileSync(GATEWAY_SRC, 'utf8');
189 assert.match(gateway, /grants\/renew-personal/);
190 assert.match(gateway, /grants\/validate/);
191 assert.match(gateway, /helper-access/);
192 assert.match(gateway, /x-delegation-actor/);
193 assert.match(gateway, /x-retail-visit/);
194 });
195
196 test('authorityBlobGetOpts omits strong consistency on Lambda-compat', () => {
197 const prevNetlify = process.env.NETLIFY;
198 const prevLambda = process.env.AWS_LAMBDA_FUNCTION_NAME;
199 try {
200 delete process.env.NETLIFY;
201 delete process.env.AWS_LAMBDA_FUNCTION_NAME;
202 assert.equal(authorityBlobGetOpts().consistency, 'strong');
203
204 process.env.NETLIFY = 'true';
205 assert.equal(authorityBlobGetOpts().consistency, undefined);
206 assert.equal(authorityBlobGetOpts().type, 'text');
207
208 delete process.env.NETLIFY;
209 process.env.AWS_LAMBDA_FUNCTION_NAME = 'bridge';
210 assert.equal(authorityBlobGetOpts().consistency, undefined);
211 } finally {
212 if (prevNetlify === undefined) delete process.env.NETLIFY;
213 else process.env.NETLIFY = prevNetlify;
214 if (prevLambda === undefined) delete process.env.AWS_LAMBDA_FUNCTION_NAME;
215 else process.env.AWS_LAMBDA_FUNCTION_NAME = prevLambda;
216 }
217 });
218 });
219
220 describe('RHF-b-KN1 — integration', () => {
221 test('helper-access states: consent_required → renewable → ready', async () => {
222 const { store } = await seededStore({ consents_by_id: {} });
223 const none = await store.readHelperAccess(TEST_UID, RETAIL_ACTOR_ID);
224 assert.equal(none.ok, true);
225 assert.equal(none.payload.state, 'consent_required');
226
227 const { store: store2 } = await seededStore();
228 const renewable = await store2.readHelperAccess(TEST_UID, RETAIL_ACTOR_ID);
229 assert.equal(renewable.payload.schema, HELPER_ACCESS_SCHEMA);
230 assert.equal(renewable.payload.state, 'renewable');
231
232 const mint = await store2.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
233 assert.equal(mint.ok, true);
234 assert.equal(mint.payload.schema, 'knowtation.delegation_grant_mint/v0');
235 assert.ok(mint.payload.bearer);
236 assert.equal(mint.payload.grant.audit_sequence, undefined);
237 assert.equal(mint.payload.grant.pending_audit_count, undefined);
238 assert.equal(mint.payload.grant.last_materialized_audit_sequence, undefined);
239 const ready = await store2.readHelperAccess(TEST_UID, RETAIL_ACTOR_ID);
240 assert.equal(ready.payload.state, 'ready');
241 });
242
243 test('helper-access survives Lambda-compat BlobsConsistencyError on strong gets', async () => {
244 /**
245 * Netlify connectLambda store: strong consistency throws; eventual succeeds.
246 * Pre-fix STRONG_GET always passed consistency:strong → 503 while grants worked.
247 */
248 class LambdaCompatCasStore extends MemoryCasBlobStore {
249 async get(key, opts = {}) {
250 if (opts.consistency === 'strong') {
251 throw new Error('BlobsConsistencyError: strong consistency is not available');
252 }
253 return super.get(key, opts);
254 }
255 async getWithMetadata(key, opts = {}) {
256 if (opts.consistency === 'strong') {
257 throw new Error('BlobsConsistencyError: strong consistency is not available');
258 }
259 return super.getWithMetadata(key, opts);
260 }
261 }
262
263 const prevNetlify = process.env.NETLIFY;
264 process.env.NETLIFY = 'true';
265 try {
266 const dataDir = mkDataDir();
267 const cas = new LambdaCompatCasStore();
268 await seedActiveAuthorityEnvelope({
269 dataDir,
270 vaultId: 'Business',
271 cas,
272 envelopeOverrides: {
273 consents_by_id: {
274 dcons_kn1retail01: personalConsent(),
275 },
276 newest_active_consent_id_by_principal_actor: {
277 [principalActorKey(PRINCIPAL, RETAIL_ACTOR_ID)]: 'dcons_kn1retail01',
278 },
279 },
280 });
281 const store = createDelegationAuthorityStore({
282 dataDir,
283 vaultId: 'Business',
284 blobStore: cas,
285 sessionSecret: SESSION_SECRET,
286 nowMs: NOW,
287 });
288 const access = await store.readHelperAccess(TEST_UID, RETAIL_ACTOR_ID);
289 assert.equal(access.ok, true);
290 assert.equal(access.payload.state, 'renewable');
291 } finally {
292 if (prevNetlify === undefined) delete process.env.NETLIFY;
293 else process.env.NETLIFY = prevNetlify;
294 }
295 });
296
297 test('renew without consent fails closed; validate consumes action_count', async () => {
298 const { store } = await seededStore({ consents_by_id: {} });
299 const denied = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
300 assert.equal(denied.ok, false);
301 assert.equal(denied.code, DELEGATION_HELPER_CONSENT_REQUIRED);
302
303 const { store: store2 } = await seededStore();
304 const mint = await store2.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
305 assert.equal(mint.ok, true);
306 const visit = randomBytes(32).toString('base64url');
307 const validated = await store2.validateAndConsume({
308 uid: TEST_UID,
309 bearer: mint.payload.bearer,
310 actorId: RETAIL_ACTOR_ID,
311 visitHandle: visit,
312 });
313 assert.equal(validated.ok, true);
314 assert.equal(validated.payload.schema, DELEGATION_VALIDATION_SCHEMA);
315 assert.equal(validated.payload.authority_subjects[0].value.length, 43);
316
317 const grantId = mint.payload.grant.grant_id;
318 const after = await store2.readActiveEnvelope();
319 assert.equal(after.envelope.grants_by_id[grantId].action_count, 1);
320 assert.equal(after.envelope.grants_by_id[grantId].last_materialized_audit_sequence >= 1, true);
321 });
322
323 test('wrong bearer / actor / principal denied', async () => {
324 const { store } = await seededStore();
325 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
326 const visit = randomBytes(32).toString('base64url');
327 const badBearer = await store.validateAndConsume({
328 uid: TEST_UID,
329 bearer: 'dgrnt_bearer_notreal00000000',
330 actorId: RETAIL_ACTOR_ID,
331 visitHandle: visit,
332 });
333 assert.equal(badBearer.code, DELEGATION_AUTHORITY_DENIED);
334
335 const badPrincipal = await store.validateAndConsume({
336 uid: 'github:other-user',
337 bearer: mint.payload.bearer,
338 actorId: RETAIL_ACTOR_ID,
339 visitHandle: visit,
340 });
341 assert.equal(badPrincipal.code, DELEGATION_AUTHORITY_DENIED);
342 });
343
344 test('candidate create is ignored until authorized marker; unauthorized activate blocked', async () => {
345 const dataDir = mkDataDir();
346 const cas = new MemoryCasBlobStore();
347 // seed empty legacy stores
348 fs.writeFileSync(
349 path.join(dataDir, 'hub_delegation_identities.json'),
350 JSON.stringify({ vaults: { Business: { identities: [] } } }),
351 );
352 fs.writeFileSync(
353 path.join(dataDir, 'hub_delegation_consents.json'),
354 JSON.stringify({
355 vaults: {
356 Business: {
357 consents: [personalConsent()],
358 },
359 },
360 }),
361 );
362 fs.writeFileSync(
363 path.join(dataDir, 'hub_delegation_grants.json'),
364 JSON.stringify({ vaults: { Business: { grants: [] } } }),
365 );
366
367 const blocked = createDelegationAuthorityStore({
368 dataDir,
369 vaultId: 'Business',
370 blobStore: cas,
371 sessionSecret: SESSION_SECRET,
372 operatorAuthorizedMarker: false,
373 });
374 const candidate = await blocked.createOrVerifyCandidate();
375 assert.equal(candidate.ok, true);
376 assert.ok(candidate.lineage_id);
377 // Readers still inactive without marker
378 const inactive = await blocked.readActiveEnvelope();
379 assert.equal(inactive.ok, false);
380
381 const noAuth = await blocked.activateMarker({ operatorAuthorized: true });
382 assert.equal(noAuth.ok, false);
383
384 const authorized = createDelegationAuthorityStore({
385 dataDir,
386 vaultId: 'Business',
387 blobStore: cas,
388 sessionSecret: SESSION_SECRET,
389 operatorAuthorizedMarker: true,
390 });
391 const activated = await authorized.activateMarker({ operatorAuthorized: true });
392 assert.equal(activated.ok, true);
393 const active = await authorized.readActiveEnvelope();
394 assert.equal(active.ok, true);
395 assert.ok(active.envelope.consents_by_id.dcons_kn1retail01);
396 });
397 });
398
399 describe('RHF-b-KN1 — e2e (store protocol)', () => {
400 test('renew → helper ready → validate → second validate increments', async () => {
401 const { store } = await seededStore();
402 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
403 const visit = randomBytes(32).toString('base64url');
404 await store.validateAndConsume({
405 uid: TEST_UID,
406 bearer: mint.payload.bearer,
407 actorId: RETAIL_ACTOR_ID,
408 visitHandle: visit,
409 });
410 await store.validateAndConsume({
411 uid: TEST_UID,
412 bearer: mint.payload.bearer,
413 actorId: RETAIL_ACTOR_ID,
414 visitHandle: visit,
415 });
416 const after = await store.readActiveEnvelope();
417 assert.equal(after.envelope.grants_by_id[mint.payload.grant.grant_id].action_count, 2);
418 assert.equal(after.envelope.revision >= 3, true);
419 });
420 });
421
422 describe('RHF-b-KN1 — stress', () => {
423 test('rate limit 12 renewals / 5 minutes', async () => {
424 const { store } = await seededStore();
425 for (let i = 0; i < RENEW_RATE_LIMIT; i += 1) {
426 const r = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
427 assert.equal(r.ok, true, `renew ${i}`);
428 }
429 const limited = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
430 assert.equal(limited.ok, false);
431 assert.equal(limited.code, DELEGATION_HELPER_RENEW_RATE_LIMITED);
432 assert.equal(RENEW_RATE_WINDOW_MS, 5 * 60 * 1000);
433 });
434
435 test('CAS conflict returns 409 after retries', async () => {
436 const dataDir = mkDataDir();
437 const cas = new MemoryCasBlobStore();
438 await seedActiveAuthorityEnvelope({
439 dataDir,
440 vaultId: 'Business',
441 cas,
442 envelopeOverrides: {
443 consents_by_id: { dcons_kn1retail01: personalConsent() },
444 },
445 });
446 // Wrap set to always fail onlyIfMatch
447 const origSet = cas.set.bind(cas);
448 cas.set = async (key, value, opts = {}) => {
449 if (opts.onlyIfMatch) return { modified: false };
450 return origSet(key, value, opts);
451 };
452 const store = createDelegationAuthorityStore({
453 dataDir,
454 vaultId: 'Business',
455 blobStore: cas,
456 sessionSecret: SESSION_SECRET,
457 nowMs: NOW,
458 });
459 const result = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
460 assert.equal(result.ok, false);
461 assert.equal(result.code, DELEGATION_AUTHORITY_CONFLICT);
462 });
463 });
464
465 describe('RHF-b-KN1 — data-integrity', () => {
466 test('mutation advances revision and previous_state_hash chain', async () => {
467 const { store } = await seededStore();
468 const before = await store.readActiveEnvelope();
469 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
470 assert.equal(mint.ok, true);
471 const after = await store.readActiveEnvelope();
472 // Authority CAS + post-CAS materialize drain each bump revision.
473 assert.ok(after.envelope.revision >= before.envelope.revision + 1);
474 assert.notEqual(after.envelope.state_hash, before.envelope.state_hash);
475 assert.equal(validateEnvelopeInternalIntegrity(after.envelope).ok, true);
476 });
477
478 test('outbox materializes contiguously in same CAS as grant mint', async () => {
479 const { store } = await seededStore();
480 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
481 const after = await store.readActiveEnvelope();
482 const grant = after.envelope.grants_by_id[mint.payload.grant.grant_id];
483 assert.equal(grant.audit_sequence, 1);
484 assert.equal(grant.last_materialized_audit_sequence, 1);
485 assert.equal(grant.pending_audit_count, 0);
486 assert.equal(Object.keys(after.envelope.audit_outbox_by_id).length, 0);
487 assert.ok(after.envelope.event_chain_heads_by_record[`grant:${grant.grant_id}`]);
488 });
489
490 test('prune refuses active grants and keeps consent forever', async () => {
491 const { store } = await seededStore();
492 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
493 const env = (await store.readActiveEnvelope()).envelope;
494 const pruned = pruneAuthorityEnvelope(env, NOW);
495 assert.ok(pruned.grants_by_id[mint.payload.grant.grant_id]);
496 assert.ok(pruned.consents_by_id.dcons_kn1retail01);
497 });
498 });
499
500 describe('RHF-b-KN1 — performance', () => {
501 test('O(1) bearer index lookup and transform p95 budget on large envelope', async () => {
502 /** @type {Record<string, object>} */
503 const grants_by_id = {};
504 /** @type {Record<string, string>} */
505 const grant_id_by_bearer_hash = {};
506 for (let i = 0; i < 200; i += 1) {
507 const id = `dgrnt_perf${String(i).padStart(8, '0')}`;
508 const bearer = `dgrnt_bearer_perf${String(i).padStart(8, '0')}`;
509 const hash = hashGrantBearer(bearer);
510 grants_by_id[id] = {
511 schema: 'knowtation.delegation_grant/v0',
512 grant_id: id,
513 consent_id: 'dcons_kn1retail01',
514 actor_agent_id: RETAIL_ACTOR_ID,
515 principal_ref: PRINCIPAL,
516 scope: 'personal',
517 expires_at: '2026-12-31T23:59:59.000Z',
518 revoked_at: null,
519 max_actions: 64,
520 action_count: 0,
521 issued_at: '2026-08-27T11:00:00.000Z',
522 grant_bearer_hash: hash,
523 audit_sequence: 0,
524 last_materialized_audit_sequence: 0,
525 pending_audit_count: 0,
526 };
527 grant_id_by_bearer_hash[hash] = id;
528 }
529 const dataDir = mkDataDir();
530 const cas = new MemoryCasBlobStore();
531 await seedActiveAuthorityEnvelope({
532 dataDir,
533 vaultId: 'Business',
534 cas,
535 envelopeOverrides: {
536 consents_by_id: { dcons_kn1retail01: personalConsent() },
537 grants_by_id,
538 grant_id_by_bearer_hash,
539 },
540 });
541
542 const samples = [];
543 for (let i = 0; i < 40; i += 1) {
544 // Space renewals outside the 5-minute window so the rate limit never trips.
545 const store = createDelegationAuthorityStore({
546 dataDir,
547 vaultId: 'Business',
548 blobStore: cas,
549 sessionSecret: SESSION_SECRET,
550 nowMs: NOW + i * (RENEW_RATE_WINDOW_MS + 1000),
551 });
552 const t0 = performance.now();
553 const r = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
554 samples.push(performance.now() - t0);
555 assert.equal(r.ok, true, `renew ${i}: ${r.code || ''}`);
556 }
557 samples.sort((a, b) => a - b);
558 const p95 = samples[Math.floor(samples.length * 0.95)];
559 assert.ok(p95 <= 250, `transform+CAS p95 ${p95}ms exceeds 250ms`);
560 assert.ok(MAX_GRANTS >= 3072);
561 assert.ok(MAX_RATE_BUCKETS === 64);
562 });
563 });
564
565 describe('RHF-b-KN1 — security', () => {
566 test('marker activation without operatorAuthorized is denied', async () => {
567 const { store } = await seededStore({}, { operatorAuthorizedMarker: true });
568 const denied = await store.activateMarker({ operatorAuthorized: false });
569 assert.equal(denied.ok, false);
570 });
571
572 test('malformed timestamps invalidate envelope integrity', () => {
573 const envelope = sealEnvelopeStateHash({
574 schema: 'knowtation.delegation_authority_envelope/v1',
575 schema_version: 1,
576 vault_id: 'Business',
577 lineage_id: 'lineage_x',
578 origin_snapshot_hash:
579 'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
580 revision: 0,
581 previous_state_hash: null,
582 identities_by_id: {},
583 consents_by_id: {
584 dcons_bad: personalConsent({ created: 'not-a-timestamp' }),
585 },
586 grants_by_id: {},
587 grant_id_by_bearer_hash: {},
588 newest_active_consent_id_by_principal_actor: {},
589 rate_buckets_by_principal_actor: {},
590 audit_outbox_by_id: {},
591 });
592 assert.equal(validateEnvelopeInternalIntegrity(envelope).ok, false);
593 });
594
595 test('bearer hash index is used (no array scan required for lookup)', async () => {
596 const { store } = await seededStore();
597 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
598 const after = await store.readActiveEnvelope();
599 const hash = hashGrantBearer(mint.payload.bearer);
600 assert.equal(after.envelope.grant_id_by_bearer_hash[hash], mint.payload.grant.grant_id);
601 assert.equal(principalActorKey(PRINCIPAL, RETAIL_ACTOR_ID).includes('\u0000'), true);
602 });
603
604 test('routes use requireRetailSession (session-first allowlisted 401)', () => {
605 const src = fs.readFileSync(ROUTES_SRC, 'utf8');
606 const renew = src.slice(src.indexOf("app.post('/api/v1/delegation/grants/renew-personal'"));
607 assert.match(renew, /requireRetailSession/);
608 assert.doesNotMatch(renew.slice(0, 200), /requireBridgeAuth/);
609 });
610
611 test('revokeGrant removes active index; revokeConsent refuses other principal', async () => {
612 const { store } = await seededStore();
613 const mint = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
614 const revoked = await store.revokeGrant('admin', mint.payload.grant.grant_id);
615 assert.equal(revoked.ok, true);
616 const access = await store.readHelperAccess(TEST_UID, RETAIL_ACTOR_ID);
617 assert.equal(access.payload.state, 'renewable');
618 const denied = await store.revokeConsent('github:other', 'dcons_kn1retail01');
619 assert.equal(denied.ok, false);
620 });
621
622 test('blob marker read errors fail closed (no stale local fallback)', async () => {
623 const dataDir = mkDataDir();
624 const cas = new MemoryCasBlobStore();
625 await seedActiveAuthorityEnvelope({
626 dataDir,
627 vaultId: 'Business',
628 cas,
629 envelopeOverrides: {
630 consents_by_id: { dcons_kn1retail01: personalConsent() },
631 },
632 });
633 const store = createDelegationAuthorityStore({
634 dataDir,
635 vaultId: 'Business',
636 blobStore: cas,
637 sessionSecret: SESSION_SECRET,
638 nowMs: NOW,
639 });
640 const origGet = cas.get.bind(cas);
641 cas.get = async (key, opts) => {
642 if (String(key).includes('/marker')) throw new Error('blob unavailable');
643 return origGet(key, opts);
644 };
645 const result = await store.readActiveEnvelope();
646 assert.equal(result.ok, false);
647 assert.equal(result.status, 503);
648 });
649
650 test('CAS conflict leaves zero external audit events for uncommitted mint', async () => {
651 const dataDir = mkDataDir();
652 const cas = new MemoryCasBlobStore();
653 await seedActiveAuthorityEnvelope({
654 dataDir,
655 vaultId: 'Business',
656 cas,
657 envelopeOverrides: {
658 consents_by_id: { dcons_kn1retail01: personalConsent() },
659 },
660 });
661 const auditKeys = [];
662 const origSet = cas.set.bind(cas);
663 cas.set = async (key, value, opts = {}) => {
664 if (String(key).startsWith('delegation/audit/')) auditKeys.push(key);
665 if (opts.onlyIfMatch && String(key).includes('/envelope')) {
666 return { modified: false };
667 }
668 return origSet(key, value, opts);
669 };
670 const store = createDelegationAuthorityStore({
671 dataDir,
672 vaultId: 'Business',
673 blobStore: cas,
674 sessionSecret: SESSION_SECRET,
675 nowMs: NOW,
676 });
677 const result = await store.renewPersonal(TEST_UID, RETAIL_ACTOR_ID);
678 assert.equal(result.code, DELEGATION_AUTHORITY_CONFLICT);
679 assert.equal(auditKeys.length, 0);
680 });
681 });
File History 1 commit
sha256:fbe982a22c05c6fe2e93876f250deecdb43d883f648b4e1810c7546caa9f17db docs: activate KNOWTATION- board identity and preserve livi… Human minor 2 days ago