Skip to content

Commit 081c63d

Browse files
author
Steven Yuan
committed
feat(experimentalIdentityAndAuth): add control branches for experimentalIdentityAndAuth
As part of feature development of `experimentalIdentityAndAuth`, add control branches for existing behavior in existing integrations, particularly `@aws.auth#sigv4` and `@httpBearerTokenAuth`: - `AddAwsAuthPlugin` - `AddAwsRuntimeConfig` - `AddBuiltinPlugins` - `AddEventBridgePlugin` - `AddS3Config` - `AddS3ControlDependency` - `AddTokenAuthPlugin` - `AddEventStreamHandlingDependency` Also, add a section in `CONTRIBUTING.md` about experimental features in `smithy-typescript` used in `aws-sdk-js-v3`.
1 parent f86ff34 commit 081c63d

File tree

9 files changed

+255
-199
lines changed

9 files changed

+255
-199
lines changed

CONTRIBUTING.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ smithy=/Volumes/workplace/smithy
142142
smithy-typescript=/Volumes/workplace/smithy-typescript
143143
```
144144

145+
## Experimental Features
146+
147+
`aws-sdk-js-v3 ` uses `smithy-typescript` to generate code. `smithy-typescript` is under heavy development and has
148+
experimental features that can affect `aws-sdk-js-v3`. These features are enabled via opt-in settings in `sdk-codegen`.
149+
Note that any contributions related to these features MUST be reviewed carefully for opt-in behavior via feature flags
150+
as to not break any existing customers. Here are the experimental features that are currently under development:
151+
152+
| Experimental Feature | Flag | Description |
153+
| -------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
154+
| Identity & Auth | `experimentalIdentityAndAuth` | Standardize identity and auth integrations to match the Smithy specification (see [Authentication Traits](https://smithy.io/2.0/spec/authentication-traits.html)). Newer capabilities include support for multiple auth schemes, `@optionalAuth`, and standardized identity interfaces for authentication schemes both in code generation and TypeScript packages. In `smithy-typescript`, `@httpApiKeyAuth` will be updated to use the new standardized interfaces. In `aws-sdk-js-v3` (`smithy-typescript`'s largest customer), this will affect `@aws.auth#sigv4` and `@httpBearerAuth` implementations, but is planned to be completely backwards-compatible. |
155+
145156
## Build caching
146157

147158
Build caching is optionally available via Turborepo. See `turbo.json`.

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsAuthPlugin.java

Lines changed: 96 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -72,39 +72,41 @@ public void addConfigInterfaceFields(
7272
SymbolProvider symbolProvider,
7373
TypeScriptWriter writer
7474
) {
75-
ServiceShape service = settings.getService(model);
76-
if (!isSigV4Service(service) && isAwsService(service)) {
77-
ServiceTrait serviceTrait = service.getTrait(ServiceTrait.class).get();
78-
settings.setDefaultSigningName(
79-
serviceTrait.getArnNamespace()
80-
);
81-
return;
82-
}
75+
if (!settings.getExperimentalIdentityAndAuth()) {
76+
ServiceShape service = settings.getService(model);
77+
if (!isSigV4Service(service) && isAwsService(service)) {
78+
ServiceTrait serviceTrait = service.getTrait(ServiceTrait.class).get();
79+
settings.setDefaultSigningName(
80+
serviceTrait.getArnNamespace()
81+
);
82+
return;
83+
}
8384

84-
if (!isSigV4Service(service)) {
85-
return;
86-
}
85+
if (!isSigV4Service(service)) {
86+
return;
87+
}
8788

88-
if (!isAwsService(service)) {
89-
writer.writeDocs("The service name to use as the signing service for AWS Auth\n@internal")
90-
.write("signingName?: string;\n");
91-
}
89+
if (!isAwsService(service)) {
90+
writer.writeDocs("The service name to use as the signing service for AWS Auth\n@internal")
91+
.write("signingName?: string;\n");
92+
}
9293

93-
if (!areAllOptionalAuthOperations(model, service)) {
94-
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES);
95-
writer.writeDocs("Default credentials provider; Not available in browser runtime.\n"
96-
+ "@internal");
97-
writer.write("credentialDefaultProvider?: (input: any) => __Provider<__Credentials>;\n");
98-
}
94+
if (!areAllOptionalAuthOperations(model, service)) {
95+
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES);
96+
writer.writeDocs("Default credentials provider; Not available in browser runtime.\n"
97+
+ "@internal");
98+
writer.write("credentialDefaultProvider?: (input: any) => __Provider<__Credentials>;\n");
99+
}
99100

