mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 08:31:33 +00:00
* fix(secrets): degrade missing TTS SecretRefs at startup * test(secrets): keep non-activating startup strict * test(secrets): mark denied key fixture synthetic * test(secrets): use synthetic TTS key fixture * test(secrets): use neutral TTS key placeholder * test(secrets): isolate TTS key placeholder * test(secrets): shorten TTS ref fixture name * test(secrets): normalize synthetic credential fixtures * test(secrets): isolate optional redaction coverage * fix(secrets): preserve degraded TTS ref ownership * refactor(secrets): keep optional resolver internal * test(secrets): cover default provider alias misses * test(secrets): pin explicit provider ownership * style(secrets): format optional assignment imports * refactor(secrets): keep optional metadata private * style(secrets): restore collector file header * fix(secrets): isolate unavailable SecretRef owners Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com> * test(secrets): complete provider fixtures * style(status): avoid degraded path shadowing * style(secrets): satisfy runtime lint * refactor(secrets): keep error codes internal * fix(secrets): keep unowned assignments fail closed * fix(secrets): preserve provider resolution batching * fix(secrets): normalize stalled resolution errors * fix(secrets): reject provider limit violations --------- Co-authored-by: snowzlmbot <293528334+snowzlmbot@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
138 lines
4.4 KiB
TypeScript
138 lines
4.4 KiB
TypeScript
/** Typed errors for SecretRef provider and ref-level resolution failures. */
|
|
import type { SecretRef, SecretRefSource } from "../config/types.secrets.js";
|
|
|
|
type SecretRefResolutionCode =
|
|
| "SECRET_REF_NOT_FOUND"
|
|
| "SECRET_REF_POLICY_DENIED"
|
|
| "SECRET_REF_INVALID"
|
|
| "SECRET_REF_PROVIDER_ERROR"
|
|
| "SECRET_REF_PROVIDER_CONTRACT";
|
|
|
|
type SecretProviderResolutionCode = "SECRET_PROVIDER_INVALID" | "SECRET_PROVIDER_UNAVAILABLE";
|
|
|
|
/** Error for failures that affect an entire configured secret provider. */
|
|
class SecretProviderResolutionError extends Error {
|
|
readonly scope = "provider" as const;
|
|
readonly code: SecretProviderResolutionCode;
|
|
readonly source: SecretRefSource;
|
|
readonly provider: string;
|
|
|
|
constructor(params: {
|
|
code: SecretProviderResolutionCode;
|
|
source: SecretRefSource;
|
|
provider: string;
|
|
message: string;
|
|
cause?: unknown;
|
|
}) {
|
|
super(params.message, params.cause !== undefined ? { cause: params.cause } : undefined);
|
|
this.name = "SecretProviderResolutionError";
|
|
this.code = params.code;
|
|
this.source = params.source;
|
|
this.provider = params.provider;
|
|
}
|
|
}
|
|
|
|
/** Error for failures limited to one SecretRef id under a provider. */
|
|
class SecretRefResolutionError extends Error {
|
|
readonly scope = "ref" as const;
|
|
readonly code: SecretRefResolutionCode;
|
|
readonly source: SecretRefSource;
|
|
readonly provider: string;
|
|
readonly refId: string;
|
|
|
|
constructor(params: {
|
|
code: SecretRefResolutionCode;
|
|
source: SecretRefSource;
|
|
provider: string;
|
|
refId: string;
|
|
message: string;
|
|
cause?: unknown;
|
|
}) {
|
|
super(params.message, params.cause !== undefined ? { cause: params.cause } : undefined);
|
|
this.name = "SecretRefResolutionError";
|
|
this.code = params.code;
|
|
this.source = params.source;
|
|
this.provider = params.provider;
|
|
this.refId = params.refId;
|
|
}
|
|
}
|
|
|
|
/** Type guard for provider-scoped secret resolution failures. */
|
|
export function isProviderScopedSecretResolutionError(
|
|
value: unknown,
|
|
): value is SecretProviderResolutionError {
|
|
return value instanceof SecretProviderResolutionError;
|
|
}
|
|
|
|
export function isSecretResolutionError(
|
|
value: unknown,
|
|
): value is SecretProviderResolutionError | SecretRefResolutionError {
|
|
return (
|
|
value instanceof SecretProviderResolutionError || value instanceof SecretRefResolutionError
|
|
);
|
|
}
|
|
|
|
/** Redacted reason suitable for warnings and status output. */
|
|
export function describeSecretResolutionError(value: unknown): string | undefined {
|
|
if (value instanceof SecretProviderResolutionError) {
|
|
return value.code === "SECRET_PROVIDER_UNAVAILABLE" ? "secret provider failed" : undefined;
|
|
}
|
|
if (!(value instanceof SecretRefResolutionError)) {
|
|
return undefined;
|
|
}
|
|
switch (value.code) {
|
|
case "SECRET_REF_NOT_FOUND":
|
|
return "secret reference was not found";
|
|
case "SECRET_REF_POLICY_DENIED":
|
|
return "secret provider policy denied resolution";
|
|
case "SECRET_REF_PROVIDER_ERROR":
|
|
return "secret provider failed";
|
|
case "SECRET_REF_PROVIDER_CONTRACT":
|
|
return "secret provider response violated its contract";
|
|
case "SECRET_REF_INVALID":
|
|
return undefined;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function providerResolutionError(params: {
|
|
code?: SecretProviderResolutionCode;
|
|
source: SecretRefSource;
|
|
provider: string;
|
|
message: string;
|
|
cause?: unknown;
|
|
}): SecretProviderResolutionError {
|
|
return new SecretProviderResolutionError({
|
|
...params,
|
|
code: params.code ?? "SECRET_PROVIDER_UNAVAILABLE",
|
|
});
|
|
}
|
|
|
|
export function refResolutionError(params: {
|
|
code: SecretRefResolutionCode;
|
|
source: SecretRefSource;
|
|
provider: string;
|
|
refId: string;
|
|
message: string;
|
|
cause?: unknown;
|
|
}): SecretRefResolutionError {
|
|
return new SecretRefResolutionError(params);
|
|
}
|
|
|
|
/** Returns whether one SecretRef failed because its configured value is absent. */
|
|
export function isMissingSecretRefResolutionError(params: {
|
|
ref: SecretRef;
|
|
error: unknown;
|
|
}): boolean {
|
|
const refId = params.ref.id.trim();
|
|
// Canonical refs already own their provider identity. Config defaults only fill an omitted
|
|
// provider during coercion; resolution never rewrites an explicit provider such as "default".
|
|
return (
|
|
params.error instanceof SecretRefResolutionError &&
|
|
params.error.code === "SECRET_REF_NOT_FOUND" &&
|
|
params.error.source === params.ref.source &&
|
|
params.error.provider === params.ref.provider &&
|
|
params.error.refId === refId
|
|
);
|
|
}
|