Files
2026-07-13 12:22:33 +08:00

79 lines
3.5 KiB
Swift

import Foundation
/// Resolves Bedrock signing credentials + region for the configured auth mode.
///
/// Shared by the main usage fetch (`BedrockAPIFetchStrategy`) and the daily
/// cost-history refresh (`CostUsageFetcher`) so both honor AWS-profile auth
/// identically instead of the history path silently requiring static keys.
enum BedrockCredentialResolver {
struct Resolved {
let credentials: BedrockAWSSigner.Credentials
let region: String
}
static func resolve(
environment: [String: String],
resolveAWSBinary: ([String: String]) -> String? = { BinaryLocator.resolveAWSBinary(env: $0) },
makeProvider: (String) -> BedrockProfileCredentialProvider = {
BedrockProfileCredentialProvider.live(awsBinaryPath: $0)
}) async throws -> Resolved
{
switch BedrockSettingsReader.authMode(environment: environment) {
case .keys:
guard let accessKeyID = BedrockSettingsReader.accessKeyID(environment: environment),
let secretAccessKey = BedrockSettingsReader.secretAccessKey(environment: environment)
else {
throw BedrockUsageError.missingCredentials
}
let credentials = BedrockAWSSigner.Credentials(
accessKeyID: accessKeyID,
secretAccessKey: secretAccessKey,
sessionToken: BedrockSettingsReader.sessionToken(environment: environment))
return Resolved(
credentials: credentials,
region: BedrockSettingsReader.region(environment: environment))
case .profile:
guard let profile = BedrockSettingsReader.profile(environment: environment) else {
throw BedrockUsageError.missingCredentials
}
guard let awsBinary = resolveAWSBinary(environment) else {
throw BedrockUsageError.awsCLINotFound
}
let cliEnvironment = Self.profileCLIEnvironment(environment)
let provider = makeProvider(awsBinary)
let credentials = try await provider.exportCredentials(profile: profile, environment: cliEnvironment)
let region = try await Self.resolveRegion(
provider: provider,
profile: profile,
environment: cliEnvironment)
return Resolved(credentials: credentials, region: region)
}
}
private static func profileCLIEnvironment(_ environment: [String: String]) -> [String: String] {
var cliEnvironment = environment
// `--profile` selects the requested profile. Leaving AWS_PROFILE set can
// break assume-role profiles that use `credential_source = Environment`;
// keep the source credential variables themselves available.
cliEnvironment[BedrockSettingsReader.profileKey] = nil
return cliEnvironment
}
private static func resolveRegion(
provider: BedrockProfileCredentialProvider,
profile: String,
environment: [String: String]) async throws -> String
{
if let explicit = BedrockSettingsReader.cleaned(environment[BedrockSettingsReader.regionKeys[0]])
?? BedrockSettingsReader.cleaned(environment[BedrockSettingsReader.regionKeys[1]])
{
return explicit
}
if let derived = try await provider.resolveRegion(profile: profile, environment: environment) {
return derived
}
return BedrockSettingsReader.defaultRegion
}
}