100-
try {
101-
ServiceTrait serviceTrait = service.getTrait(ServiceTrait.class).get();
102-
settings.setDefaultSigningName(
103-
service.getTrait(SigV4Trait.class).map(SigV4Trait::getName)
104-
.orElse(serviceTrait.getArnNamespace())
105-
);
106-
} catch (Exception e) {
107-
LOGGER.warning("Unable to set service default signing name. A SigV4 or Service trait is needed.");
101+
try {
102+
ServiceTrait serviceTrait = service.getTrait(ServiceTrait.class).get();
103+
settings.setDefaultSigningName(
104+
service.getTrait(SigV4Trait.class).map(SigV4Trait::getName)
105+
.orElse(serviceTrait.getArnNamespace())
106+
);
107+
} catch (Exception e) {
108+
LOGGER.warning("Unable to set service default signing name. A SigV4 or Service trait is needed.");
109+
}
108110
}
109111
}
110112

@@ -120,12 +122,14 @@ public List<RuntimeClientPlugin> getClientPlugins() {
120122
&& isAwsService(s)
121123
&& !testServiceId(s, "STS")
122124
&& !areAllOptionalAuthOperations(m, s))
125+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
123126
.build(),
124127
RuntimeClientPlugin.builder()
125128
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "SigV4Auth", HAS_CONFIG)
126129
.servicePredicate((m, s) -> isSigV4Service(s)
127130
&& !isAwsService(s)
128131
&& !areAllOptionalAuthOperations(m, s))
132+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
129133
.build(),
130134
RuntimeClientPlugin.builder()
131135
.withConventions(AwsDependency.STS_MIDDLEWARE.dependency,
@@ -134,33 +138,38 @@ && isAwsService(s)
134138
put("stsClientCtor", Symbol.builder().name("STSClient").build());
135139
}})
136140
.servicePredicate((m, s) -> testServiceId(s, "STS"))
141+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
137142
.build(),
138143
RuntimeClientPlugin.builder()
139144
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
140145
// See operationUsesAwsAuth() below for AwsAuth Middleware customizations.
141146
.servicePredicate((m, s) -> isSigV4Service(s)
142147
&& isAwsService(s)
143148
&& !testServiceId(s, "STS")
144-
&& !hasOptionalAuthOperation(m, s)
145-
).build(),
149+
&& !hasOptionalAuthOperation(m, s))
150+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
151+
.build(),
146152
RuntimeClientPlugin.builder()
147153
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "SigV4Auth", HAS_MIDDLEWARE)
148154
// See operationUsesAwsAuth() below for AwsAuth Middleware customizations.
149155
.servicePredicate((m, s) -> isSigV4Service(s)
150156
&& !isAwsService(s)
151-
&& !hasOptionalAuthOperation(m, s)
152-
).build(),
157+
&& !hasOptionalAuthOperation(m, s))
158+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
159+
.build(),
153160
RuntimeClientPlugin.builder()
154161
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
155162
.operationPredicate((m, s, o) -> isSigV4Service(s)
156163
&& isAwsService(s)
157164
&& operationUsesAwsAuth(m, s, o))
165+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
158166
.build(),
159167
RuntimeClientPlugin.builder()
160168
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "SigV4Auth", HAS_MIDDLEWARE)
161169
.operationPredicate((m, s, o) -> isSigV4Service(s)
162170
&& !isAwsService(s)
163171
&& operationUsesAwsAuth(m, s, o))
172+
.settingsPredicate((m, s, settings) -> !settings.getExperimentalIdentityAndAuth())
164173
.build()
165174

