Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { randomBytes } from 'node:crypto';
import { describe, expect, it, vi } from 'vitest';
import type { TrustedCalendarUserContext } from './calendar-service-context';
import type { CalendarConnectionRecord } from './calendar-connection-repository';
import {
CalendarCredentialMaterializationError,
CalendarCredentialMaterializer,
} from './calendar-credential-materializer';

const WORKSPACE_ID = '11111111-1111-4111-8111-111111111111';
const USER_ID = '22222222-2222-4222-8222-222222222222';
const CONNECTION_ID = '33333333-3333-4333-8333-333333333333';
const ACCESS_MATERIAL = randomBytes(24).toString('base64url');
const REFRESH_MATERIAL = randomBytes(24).toString('base64url');
const AUTHORITY: TrustedCalendarUserContext = Object.freeze({
workspaceId: WORKSPACE_ID,
userId: USER_ID,
});

function connection(
overrides: Partial<CalendarConnectionRecord> = {},
): CalendarConnectionRecord {
return Object.freeze({
connectionId: CONNECTION_ID,
workspaceId: WORKSPACE_ID,
userId: USER_ID,
providerCode: 'google',
providerAccountSubject: 'subject-1',
scopeValues: Object.freeze(['calendar.events']),
accessSecretHandle: 'kms://calendar/access-33333333',
refreshSecretHandle: 'kms://calendar/refresh-33333333',
tokenExpiresAt: '2026-08-12T12:00:00.000Z',
selectedCalendarIdentifier: 'primary',
status: 'active',
createdAt: '2026-08-12T10:00:00.000Z',
updatedAt: '2026-08-12T10:00:00.000Z',
revokedAt: null,
...overrides,
});
}

function materializer(record: CalendarConnectionRecord | undefined) {
const getActiveConnection = vi.fn().mockResolvedValue(record);
const readSecret = vi.fn(async (handle: string) =>
handle.includes('/refresh-') ? REFRESH_MATERIAL : ACCESS_MATERIAL,
);
return {
getActiveConnection,
readSecret,
subject: new CalendarCredentialMaterializer(
{ getActiveConnection },
{ readSecret },
),
};
}

async function expectMaterializationFailure(
operation: Promise<unknown>,
): Promise<void> {
await expect(operation).rejects.toBeInstanceOf(
CalendarCredentialMaterializationError,
);
}

