import Foundationimport Testing@testable import CodexBarCore private final class CapturedEnvironment: @unchecked Sendable { private let lock = NSLock() private var stored: [String: String] = [:] func record(_ environment: [String: String]) { self.lock.withLock { self.stored = environment } } var value: [String: String] { self.lock.withLock { self.stored } }} @Suite(.serialized)struct BedrockCredentialResolverTests { private static let credentialsJSON = #""" {"Version":1,"AccessKeyId":"AKIAPROFILE","SecretAccessKey":"profile-secret","SessionToken":"profile-token"} """# /// Fake AWS CLI runner: returns exported credentials and a profile region. private func profileProvider(region: String = "ap-southeast-2") -> BedrockProfileCredentialProvider { BedrockProfileCredentialProvider(awsBinaryPath: "/usr/bin/aws") { arguments, _ in if arguments.contains("export-credentials") { return SubprocessResult(stdout: Self.credentialsJSON, stderr: "") } if arguments.contains("get") { return SubprocessResult(stdout: region + "\n", stderr: "") } return SubprocessResult(stdout: "", stderr: "") } } @Test func `keys mode resolves static credentials and region`() async throws { let env = [ BedrockSettingsReader.accessKeyIDKey: "AKIAKEYS", BedrockSettingsReader.secretAccessKeyKey: "keys-secret", BedrockSettingsReader.regionKeys[0]: "us-west-2", ] let resolved = try await BedrockCredentialResolver.resolve(environment: env) #expect(resolved.credentials.accessKeyID == "AKIAKEYS") #expect(resolved.credentials.secretAccessKey == "keys-secret") #expect(resolved.region == "us-west-2") } @Test func `keys mode without credentials throws missingCredentials`() async { await #expect(throws: BedrockUsageError.missingCredentials) { try await BedrockCredentialResolver.resolve(environment: [:]) } } @Test func `profile mode resolves credentials via the AWS CLI`() async throws { let env = [ BedrockSettingsReader.authModeKey: "profile", BedrockSettingsReader.profileKey: "work", ] let resolved = try await BedrockCredentialResolver.resolve( environment: env, resolveAWSBinary: { _ in "/usr/bin/aws" }, makeProvider: { _ in self.profileProvider() }) #expect(resolved.credentials.accessKeyID == "AKIAPROFILE") #expect(resolved.credentials.sessionToken == "profile-token") // No explicit region in env, so it is derived from the profile. #expect(resolved.region == "ap-southeast-2") } @Test func `profile mode prefers explicit region over the profile region`() async throws { let env = [ BedrockSettingsReader.authModeKey: "profile", BedrockSettingsReader.profileKey: "work", BedrockSettingsReader.regionKeys[0]: "eu-central-1", ] let resolved = try await BedrockCredentialResolver.resolve( environment: env, resolveAWSBinary: { _ in "/usr/bin/aws" }, makeProvider: { _ in self.profileProvider() }) #expect(resolved.region == "eu-central-1") } @Test func `profile mode without a profile name throws missingCredentials`() async { let env = [BedrockSettingsReader.authModeKey: "profile"] await #expect(throws: BedrockUsageError.missingCredentials) { try await BedrockCredentialResolver.resolve( environment: env, resolveAWSBinary: { _ in "/usr/bin/aws" }, makeProvider: { _ in self.profileProvider() }) } } @Test func `profile mode preserves source credentials but removes AWS_PROFILE for AWS CLI`() async throws { let captured = CapturedEnvironment() let env = [ BedrockSettingsReader.authModeKey: "profile", BedrockSettingsReader.profileKey: "work", BedrockSettingsReader.accessKeyIDKey: "AKIAINHERITED", BedrockSettingsReader.secretAccessKeyKey: "inherited-secret", BedrockSettingsReader.sessionTokenKey: "inherited-token", ] _ = try await BedrockCredentialResolver.resolve( environment: env, resolveAWSBinary: { _ in "/usr/bin/aws" }, makeProvider: { _ in BedrockProfileCredentialProvider(awsBinaryPath: "/usr/bin/aws") { arguments, environment in captured.record(environment) if arguments.contains("export-credentials") { return SubprocessResult(stdout: Self.credentialsJSON, stderr: "") } return SubprocessResult(stdout: "us-east-1\n", stderr: "") } }) let seen = captured.value #expect(seen[BedrockSettingsReader.accessKeyIDKey] == "AKIAINHERITED") #expect(seen[BedrockSettingsReader.secretAccessKeyKey] == "inherited-secret") #expect(seen[BedrockSettingsReader.sessionTokenKey] == "inherited-token") #expect(seen[BedrockSettingsReader.profileKey] == nil) } @Test func `profile mode without the AWS CLI throws awsCLINotFound`() async { let env = [ BedrockSettingsReader.authModeKey: "profile", BedrockSettingsReader.profileKey: "work", ] await #expect(throws: BedrockUsageError.awsCLINotFound) { try await BedrockCredentialResolver.resolve( environment: env, resolveAWSBinary: { _ in nil }, makeProvider: { _ in self.profileProvider() }) } }}
import Foundation
import Testing
@testable import CodexBarCore
private final class CapturedEnvironment: @unchecked Sendable {
private let lock = NSLock()
private var stored: [String: String] = [:]
func record(_ environment: [String: String]) {
self.lock.withLock { self.stored = environment }
}
var value: [String: String] {
self.lock.withLock { self.stored }
}
}
@Suite(.serialized)
struct BedrockCredentialResolverTests {
private static let credentialsJSON = #"""
{"Version":1,"AccessKeyId":"AKIAPROFILE","SecretAccessKey":"profile-secret","SessionToken":"profile-token"}
"""#
/// Fake AWS CLI runner: returns exported credentials and a profile region.
private func profileProvider(region: String = "ap-southeast-2") -> BedrockProfileCredentialProvider {
BedrockProfileCredentialProvider(awsBinaryPath: "/usr/bin/aws") { arguments, _ in
if arguments.contains("export-credentials") {
return SubprocessResult(stdout: Self.credentialsJSON, stderr: "")
}
if arguments.contains("get") {
return SubprocessResult(stdout: region + "\n", stderr: "")
}
return SubprocessResult(stdout: "", stderr: "")
}
}
@Test
func `keys mode resolves static credentials and region`() async throws {
let env = [
BedrockSettingsReader.accessKeyIDKey: "AKIAKEYS",
BedrockSettingsReader.secretAccessKeyKey: "keys-secret",
BedrockSettingsReader.regionKeys[0]: "us-west-2",
]
let resolved = try await BedrockCredentialResolver.resolve(environment: env)
#expect(resolved.credentials.accessKeyID == "AKIAKEYS")
#expect(resolved.credentials.secretAccessKey == "keys-secret")
#expect(resolved.region == "us-west-2")
}
@Test
func `keys mode without credentials throws missingCredentials`() async {
await #expect(throws: BedrockUsageError.missingCredentials) {
try await BedrockCredentialResolver.resolve(environment: [:])
}
}
@Test
func `profile mode resolves credentials via the AWS CLI`() async throws {
let env = [
BedrockSettingsReader.authModeKey: "profile",
BedrockSettingsReader.profileKey: "work",
]
let resolved = try await BedrockCredentialResolver.resolve(
environment: env,
resolveAWSBinary: { _ in "/usr/bin/aws" },
makeProvider: { _ in self.profileProvider() })
#expect(resolved.credentials.accessKeyID == "AKIAPROFILE")
#expect(resolved.credentials.sessionToken == "profile-token")
// No explicit region in env, so it is derived from the profile.
#expect(resolved.region == "ap-southeast-2")
}
@Test
func `profile mode prefers explicit region over the profile region`() async throws {
let env = [
BedrockSettingsReader.authModeKey: "profile",
BedrockSettingsReader.profileKey: "work",
BedrockSettingsReader.regionKeys[0]: "eu-central-1",
]
let resolved = try await BedrockCredentialResolver.resolve(
environment: env,
resolveAWSBinary: { _ in "/usr/bin/aws" },
makeProvider: { _ in self.profileProvider() })
#expect(resolved.region == "eu-central-1")
}
@Test
func `profile mode without a profile name throws missingCredentials`() async {
let env = [BedrockSettingsReader.authModeKey: "profile"]
await #expect(throws: BedrockUsageError.missingCredentials) {
try await BedrockCredentialResolver.resolve(
environment: env,
resolveAWSBinary: { _ in "/usr/bin/aws" },
makeProvider: { _ in self.profileProvider() })
}
}
@Test
func `profile mode preserves source credentials but removes AWS_PROFILE for AWS CLI`() async throws {
let captured = CapturedEnvironment()
let env = [
BedrockSettingsReader.authModeKey: "profile",
BedrockSettingsReader.profileKey: "work",
BedrockSettingsReader.accessKeyIDKey: "AKIAINHERITED",
BedrockSettingsReader.secretAccessKeyKey: "inherited-secret",
BedrockSettingsReader.sessionTokenKey: "inherited-token",
]
_ = try await BedrockCredentialResolver.resolve(
environment: env,
resolveAWSBinary: { _ in "/usr/bin/aws" },
makeProvider: { _ in
BedrockProfileCredentialProvider(awsBinaryPath: "/usr/bin/aws") { arguments, environment in
captured.record(environment)
if arguments.contains("export-credentials") {
return SubprocessResult(stdout: Self.credentialsJSON, stderr: "")
}
return SubprocessResult(stdout: "us-east-1\n", stderr: "")
}
})
let seen = captured.value
#expect(seen[BedrockSettingsReader.accessKeyIDKey] == "AKIAINHERITED")
#expect(seen[BedrockSettingsReader.secretAccessKeyKey] == "inherited-secret")
#expect(seen[BedrockSettingsReader.sessionTokenKey] == "inherited-token")
#expect(seen[BedrockSettingsReader.profileKey] == nil)
}
@Test
func `profile mode without the AWS CLI throws awsCLINotFound`() async {
let env = [
BedrockSettingsReader.authModeKey: "profile",
BedrockSettingsReader.profileKey: "work",
]
await #expect(throws: BedrockUsageError.awsCLINotFound) {
try await BedrockCredentialResolver.resolve(
environment: env,
resolveAWSBinary: { _ in nil },
makeProvider: { _ in self.profileProvider() })
}
}
}