Files
openmaic/OpenMAIC/lib/server/provider-access-policy.ts
2026-08-16 14:58:47 +08:00

64 lines
1.9 KiB
TypeScript

import type { DeploymentRole } from '@/lib/config/deployment-role';
export const SERVER_MANAGED_PROVIDER_REQUIRED_MESSAGE =
'This deployment only permits providers configured by the server operator.';
export type ProviderAccessDecision =
| {
allowed: true;
/** Managed credentials and endpoints are authoritative over client input. */
acceptClientConfiguration: boolean;
}
| {
allowed: false;
reason: 'server-managed-provider-required';
};
/**
* Pure deployment policy for provider-backed network calls.
*
* A dedicated public server must never turn a caller-supplied key/base URL into
* an outbound request. Other roles keep the desktop/operations BYOK behaviour,
* while an operator-configured provider remains authoritative in every role.
*/
export function decideProviderAccess(
role: DeploymentRole,
isServerConfigured: boolean,
): ProviderAccessDecision {
if (role === 'server' && !isServerConfigured) {
return { allowed: false, reason: 'server-managed-provider-required' };
}
return {
allowed: true,
acceptClientConfiguration: !isServerConfigured,
};
}
export class ServerManagedProviderRequiredError extends Error {
readonly statusCode = 403;
readonly errorCode = 'FORBIDDEN';
constructor() {
super(SERVER_MANAGED_PROVIDER_REQUIRED_MESSAGE);
this.name = 'ServerManagedProviderRequiredError';
}
}
export function assertProviderAccess(
role: DeploymentRole,
isServerConfigured: boolean,
): Extract<ProviderAccessDecision, { allowed: true }> {
const decision = decideProviderAccess(role, isServerConfigured);
if (!decision.allowed) {
throw new ServerManagedProviderRequiredError();
}
return decision;
}
export function isServerManagedProviderRequiredError(
error: unknown,
): error is ServerManagedProviderRequiredError {
return error instanceof ServerManagedProviderRequiredError;
}