calendar-oauth-connector-data-integrity.test.mjs
89 lines 3.0 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 10 days ago
1 /**
2 * Tier 5 — DATA INTEGRITY: dedup, tombstone, revoke purge, encrypted blob restart.
3 */
4 import { describe, it, beforeEach, afterEach } from 'node:test';
5 import assert from 'node:assert/strict';
6 import fs from 'node:fs';
7 import path from 'node:path';
8 import { fileURLToPath } from 'node:url';
9 import {
10 handleBeginGoogleConnector,
11 handleGoogleConnectorCallback,
12 handleSyncGoogleConnector,
13 createFakeGoogleClient,
14 findPendingConnectorByState,
15 } from '../lib/calendar/google-oauth-connector.mjs';
16 import { buildEventId, queryStoredEvents } from '../lib/calendar/event-store.mjs';
17 import { readOAuthTokenVault } from '../lib/calendar/oauth-token-vault.mjs';
18
19 const __dirname = path.dirname(fileURLToPath(import.meta.url));
20 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-calendar-oauth-integrity');
21 const RETURN_URL = 'https://app.scooling.local:5174/settings/calendar/connect/return';
22 const testEnv = {
23 GOOGLE_CALENDAR_OAUTH_CLIENT_ID: 'cid',
24 GOOGLE_CALENDAR_OAUTH_CLIENT_SECRET: 'sec',
25 KNOWTATION_CALENDAR_OAUTH_SECRET: 'i'.repeat(40),
26 CALENDAR_OAUTH_REDIRECT_URI: 'https://hub.local/callback',
27 SCOOLING_RETURN_URL_ALLOWLIST: RETURN_URL,
28 };
29
30 describe('calendar oauth data integrity', () => {
31 let dataDir;
32
33 beforeEach(() => {
34 fs.rmSync(tmpRoot, { recursive: true, force: true });
35 dataDir = path.join(tmpRoot, 'data');
36 fs.mkdirSync(dataDir, { recursive: true });
37 });
38
39 afterEach(() => {
40 fs.rmSync(tmpRoot, { recursive: true, force: true });
41 });
42
43 it('repeated sync does not duplicate external_uid rows', async () => {
44 const googleClient = createFakeGoogleClient();
45 const begin = handleBeginGoogleConnector({
46 dataDir,
47 vaultId: 'default',
48 body: { provider: 'google', return_url: RETURN_URL },
49 env: testEnv,
50 authorizedOverride: true,
51 });
52 const state = new URL(begin.payload.authorization_url).searchParams.get('state');
53 const located = findPendingConnectorByState(dataDir, state);
54 await handleGoogleConnectorCallback({
55 dataDir,
56 query: { code: 'c', state: located.connector.oauth_pending.state },
57 googleClient,
58 env: testEnv,
59 authorizedOverride: true,
60 });
61 const t = Date.now() + 120_000;
62 await handleSyncGoogleConnector({
63 dataDir,
64 vaultId: 'default',
65 connectorId: begin.payload.connector_id,
66 googleClient,
67 env: testEnv,
68 now: t,
69 authorizedOverride: true,
70 });
71 await handleSyncGoogleConnector({
72 dataDir,
73 vaultId: 'default',
74 connectorId: begin.payload.connector_id,
75 googleClient,
76 env: testEnv,
77 now: t + 120_000,
78 authorizedOverride: true,
79 });
80 const events = queryStoredEvents(dataDir, 'default', {
81 fromIso: '2026-01-01T00:00:00.000Z',
82 toIso: '2027-01-01T00:00:00.000Z',
83 });
84 const ids = new Set(events.map((e) => e.event_id));
85 assert.equal(ids.size, events.length);
86 assert.ok(readOAuthTokenVault(dataDir, begin.payload.connector_id, testEnv.KNOWTATION_CALENDAR_OAUTH_SECRET));
87 assert.ok(buildEventId('cal_g_primary', 'evt-1'));
88 });
89 });
File History 1 commit
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago