Skip to content

chore: Refactor internal clients #952

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
// SPDX-License-Identifier: Apache-2.0
//

@_spi(ClientConfigDefaultIdentityResolver) import protocol SmithyIdentityAPI.ClientConfigDefaultIdentityResolver
import struct Smithy.Attributes

/// A credential identity resolver that provides a fixed set of credentials
public struct StaticAWSCredentialIdentityResolver: AWSCredentialIdentityResolver {
private let credentials: AWSCredentialIdentity
fileprivate let credentials: AWSCredentialIdentity

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @_spi initializer below creates a AWS credential identity resolver with empty credentials. This is used in internal clients, where the default AWS credential identity resolver is never used.

@_spi(StaticAWSCredentialIdentityResolver)
public init() {
self.credentials = AWSCredentialIdentity(accessKey: "", secret: "")
}

/// Creates a credential identity resolver for a fixed set of credentials
///
Expand All @@ -24,3 +30,11 @@ public struct StaticAWSCredentialIdentityResolver: AWSCredentialIdentityResolver
return credentials
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ClientConfigDefaultIdentityResolver extension below marks this resolver as a client config default if the credentials are empty, something that the new initializer above does, but a real customer should never do.

@_spi(ClientConfigDefaultIdentityResolver)
extension StaticAWSCredentialIdentityResolver: ClientConfigDefaultIdentityResolver {

public var isClientConfigDefault: Bool {
self.credentials.accessKey.isEmpty && self.credentials.secret.isEmpty
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
// SPDX-License-Identifier: Apache-2.0
//

@_spi(ClientConfigDefaultIdentityResolver) import protocol SmithyIdentityAPI.ClientConfigDefaultIdentityResolver
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty much the same changes in this StaticBearerTokenIdentityResolver as in the StaticAWSCredentialIdentityResolver just above.

import struct Smithy.Attributes

/// The token identity resolver that returns a static token identity given to it at initialization.
public struct StaticBearerTokenIdentityResolver: BearerTokenIdentityResolver {
private let token: BearerTokenIdentity
fileprivate let token: BearerTokenIdentity

@_spi(StaticBearerTokenIdentityResolver)
public init() {
self.token = BearerTokenIdentity(token: "")
}

public init(token: BearerTokenIdentity) {
self.token = token
Expand All @@ -19,3 +25,11 @@ public struct StaticBearerTokenIdentityResolver: BearerTokenIdentityResolver {
return token
}
}

@_spi(ClientConfigDefaultIdentityResolver)
extension StaticBearerTokenIdentityResolver: ClientConfigDefaultIdentityResolver {

public var isClientConfigDefault: Bool {
token.token.isEmpty
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// A protocol on identity resolver used to signify that this resolver is a default resolver created because the client config was not passed a custom resolver at creation.
///
/// Resolvers that do not implement this protocol should be presumed to not be a client config default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The protocol below is used to determine if a credential resolver came from client config defaults. It's protected with @_spi so it isn't visible to customers.

@_spi(ClientConfigDefaultIdentityResolver)
public protocol ClientConfigDefaultIdentityResolver: IdentityResolver {

/// Indicates whether this identity resolver was provided as a client config default.
var isClientConfigDefault: Bool { get }
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class AuthSchemeResolverGenerator(
// Model-based auth scheme resolver should be private internal impl detail if service uses rules-based resolver.
val accessModifier = if (usesRulesBasedResolver) "private" else "public"
val resolvedAccessModifier =
if (accessModifier == "public" && ctx.settings.visibility == "internal") {
if (accessModifier == "public" && ctx.settings.internalClient) {
ctx.settings.visibility
} else {
accessModifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,8 @@ class SwiftDependency(
"",
DistributionMethod.GIT,
)
val CRT =
SwiftDependency(
"AwsCommonRuntimeKit",
null,
"0.52.1",
"https://github.com/awslabs/aws-crt-swift",
"",
"aws-crt-swift",
DistributionMethod.GIT,
)
val CLIENT_RUNTIME = smithySwiftDependency("ClientRuntime")
val SMITHY = smithySwiftDependency("Smithy")
val SMITHY_IDENTITY_API = smithySwiftDependency("SmithyIdentityAPI")
val SMITHY_IDENTITY = smithySwiftDependency("SmithyIdentity")
val SMITHY_RETRIES_API = smithySwiftDependency("SmithyRetriesAPI")
val SMITHY_RETRIES = smithySwiftDependency("SmithyRetries")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ private const val SWIFT_VERSION = "swiftVersion"
private const val MERGE_MODELS = "mergeModels"
private const val COPYRIGHT_NOTICE = "copyrightNotice"
private const val VISIBILITY = "visibility"
private const val INTERNAL_CLIENT = "internalClient"
private const val FOR_PROTOCOL_TESTS = "forProtocolTests"

// Prioritized list of protocols supported for code generation
Expand Down Expand Up @@ -64,6 +65,7 @@ class SwiftSettings(
val mergeModels: Boolean,
val copyrightNotice: String,
val visibility: String,
val internalClient: Boolean,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this internalClient field to SwiftSettings to help make codegen more clear, i.e. can query this setting directly rather than rely on some string value of visibility.

val forProtocolTests: Boolean,
) {
companion object {
Expand Down Expand Up @@ -120,6 +122,7 @@ class SwiftSettings(
"// Code generated by smithy-swift-codegen. DO NOT EDIT!\n\n",
)
val visibility = config.getStringMemberOrDefault(VISIBILITY, "public")
val internalClient = config.getBooleanMemberOrDefault(INTERNAL_CLIENT, false)
val forProtocolTests = config.getBooleanMemberOrDefault(FOR_PROTOCOL_TESTS, false)

return SwiftSettings(
Expand All @@ -135,6 +138,7 @@ class SwiftSettings(
mergeModels,
copyrightNotice,
visibility,
internalClient,
forProtocolTests,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum class AccessModifier {
PublicPrivateSet,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of Swift 5.9 package is a Swift access modifier or "visibility" level.

Adding it to this enum along with the existing levels.

Internal,
Private,
Package,
None,
;

Expand All @@ -27,6 +28,7 @@ enum class AccessModifier {
PublicPrivateSet -> "public private(set)"
Internal -> "internal"
Private -> "private"
Package -> "package"
None -> ""
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ val reservedWords =
"operator",
"optional",
"override",
"package",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding package as a Swift reserved word so that it gets escaped with backticks in generated code.

There actually do seem to be services that already use package as an identifier without escaping it, but to date it seems not to cause any problems.

"postfix",
"prefix",
"private",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ private fun runtimeSymbol(
name: String,
declaration: SwiftDeclaration?,
additionalImports: List<Symbol> = emptyList(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just fixed a typo in this file

spiName: List<String> = emptyList(),
spiNames: List<String> = emptyList(),
): Symbol =
SwiftSymbol.make(
name,
declaration,
SwiftDependency.CLIENT_RUNTIME.takeIf { additionalImports.isEmpty() },
additionalImports,
spiName,
spiNames,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ import software.amazon.smithy.swift.codegen.SwiftDeclaration
import software.amazon.smithy.swift.codegen.SwiftDependency

object SmithyIdentityTypes {
val AWSCredentialIdentityResolver = runtimeSymbol("AWSCredentialIdentityResolver", SwiftDeclaration.PROTOCOL)
val AWSCredentialIdentityResolver =
runtimeSymbol("AWSCredentialIdentityResolver", SwiftDeclaration.PROTOCOL, listOf("AWSCredentialIdentityResolver"))
val BearerTokenIdentityResolver = runtimeSymbol("BearerTokenIdentityResolver", SwiftDeclaration.PROTOCOL)
val BearerTokenIdentity = runtimeSymbol("BearerTokenIdentity", SwiftDeclaration.STRUCT)
val StaticBearerTokenIdentityResolver = runtimeSymbol("StaticBearerTokenIdentityResolver", SwiftDeclaration.STRUCT)
val StaticAWSCredentialIdentityResolver = runtimeSymbol("StaticAWSCredentialIdentityResolver", SwiftDeclaration.STRUCT)
val StaticAWSCredentialIdentityResolver =
runtimeSymbol("StaticAWSCredentialIdentityResolver", SwiftDeclaration.STRUCT, listOf("StaticAWSCredentialIdentityResolver"))
val StaticBearerTokenIdentityResolver =
runtimeSymbol("StaticBearerTokenIdentityResolver", SwiftDeclaration.STRUCT, listOf("StaticBearerTokenIdentityResolver"))
}

private fun runtimeSymbol(
name: String,
declaration: SwiftDeclaration? = null,
spiNames: List<String> = listOf(),
): Symbol =
SwiftSymbol.make(
name,
declaration,
SwiftDependency.SMITHY_IDENTITY,
emptyList(),
emptyList(),
spiNames,
)
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class SwiftSettingsTest {
assertEquals("Amazon Web Services", settings.author)
assertEquals("https://github.com/aws-amplify/amplify-codegen.git", settings.gitRepo)
assertEquals(false, settings.mergeModels)
assertEquals(false, settings.internalClient)
}

// Smithy Protocol Selection Tests
Expand Down Expand Up @@ -193,6 +194,7 @@ class SwiftSettingsTest {
copyrightNotice = "// Test copyright",
visibility = "public",
forProtocolTests = false,
internalClient = false,
)

private fun createServiceWithProtocols(protocols: Set<ShapeId>): ServiceShape {
Expand Down
Loading