agent-ecosystem/src/main/services/team/bootstrap/BootstrapProofValidation.ts
2026-05-06 17:34:01 +03:00

225 lines
7.5 KiB
TypeScript

export const LEGACY_MEMBER_BRIEFING_BOOTSTRAP_PROOF_SOURCE = 'member_briefing_tool_success';
export const NATIVE_APP_MANAGED_BOOTSTRAP_PROOF_SOURCE =
'native_app_managed_bootstrap_private_turn';
type BootstrapProofField =
| 'source'
| 'bootstrapProofToken'
| 'contextHash'
| 'briefingHash'
| 'runId';
export type BootstrapProofSource =
| typeof LEGACY_MEMBER_BRIEFING_BOOTSTRAP_PROOF_SOURCE
| typeof NATIVE_APP_MANAGED_BOOTSTRAP_PROOF_SOURCE;
export type BootstrapProofValidationFailureReason =
| 'wrong_event_type'
| 'wrong_team'
| 'stale_timestamp'
| 'unsupported_source'
| 'missing_team'
| 'missing_token'
| 'token_mismatch'
| 'missing_run_id'
| 'run_id_mismatch'
| 'missing_hash'
| 'hash_mismatch'
| 'wrong_proof_mode';
export type BootstrapProofValidationResult =
| { ok: true; source: BootstrapProofSource }
| { ok: false; reason: BootstrapProofValidationFailureReason; diagnostic: string };
export interface BootstrapRuntimeProofEventLike {
type?: unknown;
timestamp?: unknown;
teamName?: unknown;
source?: unknown;
bootstrapProofToken?: unknown;
contextHash?: unknown;
briefingHash?: unknown;
runId?: unknown;
detail?: unknown;
}
export interface BootstrapRuntimeProofExpected {
teamName: string;
boundaryMs: number;
proofToken?: string;
proofMode?: string;
contextHash?: string;
briefingHash?: string;
runId?: string;
}
export function parseBootstrapRuntimeProofDetail(detail: unknown): Record<string, unknown> {
if (typeof detail !== 'string' || detail.trim().length === 0) {
return {};
}
try {
const parsed = JSON.parse(detail) as unknown;
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
? (parsed as Record<string, unknown>)
: {};
} catch {
return {};
}
}
function readProofField(
event: BootstrapRuntimeProofEventLike,
detail: Record<string, unknown>,
field: BootstrapProofField
): string | undefined {
const direct = event[field];
if (typeof direct === 'string' && direct.trim().length > 0) {
return direct.trim();
}
const nested = detail[field];
return typeof nested === 'string' && nested.trim().length > 0 ? nested.trim() : undefined;
}
function getBootstrapProofSource(
event: BootstrapRuntimeProofEventLike,
detail: Record<string, unknown>
): BootstrapProofSource | undefined {
const source = readProofField(event, detail, 'source');
return source === LEGACY_MEMBER_BRIEFING_BOOTSTRAP_PROOF_SOURCE ||
source === NATIVE_APP_MANAGED_BOOTSTRAP_PROOF_SOURCE
? source
: undefined;
}
function reject(
reason: BootstrapProofValidationFailureReason,
diagnostic: string
): BootstrapProofValidationResult {
return { ok: false, reason, diagnostic };
}
function validateExpectedProofToken(input: {
event: BootstrapRuntimeProofEventLike;
detail: Record<string, unknown>;
expected: BootstrapRuntimeProofExpected;
}): BootstrapProofValidationResult | null {
if (!input.expected.proofToken) {
return null;
}
const eventToken = readProofField(input.event, input.detail, 'bootstrapProofToken');
if (!eventToken) {
return reject('missing_token', 'Bootstrap proof token is missing');
}
if (eventToken !== input.expected.proofToken) {
return reject('token_mismatch', 'Bootstrap proof token does not match the current attempt');
}
return null;
}
function validateLegacyMemberBriefingProof(input: {
event: BootstrapRuntimeProofEventLike;
detail: Record<string, unknown>;
expected: BootstrapRuntimeProofExpected;
}): BootstrapProofValidationResult {
const tokenFailure = validateExpectedProofToken(input);
return tokenFailure ?? { ok: true, source: LEGACY_MEMBER_BRIEFING_BOOTSTRAP_PROOF_SOURCE };
}
function validateNativeAppManagedProof(input: {
event: BootstrapRuntimeProofEventLike;
detail: Record<string, unknown>;
expected: BootstrapRuntimeProofExpected;
}): BootstrapProofValidationResult {
const eventTeamName = typeof input.event.teamName === 'string' ? input.event.teamName.trim() : '';
if (!eventTeamName) {
return reject('missing_team', 'Native app-managed bootstrap proof is missing teamName');
}
if (eventTeamName !== input.expected.teamName) {
return reject('wrong_team', 'Native app-managed bootstrap proof teamName does not match');
}
if (input.expected.proofMode !== 'native_app_managed_context') {
return reject('wrong_proof_mode', 'Native app-managed bootstrap proof mode is not expected');
}
const tokenFailure = validateExpectedProofToken(input);
if (tokenFailure) {
return tokenFailure;
}
if (!input.expected.proofToken) {
return reject('missing_token', 'Native app-managed bootstrap expected proof token is missing');
}
const runId = readProofField(input.event, input.detail, 'runId');
if (!input.expected.runId || !runId) {
return reject('missing_run_id', 'Native app-managed bootstrap runId is missing');
}
if (runId !== input.expected.runId) {
return reject('run_id_mismatch', 'Native app-managed bootstrap runId does not match');
}
const contextHash = readProofField(input.event, input.detail, 'contextHash');
const briefingHash = readProofField(input.event, input.detail, 'briefingHash');
if (
!input.expected.contextHash ||
!input.expected.briefingHash ||
!contextHash ||
!briefingHash
) {
return reject('missing_hash', 'Native app-managed bootstrap proof hash metadata is missing');
}
if (contextHash !== input.expected.contextHash || briefingHash !== input.expected.briefingHash) {
return reject('hash_mismatch', 'Native app-managed bootstrap proof hashes do not match');
}
return { ok: true, source: NATIVE_APP_MANAGED_BOOTSTRAP_PROOF_SOURCE };
}
const BOOTSTRAP_PROOF_VALIDATORS: Record<
BootstrapProofSource,
(input: {
event: BootstrapRuntimeProofEventLike;
detail: Record<string, unknown>;
expected: BootstrapRuntimeProofExpected;
}) => BootstrapProofValidationResult
> = {
[LEGACY_MEMBER_BRIEFING_BOOTSTRAP_PROOF_SOURCE]: validateLegacyMemberBriefingProof,
[NATIVE_APP_MANAGED_BOOTSTRAP_PROOF_SOURCE]: validateNativeAppManagedProof,
};
export function validateBootstrapRuntimeProofEnvelopeDetailed(input: {
event: BootstrapRuntimeProofEventLike;
detail?: Record<string, unknown>;
expected: BootstrapRuntimeProofExpected;
}): BootstrapProofValidationResult {
const { event, expected } = input;
const detail = input.detail ?? parseBootstrapRuntimeProofDetail(event.detail);
if (event.type !== 'bootstrap_confirmed') {
return reject('wrong_event_type', 'Runtime event is not bootstrap_confirmed');
}
if (typeof event.teamName === 'string' && event.teamName.trim() !== expected.teamName) {
return reject('wrong_team', 'Bootstrap proof teamName does not match');
}
const timestamp = typeof event.timestamp === 'string' ? event.timestamp : '';
const eventMs = Date.parse(timestamp);
if (
Number.isFinite(expected.boundaryMs) &&
(!Number.isFinite(eventMs) || eventMs < expected.boundaryMs)
) {
return reject('stale_timestamp', 'Bootstrap proof timestamp is older than the current attempt');
}
const source = getBootstrapProofSource(event, detail);
if (!source) {
return reject('unsupported_source', 'Bootstrap proof source is missing or unsupported');
}
return BOOTSTRAP_PROOF_VALIDATORS[source]({ event, detail, expected });
}
export function validateBootstrapRuntimeProofEnvelope(input: {
event: BootstrapRuntimeProofEventLike;
detail?: Record<string, unknown>;
expected: BootstrapRuntimeProofExpected;
}): boolean {
return validateBootstrapRuntimeProofEnvelopeDetailed(input).ok;
}