feat: add provider profile removal

This commit is contained in:
Codex
2026-06-08 05:29:11 +08:00
parent 509c2aa6fd
commit 601d8190d0
8 changed files with 121 additions and 12 deletions
+42
View File
@@ -75,6 +75,37 @@ export async function getProviderProfileConfig(profileValue: string, options: Pr
};
}
export async function removeProviderProfile(profileValue: string, options: ProviderProfileOptions = {}): Promise<JsonRecord> {
const profile = validateBackendProfile(profileValue);
const spec = requiredSpec(profile);
const namespace = profileNamespace(options);
const secret = await kubectlGetSecret(spec.defaultSecretName, namespace, options.kubectlCommand ?? "kubectl");
const data = asOptionalRecord(secret?.data);
const annotations = asOptionalRecord(asOptionalRecord(secret?.metadata)?.annotations);
if (secret) await kubectlDeleteSecret(spec.defaultSecretName, namespace, options.kubectlCommand ?? "kubectl");
return {
action: "provider-profile-removed",
mutation: true,
profile,
configured: false,
removed: Boolean(secret),
...(secret ? {} : { alreadyAbsent: true }),
...(isBuiltinProviderProfile(profile) ? { builtinCapabilityRetained: true } : {}),
secretRef: secretRefSummary(profile, namespace),
deletedResourceVersion: stringPath(secret, ["metadata", "resourceVersion"]),
credentialHashSuffix: hashDataKey(data, "auth.json") ?? stringPath(annotations, [`${credentialAnnotationPrefix}-credential-hash-suffix`]),
configHashSuffix: hashDataKey(data, "config.toml") ?? stringPath(annotations, [`${credentialAnnotationPrefix}-config-hash-suffix`]),
updatedAt: new Date().toISOString(),
valuesPrinted: false,
pollCommands: {
list: "./scripts/agentrun provider-profiles list",
show: `./scripts/agentrun provider-profiles show ${profile}`,
setKey: `./scripts/agentrun provider-profiles set-key ${profile} --key-stdin`,
setConfig: `./scripts/agentrun provider-profiles set-config ${profile} --config-stdin`,
},
};
}
export async function setProviderProfileConfig(profileValue: string, body: unknown, options: ProviderProfileOptions = {}): Promise<JsonRecord> {
const profile = validateBackendProfile(profileValue);
const spec = requiredSpec(profile);
@@ -304,6 +335,10 @@ function compareProviderProfiles(left: string, right: string): number {
return left.localeCompare(right);
}
function isBuiltinProviderProfile(profile: BackendProfile): boolean {
return backendProfileSpecs.some((item) => item.profile === profile);
}
function providerProfileFromSecret(secret: JsonRecord): BackendProfile | null {
const metadata = asOptionalRecord(secret.metadata);
const labels = asOptionalRecord(metadata?.labels);
@@ -615,6 +650,13 @@ async function kubectlUpsertSecret(manifest: JsonRecord, kubectlCommand: string)
throw new AgentRunError("infra-failed", `kubectl replace provider profile secret ${namespace}/${name} failed with code ${replace.code}`, { httpStatus: 502, details: redactJson({ stderr: redactText(replace.stderr.slice(-2000)), stdout: redactText(replace.stdout.slice(-1000)) }) });
}
async function kubectlDeleteSecret(name: string, namespace: string, kubectlCommand: string): Promise<void> {
const result = await runKubectl(kubectlCommand, ["delete", "secret", name, "-n", namespace, "--ignore-not-found=true"]);
if (result.code !== 0) {
throw new AgentRunError("infra-failed", `kubectl delete provider profile secret ${namespace}/${name} failed with code ${result.code}`, { httpStatus: 502, details: redactJson({ stderr: redactText(result.stderr.slice(-2000)), stdout: redactText(result.stdout.slice(-1000)) }) });
}
}
function isKubectlNotFoundFailure(result: { stdout: string; stderr: string }): boolean {
return /notfound|not found|not-found/iu.test(`${result.stderr}\n${result.stdout}`);
}