companion-token-custody-integration.test.mjs
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠ breaking
1 day ago
| 1 | /** |
| 2 | * Tier 2 — INTEGRATION: custody composed with the PKCE core across the acquire → use → refresh → |
| 3 | * logout lifecycle, over an async keychain adapter (the realistic shape). |
| 4 | */ |
| 5 | import { describe, it } from 'node:test'; |
| 6 | import assert from 'node:assert/strict'; |
| 7 | import { validateTokenResponse } from '../lib/companion-oauth-pkce.mjs'; |
| 8 | import { buildSessionMeta, createTokenCustody } from '../lib/companion-token-custody.mjs'; |
| 9 | import { makeAsyncKeychain } from './helpers/companion-keychain-fake.mjs'; |
| 10 | |
| 11 | describe('Integration — token response → custody → refresh decision', () => { |
| 12 | it('stores a validated token response and decides correctly over time', async () => { |
| 13 | const custody = createTokenCustody(makeAsyncKeychain()); |
| 14 | const tr = validateTokenResponse({ access_token: 'jwt', token_type: 'Bearer', expires_in: 3600, refresh_token: 'r', scope: 'vault:read vault:write' }); |
| 15 | assert.equal(tr.ok, true); |
| 16 | |
| 17 | const now = 1_000_000; |
| 18 | const meta = buildSessionMeta(tr, { now, refreshTtlMs: 86_400_000, issuer: 'https://knowtation.store' }); |
| 19 | await custody.storeSession({ accessToken: tr.accessToken, refreshToken: tr.refreshToken, meta }); |
| 20 | |
| 21 | assert.equal(await custody.decide({ now, skewMs: 30_000 }), 'valid'); |
| 22 | assert.equal(await custody.decide({ now: meta.expiresAt - 10, skewMs: 30_000 }), 'refresh'); |
| 23 | assert.equal(await custody.decide({ now: meta.refreshExpiresAt + 1 }), 'reauth'); |
| 24 | }); |
| 25 | }); |
| 26 | |
| 27 | describe('Integration — refresh rotation lifecycle', () => { |
| 28 | it('a refreshed token response rotates the stored secrets', async () => { |
| 29 | const custody = createTokenCustody(makeAsyncKeychain()); |
| 30 | const first = validateTokenResponse({ access_token: 'jwt1', token_type: 'Bearer', expires_in: 60, refresh_token: 'r1' }); |
| 31 | await custody.storeSession({ accessToken: first.accessToken, refreshToken: first.refreshToken, meta: buildSessionMeta(first, { now: 0, refreshTtlMs: 1_000_000 }) }); |
| 32 | |
| 33 | const refreshed = validateTokenResponse({ access_token: 'jwt2', token_type: 'Bearer', expires_in: 60, refresh_token: 'r2' }); |
| 34 | await custody.updateAccessToken({ accessToken: refreshed.accessToken, refreshToken: refreshed.refreshToken, meta: buildSessionMeta(refreshed, { now: 1000, refreshTtlMs: 1_000_000 }) }); |
| 35 | |
| 36 | const loaded = await custody.loadSession(); |
| 37 | assert.equal(loaded.accessToken, 'jwt2'); |
| 38 | assert.equal(loaded.refreshToken, 'r2'); |
| 39 | }); |
| 40 | }); |
| 41 | |
| 42 | describe('Integration — invalid_grant on refresh forces a full logout', () => { |
| 43 | it('an invalid_grant token response leads the caller to clearSession → reauth', async () => { |
| 44 | const custody = createTokenCustody(makeAsyncKeychain()); |
| 45 | const first = validateTokenResponse({ access_token: 'jwt1', token_type: 'Bearer', expires_in: 60, refresh_token: 'r1' }); |
| 46 | await custody.storeSession({ accessToken: first.accessToken, refreshToken: first.refreshToken, meta: buildSessionMeta(first, { now: 0, refreshTtlMs: 1_000_000 }) }); |
| 47 | |
| 48 | const refreshAttempt = validateTokenResponse({ error: 'invalid_grant' }); |
| 49 | assert.equal(refreshAttempt.ok, false); |
| 50 | // Caller policy on refresh failure: clear and re-auth. |
| 51 | await custody.clearSession(); |
| 52 | assert.equal(await custody.decide({ now: 0 }), 'reauth'); |
| 53 | }); |
| 54 | }); |
File History
2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd
feat(calendar): enforce agent context tiers in retrieval AP…
Human
minor
⚠
1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6
docs: accept Calendar Events v0 spec with Phase 0 security …
Human
1 day ago