Skip to content

Commit 7a77db8

Browse files
sichanyooSichan Yoo
andauthored
feat: STS web identity creds resolver (#933)
* Add visibility setting to SwiftSettings. * ktlint & build errors. * Limit visibility of generated types that aren't nested within service client. * Add access level logic to make model-based auth scheme resolver internal even when service isn't rules-based, if service client visibility is internal. * ktlint * Codegen changes for constructing & saving IdentityResolvingSTSClient into auth options returned by auth scheme resolver. * Add back logic for directly nesting auth option constructino in auth option append function if it's noAuth. * ktlint * Update codegen test. * Add forProtocolTests flag to SwiftSettings, to skip auth option customization w/ internal service clients for protocol test codegen. * Add new setting to SwiftSettings codegen test. --------- Co-authored-by: Sichan Yoo <[email protected]>
1 parent 60acf57 commit 7a77db8

File tree

11 files changed

+94
-45
lines changed

11 files changed

+94
-45
lines changed

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/AuthSchemeResolverGenerator.kt

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.ShapeId
1010
import software.amazon.smithy.model.traits.AuthTrait
1111
import software.amazon.smithy.model.traits.OptionalAuthTrait
1212
import software.amazon.smithy.model.traits.Trait
13+
import software.amazon.smithy.model.traits.synthetic.NoAuthTrait
1314
import software.amazon.smithy.rulesengine.language.EndpointRuleSet
1415
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter
1516
import software.amazon.smithy.rulesengine.language.syntax.parameters.ParameterType
@@ -26,7 +27,9 @@ import software.amazon.smithy.swift.codegen.utils.clientName
2627
import software.amazon.smithy.swift.codegen.utils.toLowerCamelCase
2728
import java.util.Locale
2829

29-
class AuthSchemeResolverGenerator {
30+
class AuthSchemeResolverGenerator(
31+
private val optionCustomization: ((String, SwiftWriter) -> SwiftWriter)? = null,
32+
) {
3033
fun render(ctx: ProtocolGenerator.GenerationContext) {
3134
val serviceIndex = ServiceIndex(ctx.model)
3235

@@ -47,7 +50,7 @@ class AuthSchemeResolverGenerator {
4750
) {
4851
writer.apply {
4952
openBlock(
50-
"public struct ${getSdkId(ctx)}${SmithyHTTPAuthAPITypes.AuthSchemeResolverParams.name}: \$N {",
53+
"${ctx.settings.visibility} struct ${getSdkId(ctx)}${SmithyHTTPAuthAPITypes.AuthSchemeResolverParams.name}: \$N {",
5154
"}",
5255
SmithyHTTPAuthAPITypes.AuthSchemeResolverParams,
5356
) {
@@ -96,7 +99,7 @@ class AuthSchemeResolverGenerator {
9699
) {
97100
writer.apply {
98101
openBlock(
99-
"public protocol ${getServiceSpecificAuthSchemeResolverName(ctx)}: \$N {",
102+
"${ctx.settings.visibility} protocol ${getServiceSpecificAuthSchemeResolverName(ctx)}: \$N {",
100103
"}",
101104
SmithyHTTPAuthAPITypes.AuthSchemeResolver,
102105
) {
@@ -127,13 +130,19 @@ class AuthSchemeResolverGenerator {
127130

128131
// Model-based auth scheme resolver should be private internal impl detail if service uses rules-based resolver.
129132
val accessModifier = if (usesRulesBasedResolver) "private" else "public"
133+
val resolvedAccessModifier =
134+
if (accessModifier == "public" && ctx.settings.visibility == "internal") {
135+
ctx.settings.visibility
136+
} else {
137+
accessModifier
138+
}
130139
val serviceSpecificAuthResolverProtocol = sdkId + AUTH_SCHEME_RESOLVER
131140

132141
writer.apply {
133142
writer.openBlock(
134143
"\$L struct \$L: \$L {",
135144
"}",
136-
accessModifier,
145+
resolvedAccessModifier,
137146
defaultResolverName,
138147
serviceSpecificAuthResolverProtocol,
139148
) {
@@ -240,35 +249,50 @@ class AuthSchemeResolverGenerator {
240249
writer.apply {
241250
indent()
242251
schemes.forEach {
243-
if (it.key == SigV4Trait.ID) {
244-
renderSigV4AuthOption(it, writer)
245-
} else {
252+
if (it.key == NoAuthTrait.ID) {
246253
write(
247254
"validAuthOptions.append(\$N(schemeID: \$S))",
248255
SmithyHTTPAuthAPITypes.AuthOption,
249256
it.key,
250257
)
258+
} else {
259+
renderAuthOption(it, writer)
251260
}
252261
}
253262
dedent()
254263
}
255264
}
256265

257-
private fun renderSigV4AuthOption(
266+
private fun renderAuthOption(
267+
scheme: Map.Entry<ShapeId, Trait>,
268+
writer: SwiftWriter,
269+
) {
270+
writer.apply {
271+
val authOptionName = "${scheme.key.name}Option"
272+
write("var $authOptionName = \$N(schemeID: \$S)", SmithyHTTPAuthAPITypes.AuthOption, scheme.key)
273+
if (scheme.key == SigV4Trait.ID) renderSigV4AuthOptionCustomization(authOptionName, scheme, writer)
274+
optionCustomization?.invoke(authOptionName, writer)
275+
write("validAuthOptions.append($authOptionName)")
276+
}
277+
}
278+
279+
private fun renderSigV4AuthOptionCustomization(
280+
authOptionName: String,
258281
scheme: Map.Entry<ShapeId, Trait>,
259282
writer: SwiftWriter,
260283
) {
261284
writer.apply {
262-
write("var sigV4Option = \$N(schemeID: \$S)", SmithyHTTPAuthAPITypes.AuthOption, scheme.key)
263285
write(
264-
"sigV4Option.signingProperties.set(key: \$N.signingName, value: \"${(scheme.value as SigV4Trait).name}\")",
286+
"$authOptionName.signingProperties.set(key: \$N.signingName, value: \"${(scheme.value as SigV4Trait).name}\")",
265287
SmithyHTTPAuthAPITypes.SigningPropertyKeys,
266288
)
267289
openBlock("guard let region = serviceParams.region else {", "}") {
268290
write("throw \$N.authError(\"Missing region in auth scheme parameters for SigV4 auth scheme.\")", SmithyTypes.ClientError)
269291
}
270-
write("sigV4Option.signingProperties.set(key: \$N.signingRegion, value: region)", SmithyHTTPAuthAPITypes.SigningPropertyKeys)
271-
write("validAuthOptions.append(sigV4Option)")
292+
write(
293+
"$authOptionName.signingProperties.set(key: \$N.signingRegion, value: region)",
294+
SmithyHTTPAuthAPITypes.SigningPropertyKeys,
295+
)
272296
}
273297
}
274298

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/EnumGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class EnumGenerator(
142142
writer.writeShapeDocs(shape)
143143
writer.writeAvailableAttribute(null, shape)
144144
writer.openBlock(
145-
"public enum \$enum.name:L: \$N, \$N, \$N, \$N, \$N {",
145+
"${settings.visibility} enum \$enum.name:L: \$N, \$N, \$N, \$N, \$N {",
146146
"}",
147147
SwiftTypes.Protocols.Sendable,
148148
SwiftTypes.Protocols.Equatable,

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/IntEnumGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class IntEnumGenerator(
4242
writer.writeShapeDocs(shape)
4343
writer.writeAvailableAttribute(null, shape)
4444
writer.openBlock(
45-
"public enum \$enum.name:L: \$N, \$N, \$N, \$N, \$N {",
45+
"${settings.visibility} enum \$enum.name:L: \$N, \$N, \$N, \$N, \$N {",
4646
"}",
4747
SwiftTypes.Protocols.Sendable,
4848
SwiftTypes.Protocols.Equatable,

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ServiceNamespaceIntegration.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ServiceNamespaceIntegration : SwiftIntegration {
2222
val namespaceName = service.nestedNamespaceType(ctx.symbolProvider).name
2323
val filename = ModelFileUtils.filename(ctx.settings, namespaceName)
2424
delegator.useFileWriter(filename) { writer ->
25-
writer.write("public enum \$L {}", namespaceName)
25+
writer.write("${ctx.settings.visibility} enum \$L {}", namespaceName)
2626
}
2727
}
2828
}

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/StructureGenerator.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class StructureGenerator(
118118
val equatableConformance =
119119
writer.format(", \$N", SwiftTypes.Protocols.Equatable).takeIf { shape.hasTrait<EquatableConformanceTrait>() } ?: ""
120120
writer
121-
.openBlock("public struct \$struct.name:L: \$N$equatableConformance {", SwiftTypes.Protocols.Sendable)
121+
.openBlock("${settings.visibility} struct \$struct.name:L: \$N$equatableConformance {", SwiftTypes.Protocols.Sendable)
122122
.call { generateStructMembers() }
123123
.write("")
124124
.call { generateInitializerForStructure(false) }
@@ -220,7 +220,7 @@ class StructureGenerator(
220220
writer.writeAvailableAttribute(model, shape)
221221
writer
222222
.openBlock(
223-
"public struct \$struct.name:L: \$N, \$error.protocol:N, \$N, \$N, \$N {",
223+
"${settings.visibility} struct \$struct.name:L: \$N, \$error.protocol:N, \$N, \$N, \$N {",
224224
ClientRuntimeTypes.Core.ModeledError,
225225
ClientRuntimeTypes.Http.HttpError,
226226
SwiftTypes.Error,
@@ -239,7 +239,7 @@ class StructureGenerator(
239239
private fun generateErrorStructMembers() {
240240
if (membersSortedByName.isNotEmpty()) {
241241
writer.write("")
242-
writer.openBlock("public struct Properties: \$N {", "}", SwiftTypes.Protocols.Sendable) {
242+
writer.openBlock("${settings.visibility} struct Properties: \$N {", "}", SwiftTypes.Protocols.Sendable) {
243243
membersSortedByName.forEach {
244244
val (memberName, memberSymbol) = memberShapeDataContainer.getOrElse(it) { return@forEach }
245245
writer.writeMemberDocs(model, it)

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/SwiftSettings.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ private const val GIT_REPO = "gitRepo"
3636
private const val SWIFT_VERSION = "swiftVersion"
3737
private const val MERGE_MODELS = "mergeModels"
3838
private const val COPYRIGHT_NOTICE = "copyrightNotice"
39+
private const val VISIBILITY = "visibility"
40+
private const val FOR_PROTOCOL_TESTS = "forProtocolTests"
3941

4042
// Prioritized list of protocols supported for code generation
4143
private val DEFAULT_PROTOCOL_RESOLUTION_PRIORITY =
@@ -61,6 +63,8 @@ class SwiftSettings(
6163
val swiftVersion: String,
6264
val mergeModels: Boolean,
6365
val copyrightNotice: String,
66+
val visibility: String,
67+
val forProtocolTests: Boolean,
6468
) {
6569
companion object {
6670
private val LOGGER: Logger = Logger.getLogger(SwiftSettings::class.java.name)
@@ -90,6 +94,8 @@ class SwiftSettings(
9094
SWIFT_VERSION,
9195
MERGE_MODELS,
9296
COPYRIGHT_NOTICE,
97+
VISIBILITY,
98+
FOR_PROTOCOL_TESTS,
9399
),
94100
)
95101

@@ -113,6 +119,8 @@ class SwiftSettings(
113119
COPYRIGHT_NOTICE,
114120
"// Code generated by smithy-swift-codegen. DO NOT EDIT!\n\n",
115121
)
122+
val visibility = config.getStringMemberOrDefault(VISIBILITY, "public")
123+
val forProtocolTests = config.getBooleanMemberOrDefault(FOR_PROTOCOL_TESTS, false)
116124

117125
return SwiftSettings(
118126
serviceId,
@@ -126,6 +134,8 @@ class SwiftSettings(
126134
swiftVersion,
127135
mergeModels,
128136
copyrightNotice,
137+
visibility,
138+
forProtocolTests,
129139
)
130140
}
131141

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/endpoints/EndpointParamsGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class EndpointParamsGenerator(
4141
writer: SwiftWriter,
4242
endpointRuleSet: EndpointRuleSet?,
4343
) {
44-
writer.openBlock("public struct EndpointParams: Sendable {", "}") {
44+
writer.openBlock("${ctx.settings.visibility} struct EndpointParams: Sendable {", "}") {
4545
endpointRuleSet?.parameters?.toList()?.sortedBy { it.name.toString() }?.let { sortedParameters ->
4646
renderMembers(writer, sortedParameters)
4747
writer.write("")

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/endpoints/EndpointResolverGenerator.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,19 @@ class EndpointResolverGenerator(
2626
val ruleSet = if (ruleSetNode != null) EndpointRuleSet.fromNode(ruleSetNode) else null
2727

2828
ctx.delegator.useFileWriter("Sources/${ctx.settings.moduleName}/Endpoints.swift") {
29-
renderResolverProtocol(it)
29+
renderResolverProtocol(it, ctx.settings.visibility)
3030
it.write("")
3131
renderResolver(it, ruleSet)
3232
renderStaticResolver(it)
3333
it.write("")
3434
}
3535
}
3636

37-
private fun renderResolverProtocol(writer: SwiftWriter) {
38-
writer.openBlock("public protocol \$N {", "}", EndpointTypes.EndpointResolver) {
37+
private fun renderResolverProtocol(
38+
writer: SwiftWriter,
39+
visibility: String,
40+
) {
41+
writer.openBlock("$visibility protocol \$N {", "}", EndpointTypes.EndpointResolver) {
3942
writer.write("func resolve(params: EndpointParams) throws -> \$N", SmithyHTTPAPITypes.Endpoint)
4043
}
4144
}

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/HttpProtocolServiceClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ open class HttpProtocolServiceClient(
2424

2525
fun render(serviceSymbol: Symbol) {
2626
writer.openBlock(
27-
"public class \$L: \$N {",
27+
"${ctx.settings.visibility} class \$L: \$N {",
2828
"}",
2929
serviceSymbol.name,
3030
ClientRuntimeTypes.Core.Client,

smithy-swift-codegen/src/test/kotlin/software/amazon/smithy/swift/codegen/codegencomponents/SwiftSettingsTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ class SwiftSettingsTest {
191191
swiftVersion = "5.7",
192192
mergeModels = false,
193193
copyrightNotice = "// Test copyright",
194+
visibility = "public",
195+
forProtocolTests = false,
194196
)
195197

196198
private fun createServiceWithProtocols(protocols: Set<ShapeId>): ServiceShape {

0 commit comments

Comments
 (0)