describe('CalendarCredentialMaterializer', () => {
it('materializes only the exact active connection inside trusted user authority', async () => {
const fixture = materializer(connection());

await expect(
fixture.subject.materialize(AUTHORITY, CONNECTION_ID),
).resolves.toEqual({
connectionId: CONNECTION_ID,
providerCode: 'google',
accessToken: ACCESS_MATERIAL,
refreshToken: REFRESH_MATERIAL,
tokenExpiresAt: '2026-08-12T12:00:00.000Z',
selectedCalendarIdentifier: 'primary',
});
expect(fixture.getActiveConnection).toHaveBeenCalledWith({
connectionId: CONNECTION_ID,
workspaceId: WORKSPACE_ID,
userId: USER_ID,
});
expect(fixture.readSecret.mock.calls.map(([handle]) => handle)).toEqual([
'kms://calendar/access-33333333',
'kms://calendar/refresh-33333333',
]);
});

it('fails closed when the connection does not exist and never materializes a secret', async () => {
const fixture = materializer(undefined);

await expectMaterializationFailure(
fixture.subject.materialize(AUTHORITY, CONNECTION_ID),
);
expect(fixture.readSecret).not.toHaveBeenCalled();
});

it('rejects persistence evidence from another workspace or user before secret access', async () => {
for (const record of [
connection({ workspaceId: '44444444-4444-4444-8444-444444444444' }),
connection({ userId: '55555555-5555-4555-8555-555555555555' }),
connection({ connectionId: '66666666-6666-4666-8666-666666666666' }),
connection({ status: 'revoked', revokedAt: '2026-08-12T11:00:00.000Z' }),
]) {
const fixture = materializer(record);
await expectMaterializationFailure(
fixture.subject.materialize(AUTHORITY, CONNECTION_ID),
);
expect(fixture.readSecret).not.toHaveBeenCalled();
}
});

it('fails closed when secret materialization is unavailable without exposing provider errors', async () => {
const getActiveConnection = vi.fn().mockResolvedValue(connection());
const readSecret = vi
.fn()
.mockRejectedValue(new Error('provider sensitive-material marker'));
const subject = new CalendarCredentialMaterializer(
{ getActiveConnection },
{ readSecret },
);

let thrown: unknown;
try {
await subject.materialize(AUTHORITY, CONNECTION_ID);
} catch (error) {
thrown = error;
}
expect(thrown).toBeInstanceOf(CalendarCredentialMaterializationError);
expect((thrown as Error).message).not.toContain('sensitive-material');
});

it('rejects empty, oversized, or control-character secret values', async () => {
for (const secretValue of ['', 'a'.repeat(16_385), 'material\nvalue']) {
const getActiveConnection = vi.fn().mockResolvedValue(
connection({
refreshSecretHandle: null,
}),
);
const readSecret = vi.fn().mockResolvedValue(secretValue);
const subject = new CalendarCredentialMaterializer(
{ getActiveConnection },
{ readSecret },
);

await expectMaterializationFailure(
subject.materialize(AUTHORITY, CONNECTION_ID),
);
}
});

it('supports access-token-only providers without inventing refresh authority', async () => {
const fixture = materializer(connection({ refreshSecretHandle: null }));

await expect(
fixture.subject.materialize(AUTHORITY, CONNECTION_ID),
).resolves.toMatchObject({ refreshToken: null });
expect(fixture.readSecret).toHaveBeenCalledTimes(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import type { TrustedCalendarUserContext } from './calendar-service-context';
import type {
CalendarConnectionProvider,
CalendarConnectionRecord,
GetActiveCalendarConnection,
} from './calendar-connection-repository';

const UUID_V4_PATTERN =
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
const SECRET_HANDLE_PATTERN =
/^[A-Za-z][A-Za-z0-9+.-]{0,31}:\/\/[^\s\u0000-\u001f\u007f]{1,1024}$/u;
const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f]/u;
const MAXIMUM_SECRET_LENGTH = 16_384;

/** Least-authority lookup needed before calendar credential materialization. */
export interface CalendarCredentialConnectionPort {
getActiveConnection(
input: GetActiveCalendarConnection,
): Promise<CalendarConnectionRecord | undefined>;
}

/** External encrypted secret-store/KMS port; opaque handles are the only lookup key. */
export interface CalendarCredentialSecretStore {
readSecret(secretHandle: string): Promise<string>;
}

/** Internal-only provider material. This type must never be returned by a public controller. */
export interface CalendarCredentialMaterial {
readonly connectionId: string;
readonly providerCode: CalendarConnectionProvider;
readonly accessToken: string;
readonly refreshToken: string | null;
readonly tokenExpiresAt: string;
readonly selectedCalendarIdentifier: string;
}

/** Fixed fail-closed error that never retains provider credential material. */
export class CalendarCredentialMaterializationError extends Error {
/** Creates a credential-free failure safe for application-level sanitization. */
constructor() {
super('Calendar credential materialization is unavailable');
this.name = 'CalendarCredentialMaterializationError';
}
}

function invalid(): never {
throw new CalendarCredentialMaterializationError();
}

function requireUuidV4(value: unknown): string {
if (typeof value !== 'string' || !UUID_V4_PATTERN.test(value)) {
return invalid();
}
return value.toLowerCase();
}

function requireSecretHandle(value: unknown): string {
if (typeof value !== 'string' || !SECRET_HANDLE_PATTERN.test(value)) {
return invalid();
}
return value;
}

function requireSecretMaterial(value: unknown): string {
if (
typeof value !== 'string' ||
value.length === 0 ||
value.length > MAXIMUM_SECRET_LENGTH ||
CONTROL_CHARACTER_PATTERN.test(value)
) {
return invalid();
}
return value;
}

function requireActiveEvidence(
record: CalendarConnectionRecord,
expected: GetActiveCalendarConnection,
): CalendarConnectionRecord {
if (
record.status !== 'active' ||
record.revokedAt !== null ||
record.connectionId !== expected.connectionId ||
record.workspaceId !== expected.workspaceId ||
record.userId !== expected.userId
) {
return invalid();
}
return record;
}

/**
* Resolves provider credentials only after exact tenant/user/connection authority.
* Durable LifeOS state supplies opaque handles; plaintext exists only in the
* returned internal value and must be passed directly to the selected provider.
*/
export class CalendarCredentialMaterializer {
/** Creates the materializer over scoped connection evidence and encrypted secret storage. */
constructor(
private readonly connections: CalendarCredentialConnectionPort,
private readonly secrets: CalendarCredentialSecretStore,
) {}

/** Materializes one exact active connection without accepting ownership from caller data. */
async materialize(
authority: TrustedCalendarUserContext,
connectionId: string,
): Promise<CalendarCredentialMaterial> {
const expected = Object.freeze({
connectionId: requireUuidV4(connectionId),
workspaceId: requireUuidV4(authority.workspaceId),
userId: requireUuidV4(authority.userId),
});

let persisted: CalendarConnectionRecord | undefined;
try {
persisted = await this.connections.getActiveConnection(expected);
} catch {
return invalid();
}
if (!persisted) {
return invalid();
}
const record = requireActiveEvidence(persisted, expected);
const accessSecretHandle = requireSecretHandle(record.accessSecretHandle);
const refreshSecretHandle =
record.refreshSecretHandle === null
? null
: requireSecretHandle(record.refreshSecretHandle);

let accessToken: string;
let refreshToken: string | null;
try {
accessToken = requireSecretMaterial(
await this.secrets.readSecret(accessSecretHandle),
);
refreshToken = refreshSecretHandle
? requireSecretMaterial(await this.secrets.readSecret(refreshSecretHandle))
: null;
} catch {
return invalid();
}

return Object.freeze({
connectionId: record.connectionId,
providerCode: record.providerCode,
accessToken,
refreshToken,
tokenExpiresAt: record.tokenExpiresAt,
selectedCalendarIdentifier: record.selectedCalendarIdentifier,
});
}
}
Loading