79 lines
3.5 KiB
Swift
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
|
|
}
|
|
}
|