/** * ADR-0027: org-scoped capability credential resolver. Reuses the ADR-0024 * envelope decryption machinery (LocalSecretEnvelope) with * purpose="capability", distinct from the model-provider and Feishu * application connections. Fail-closed: no process-global fallback. * * Mirrors the Feishu application connection resolver shape, minus the * readiness probe (capability probes are per-capability and injected by the * adapter wiring, not this resolver). */ import type { PrismaClient } from "@prisma/client"; import { LocalSecretEnvelope, type SecretEnvelopeV1 } from "../security/secretEnvelope.js"; import { CapabilityConnectionUnavailable, type CapabilitySecretPayload, type CapabilityId, } from "./types.js"; const CAPABILITY_PURPOSE = "capability"; export interface ResolvedCapabilityCredential extends CapabilitySecretPayload { readonly connectionId: string; readonly organizationId: string; readonly capabilityId: string; } /** * Resolve the active capability credential for an organization. Throws * CapabilityConnectionUnavailable when the org has no ACTIVE connection * (fail-closed, ADR-0024). Decrypted plaintext exists only in the returned * object for the duration of the capability call; it is never cached, logged, * or passed to the Agent process. */ export async function resolveCapabilityCredential( prisma: PrismaClient, secrets: LocalSecretEnvelope, input: { readonly organizationId: string; readonly capabilityId: CapabilityId }, ): Promise { const connection = await prisma.organizationCapabilityConnection.findFirst({ where: { organizationId: input.organizationId, capabilityId: input.capabilityId, status: "ACTIVE", }, include: { activeSecretVersion: true }, }); if (connection === null || connection.activeSecretVersion === null) { throw new CapabilityConnectionUnavailable(input.capabilityId, input.organizationId); } const version = connection.activeSecretVersion; const binding = { purpose: CAPABILITY_PURPOSE, organizationId: connection.organizationId, connectionId: connection.id, secretVersionId: version.id, }; const payload = secrets.decryptJson(binding, version.envelope as unknown as SecretEnvelopeV1); if (payload.schemaVersion !== 1) { throw new Error(`unsupported capability secret schemaVersion: ${payload.schemaVersion}`); } return { connectionId: connection.id, organizationId: connection.organizationId, capabilityId: connection.capabilityId, schemaVersion: 1, accessKeyId: payload.accessKeyId, accessKeySecret: payload.accessKeySecret, endpoint: payload.endpoint, }; }