Files
steipete--codexbar/Tests/CodexBarTests/BedrockCredentialResolverTests.swift
2026-07-13 12:22:33 +08:00

140 lines
5.7 KiB
Swift

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() })
}
}
}