166175
);
@@ -173,61 +182,70 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
173182
SymbolProvider symbolProvider,
174183
LanguageTarget target
175184
) {
176-
ServiceShape service = settings.getService(model);
177-
if (!isSigV4Service(service) || areAllOptionalAuthOperations(model, service)) {
178-
return Collections.emptyMap();
179-
}
180-
switch (target) {
181-
case SHARED:
182-
if (isAwsService(service)) {
183-
return Collections.emptyMap();
184-
}
185-
String signingService = service.getTrait(SigV4Trait.class).get().getName();
186-
return MapUtils.of(
187-
"signingName", writer -> {
188-
writer.write("$S", signingService);
189-
}
190-
);
191-
case BROWSER:
192-
return MapUtils.of(
193-
"credentialDefaultProvider", writer -> {
194-
writer.write("((_: unknown) => () => Promise.reject(new Error(\"Credential is missing\")))");
185+
if (!settings.getExperimentalIdentityAndAuth()) {
186+
ServiceShape service = settings.getService(model);
187+
if (!isSigV4Service(service) || areAllOptionalAuthOperations(model, service)) {
188+
return Collections.emptyMap();
189+
}
190+
switch (target) {
191+
case SHARED:
192+
if (isAwsService(service)) {
193+
return Collections.emptyMap();
195194
}
196-
);
197-
case NODE:
198-
return MapUtils.of(
199-
"credentialDefaultProvider", writer -> {
200-
if (!testServiceId(service, "STS")) {
201-
writer.addDependency(AwsDependency.STS_CLIENT);
202-
writer.addImport("decorateDefaultCredentialProvider", "decorateDefaultCredentialProvider",
195+
String signingService = service.getTrait(SigV4Trait.class).get().getName();
196+
return MapUtils.of(
197+
"signingName", writer -> {
198+
writer.write("$S", signingService);
199+
}
200+
);
201+
case BROWSER:
202+
return MapUtils.of(
203+
"credentialDefaultProvider", writer -> {
204+
writer.write(
205+
"((_: unknown) => () => Promise.reject(new Error(\"Credential is missing\")))");
206+
}
207+
);
208+
case NODE:
209+
return MapUtils.of(
210+
"credentialDefaultProvider", writer -> {
211+
if (!testServiceId(service, "STS")) {
212+
writer.addDependency(AwsDependency.STS_CLIENT);
213+
writer.addImport(
214+
"decorateDefaultCredentialProvider",
215+
"decorateDefaultCredentialProvider",
203216
AwsDependency.STS_CLIENT);
204-
} else {
205-
writer.addRelativeImport("decorateDefaultCredentialProvider",
206-
"decorateDefaultCredentialProvider", Paths.get(".", CodegenUtils.SOURCE_FOLDER,
207-
STS_ROLE_ASSUMERS_FILE));
217+
} else {
218+
writer.addRelativeImport("decorateDefaultCredentialProvider",
219+
"decorateDefaultCredentialProvider", Paths.get(".", CodegenUtils.SOURCE_FOLDER,
220+
STS_ROLE_ASSUMERS_FILE));
221+
}
222+
writer.addDependency(AwsDependency.CREDENTIAL_PROVIDER_NODE);
223+
writer.addImport("defaultProvider", "credentialDefaultProvider",
224+
AwsDependency.CREDENTIAL_PROVIDER_NODE);
225+
writer.write("decorateDefaultCredentialProvider(credentialDefaultProvider)");
208226
}
209-
writer.addDependency(AwsDependency.CREDENTIAL_PROVIDER_NODE);
210-
writer.addImport("defaultProvider", "credentialDefaultProvider",
211-
AwsDependency.CREDENTIAL_PROVIDER_NODE);
212-
writer.write("decorateDefaultCredentialProvider(credentialDefaultProvider)");
213-
}
214-
);
215-
default:
216-
return Collections.emptyMap();
227+
);
228+
default:
229+
return Collections.emptyMap();
230+
}
217231
}
232+
return Collections.emptyMap();
218233
}
219234

220235
@Override
221236
public void customize(TypeScriptCodegenContext codegenContext) {
222-
TypeScriptSettings settings = codegenContext.settings();
223-
Model model = codegenContext.model();
224-
BiConsumer<String, Consumer<TypeScriptWriter>> writerFactory = codegenContext.writerDelegator()::useFileWriter;
237+
if (!codegenContext.settings().getExperimentalIdentityAndAuth()) {
238+
TypeScriptSettings settings = codegenContext.settings();
239+
Model model = codegenContext.model();
240+
BiConsumer<String, Consumer<TypeScriptWriter>> writerFactory =
241+
codegenContext.writerDelegator()::useFileWriter;
225242

226-
writeAdditionalFiles(settings, model, writerFactory);
243+
writeAdditionalFiles(settings, model, writerFactory);
227244

228-
writerFactory.accept(Paths.get(CodegenUtils.SOURCE_FOLDER, "index.ts").toString(), writer -> {
229-
writeAdditionalExports(settings, model, writer);
230-
});
245+
writerFactory.accept(Paths.get(CodegenUtils.SOURCE_FOLDER, "index.ts").toString(), writer -> {
246+
writeAdditionalExports(settings, model, writer);
247+
});
248+
}
231249
}
232250

233251
private void writeAdditionalFiles(

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,13 @@ public void addConfigInterfaceFields(
9191
writer.writeDocs("Enables FIPS compatible endpoints.")
9292
.write("useFipsEndpoint?: boolean | __Provider<boolean>;\n");
9393
}
94-
if (isSigV4Service(settings, model)) {
95-
writer.writeDocs(isAwsService(settings, model)
96-
? "The AWS region to which this client will send requests"
97-
: "The AWS region to use as signing region for AWS Auth")
98-
.write("region?: string | __Provider<string>;\n");
94+
if (!settings.getExperimentalIdentityAndAuth()) {
95+
if (isSigV4Service(settings, model)) {
96+
writer.writeDocs(isAwsService(settings, model)
97+
? "The AWS region to which this client will send requests"
98+
: "The AWS region to use as signing region for AWS Auth")
99+
.write("region?: string | __Provider<string>;\n");
100+
}
99101
}
100102
}
101103

@@ -134,30 +136,33 @@ private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(
134136
if (!isSigV4Service(settings, model)) {
135137
return Collections.emptyMap();
136138
}
137-
switch (target) {
138-
case BROWSER:
139-
return MapUtils.of("region", writer -> {
140-
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
141-
writer.addImport("invalidProvider", "invalidProvider",
142-
TypeScriptDependency.INVALID_DEPENDENCY);
143-
writer.write("invalidProvider(\"Region is missing\")");
144-
});
145-
case NODE:
146-
return MapUtils.of("region", writer -> {
147-
writer.addDependency(TypeScriptDependency.NODE_CONFIG_PROVIDER);
148-
writer.addImport("loadConfig", "loadNodeConfig",
149-
TypeScriptDependency.NODE_CONFIG_PROVIDER);
150-
writer.addDependency(TypeScriptDependency.CONFIG_RESOLVER);
151-
writer.addImport("NODE_REGION_CONFIG_OPTIONS", "NODE_REGION_CONFIG_OPTIONS",
152-
TypeScriptDependency.CONFIG_RESOLVER);
153-
writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS",
154-
TypeScriptDependency.CONFIG_RESOLVER);
155-
writer.write(
156-
"loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS)");
157-
});
158-
default:
159-
return Collections.emptyMap();
139+
if (!settings.getExperimentalIdentityAndAuth()) {
140+
switch (target) {
141+
case BROWSER:
142+
return MapUtils.of("region", writer -> {
143+
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
144+
writer.addImport("invalidProvider", "invalidProvider",
145+
TypeScriptDependency.INVALID_DEPENDENCY);
146+
writer.write("invalidProvider(\"Region is missing\")");
147+
});
148+
case NODE:
149+
return MapUtils.of("region", writer -> {
150+
writer.addDependency(TypeScriptDependency.NODE_CONFIG_PROVIDER);
151+
writer.addImport("loadConfig", "loadNodeConfig",
152+
TypeScriptDependency.NODE_CONFIG_PROVIDER);
153+
writer.addDependency(TypeScriptDependency.CONFIG_RESOLVER);
154+
writer.addImport("NODE_REGION_CONFIG_OPTIONS", "NODE_REGION_CONFIG_OPTIONS",
155+
TypeScriptDependency.CONFIG_RESOLVER);
156+
writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS",
157+
TypeScriptDependency.CONFIG_RESOLVER);
158+
writer.write(
159+
"loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS)");
160+
});
161+
default:
162+
return Collections.emptyMap();
163+
}
160164
}
165+
return Collections.emptyMap();
161166
}
162167

163168
private Map<String, Consumer<TypeScriptWriter>> getEndpointConfigWriters(

0 commit comments

Comments
 (0)