Add SigV4 and SigV4A migration diff validation (#2245)

* Add Endpoint helper methods
* Add SigV4Migration diff validation
* Add EndpointSigV4Migration diff validation
This commit is contained in:
Steven Yuan 2024-04-23 14:03:22 -07:00 committed by GitHub
parent 507eeb09bd
commit 9511565c84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 4828 additions and 23 deletions

View File

@ -11,6 +11,8 @@ ext {
} }
dependencies { dependencies {
api project(":smithy-aws-traits")
api project(":smithy-diff")
api project(":smithy-rules-engine") api project(":smithy-rules-engine")
api project(":smithy-model") api project(":smithy-model")
api project(":smithy-utils") api project(":smithy-utils")

View File

@ -0,0 +1,249 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.rulesengine.aws.diff;
import static software.amazon.smithy.rulesengine.aws.language.functions.EndpointAuthUtils.isSigV4AEquivalentAuthScheme;
import static software.amazon.smithy.rulesengine.aws.language.functions.EndpointAuthUtils.isSigV4EquivalentAuthScheme;
import static software.amazon.smithy.rulesengine.language.EndpointRuleSet.EndpointPathCollector;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import software.amazon.smithy.diff.ChangedShape;
import software.amazon.smithy.diff.Differences;
import software.amazon.smithy.diff.evaluators.AbstractDiffEvaluator;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.AuthTrait;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.rulesengine.aws.language.functions.EndpointAuthUtils;
import software.amazon.smithy.rulesengine.language.Endpoint;
import software.amazon.smithy.rulesengine.language.syntax.Identifier;
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
import software.amazon.smithy.utils.Pair;
import software.amazon.smithy.utils.SmithyInternalApi;
/**
* Emit diff validation for SigV4 migration in the {@code @smithy.rules#endpointRuleSet} trait.
*
* Specifically, SigV4 ({@code aws.auth#sigv4}) to SigV4A ({@code aws.auth#sigv4a}) due to a subset of credentials
* usable with SigV4 that are not usable with SigV4A.
*
* @see <a href="https://smithy.io/2.0/aws/aws-auth.html">AWS Authentication Traits</a>
* @see <a href="https://smithy.io/2.0/additional-specs/rules-engine/specification.html#endpoint-authschemes-list-property">Endpoint {@code authSchemes} list property</a>
*/
@SmithyInternalApi
public final class EndpointSigV4Migration extends AbstractDiffEvaluator {
private static final Identifier ID_NAME = Identifier.of("name");
@Override
public List<ValidationEvent> evaluate(Differences differences) {
List<ValidationEvent> events = new ArrayList<>();
Model oldModel = differences.getOldModel();
ServiceIndex oldServiceIndex = ServiceIndex.of(oldModel);
Model newModel = differences.getNewModel();
ServiceIndex newServiceIndex = ServiceIndex.of(newModel);
// Validate Service effective auth schemes
List<ChangedShape<ServiceShape>> serviceChanges = differences
.changedShapes(ServiceShape.class)
.collect(Collectors.toList());
for (ChangedShape<ServiceShape> change : serviceChanges) {
ServiceShape oldServiceShape = change.getOldShape();
ServiceShape newServiceShape = change.getNewShape();
if (!oldServiceShape.hasTrait(EndpointRuleSetTrait.ID)
|| !newServiceShape.hasTrait(EndpointRuleSetTrait.ID)) {
continue;
}
Optional<Pair<EndpointRuleSetTrait, EndpointRuleSetTrait>> endpointRuleSetOpt =
change.getChangedTrait(EndpointRuleSetTrait.class);
Optional<Pair<AuthTrait, AuthTrait>> authOpt =
change.getChangedTrait(AuthTrait.class);
List<String> oldModeledAuthSchemes = getModeledAuthSchemes(oldServiceIndex, oldServiceShape);
List<String> newModeledAuthSchemes = getModeledAuthSchemes(newServiceIndex, newServiceShape);
// Validate diffs for changes to `@smithy.rules#endpointRuleSet` and `@auth` and effective auth schemes
if (!endpointRuleSetOpt.isPresent()
&& !authOpt.isPresent()
// Check modeled auth schemes since they could change without the `@auth` trait present
&& oldModeledAuthSchemes.equals(newModeledAuthSchemes)) {
continue;
}
EndpointRuleSetTrait oldErs = oldServiceShape.expectTrait(EndpointRuleSetTrait.class);
Map<String, Endpoint> oldEndpoints = EndpointPathCollector.from(oldErs).collect();
EndpointRuleSetTrait newErs = newServiceShape.expectTrait(EndpointRuleSetTrait.class);
Map<String, Endpoint> newEndpoints = EndpointPathCollector.from(newErs).collect();
// JSON path -> Endpoint entries that exist in both the old and new model and are changed
Map<String, Pair<Endpoint, Endpoint>> changedEndpoints = newEndpoints.entrySet().stream()
.filter(e -> oldEndpoints.containsKey(e.getKey()))
.map(e -> new SimpleEntry<String, Pair<Endpoint, Endpoint>>(
e.getKey(),
Pair.of(oldEndpoints.get(e.getKey()), e.getValue())))
.filter(e -> !e.getValue().getLeft().equals(e.getValue().getRight()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
for (Entry<String, Pair<Endpoint, Endpoint>> entry : changedEndpoints.entrySet()) {
String jsonPath = entry.getKey();
Endpoint oldEndpoint = entry.getValue().getLeft();
Endpoint newEndpoint = entry.getValue().getRight();
List<String> oldAuthSchemes = getAuthSchemes(oldEndpoint, oldModeledAuthSchemes);
List<String> newAuthSchemes = getAuthSchemes(newEndpoint, newModeledAuthSchemes);
boolean isOldSigV4Present = containsSigV4EquivalentAuthScheme(oldAuthSchemes);
boolean isOldSigV4APresent = containsSigV4AEquivalentAuthScheme(oldAuthSchemes);
boolean isNewSigV4Present = containsSigV4EquivalentAuthScheme(newAuthSchemes);
boolean isNewSigV4APresent = containsSigV4AEquivalentAuthScheme(newAuthSchemes);
boolean isSigV4Replaced = isOldSigV4Present && !isNewSigV4Present
&& !isOldSigV4APresent && isNewSigV4APresent;
boolean isSigV4AReplaced = !isOldSigV4Present && isNewSigV4Present
&& isOldSigV4APresent && !isNewSigV4APresent;
boolean noSigV4XRemoved = isOldSigV4Present && isNewSigV4Present
&& isOldSigV4APresent && isNewSigV4APresent;
boolean isSigV4Added = !isOldSigV4Present && isNewSigV4Present
&& isOldSigV4APresent && isNewSigV4APresent;
boolean isSigV4AAdded = isOldSigV4Present && isNewSigV4Present
&& !isOldSigV4APresent && isNewSigV4APresent;
if (isSigV4Replaced) {
events.add(danger(
newServiceShape,
"The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` "
+ "authentication scheme in the effective auth schemes for an endpoint in the "
+ "`@smithy.rules#endpointRuleSet` trait applied to `" + newServiceShape.getId() + "` at: `"
+ jsonPath + "`. "
+ "Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` "
+ "authentication scheme directly is not backward compatible since not all credentials usable "
+ "by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' "
+ "authentication."));
} else if (isSigV4AReplaced) {
events.add(danger(
newServiceShape,
"The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` "
+ "authentication scheme in the effective auth schemes for an endpoint in the "
+ "`@smithy.rules#endpointRuleSet` trait applied to `" + newServiceShape.getId() + "` at: `"
+ jsonPath + "`. "
+ "Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` "
+ "authentication scheme directly may not be backward compatible if the signing scope was "
+ "narrowed (typically from `*`)."));
} else if (noSigV4XRemoved) {
int oldSigV4Index = getIndexOfSigV4AuthScheme(oldAuthSchemes);
int oldSigV4aIndex = getIndexOfSigV4AAuthScheme(oldAuthSchemes);
int sigV4Index = getIndexOfSigV4AuthScheme(newAuthSchemes);
int sigV4aIndex = getIndexOfSigV4AAuthScheme(newAuthSchemes);
boolean isOldSigV4BeforeSigV4A = oldSigV4Index < oldSigV4aIndex;
boolean isSigV4BeforeSigV4A = sigV4Index < sigV4aIndex;
if (isOldSigV4BeforeSigV4A && !isSigV4BeforeSigV4A) {
events.add(danger(
newServiceShape,
"The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` "
+ "authentication scheme in the effective auth schemes for an endpoint in the "
+ "`@smithy.rules#endpointRuleSet` trait applied to `" + newServiceShape.getId()
+ "` at: `" + jsonPath + "`. "
+ "Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` "
+ "authentication scheme is not backward compatible since not all credentials usable by "
+ "`aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing "
+ "clients' authentication."));
}
if (!isOldSigV4BeforeSigV4A && isSigV4BeforeSigV4A) {
events.add(danger(
newServiceShape,
"The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` "
+ "authentication scheme in the effective auth schemes for an endpoint in the "
+ "`@smithy.rules#endpointRuleSet` trait applied to `" + newServiceShape.getId()
+ "` at: `" + jsonPath + "`. "
+ "Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` "
+ "authentication scheme may not be backward compatible if the signing scope was narrowed "
+ "(typically from `*`)."));
}
} else if (isSigV4Added) {
int sigV4Index = getIndexOfSigV4AuthScheme(newAuthSchemes);
int sigV4aIndex = getIndexOfSigV4AAuthScheme(newAuthSchemes);
boolean isSigV4AddedBeforeSigV4A = sigV4Index < sigV4aIndex;
if (isSigV4AddedBeforeSigV4A) {
events.add(danger(
newServiceShape,
"The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` "
+ "authentication scheme in the effective auth schemes for an endpoint in the "
+ "`@smithy.rules#endpointRuleSet` trait applied to `" + newServiceShape.getId()
+ "` at: `" + jsonPath + "`. "
+ "Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` "
+ "authentication scheme may not be backward compatible if the signing scope was narrowed "
+ "(typically from `*`)."));
}
} else if (isSigV4AAdded) {
int sigV4Index = getIndexOfSigV4AuthScheme(newAuthSchemes);
int sigV4aIndex = getIndexOfSigV4AAuthScheme(newAuthSchemes);
boolean isSigV4AAddedBeforeSigV4 = sigV4aIndex < sigV4Index;
if (isSigV4AAddedBeforeSigV4) {
events.add(danger(
newServiceShape,
"The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` "
+ "authentication scheme in the effective auth schemes for an endpoint in the "
+ "`@smithy.rules#endpointRuleSet` trait applied to `" + newServiceShape.getId()
+ "` at: `" + jsonPath + "`. "
+ "Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` "
+ "authentication scheme is not backward compatible since not all credentials usable by "
+ "`aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' "
+ "authentication."));
}
}
}
}
return events;
}
private static List<String> getAuthSchemes(Endpoint endpoint, List<String> modeledAuthSchemes) {
List<String> endpointAuthSchemes = endpoint.getEndpointAuthSchemes().stream()
.map(a -> a.get(ID_NAME).asStringLiteral().get().expectLiteral())
.collect(Collectors.toList());
return endpointAuthSchemes.size() == 0
? modeledAuthSchemes
: endpointAuthSchemes;
}
private static List<String> getModeledAuthSchemes(ServiceIndex serviceIndex, ServiceShape serviceShape) {
return serviceIndex.getEffectiveAuthSchemes(serviceShape).keySet().stream()
.map(ShapeId::toString)
.collect(Collectors.toList());
}
private static boolean containsSigV4EquivalentAuthScheme(List<String> authSchemes) {
return getIndexOfSigV4AuthScheme(authSchemes) != -1;
}
private static boolean containsSigV4AEquivalentAuthScheme(List<String> authSchemes) {
return getIndexOfSigV4AAuthScheme(authSchemes) != -1;
}
private static int getIndexOfSigV4AuthScheme(List<String> authSchemes) {
return getIndexOfAuthScheme(authSchemes, EndpointAuthUtils::isSigV4EquivalentAuthScheme);
}
private static int getIndexOfSigV4AAuthScheme(List<String> authSchemes) {
return getIndexOfAuthScheme(authSchemes, EndpointAuthUtils::isSigV4AEquivalentAuthScheme);
}
private static int getIndexOfAuthScheme(List<String> authSchemes, Predicate<String> identifier) {
for (int i = 0; i < authSchemes.size(); i++) {
if (identifier.test(authSchemes.get(i))) {
return i;
}
}
return -1;
}
}

View File

@ -11,6 +11,8 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import software.amazon.smithy.aws.traits.auth.SigV4ATrait;
import software.amazon.smithy.aws.traits.auth.SigV4Trait;
import software.amazon.smithy.model.FromSourceLocation; import software.amazon.smithy.model.FromSourceLocation;
import software.amazon.smithy.model.validation.Severity; import software.amazon.smithy.model.validation.Severity;
import software.amazon.smithy.model.validation.ValidationEvent; import software.amazon.smithy.model.validation.ValidationEvent;
@ -26,15 +28,19 @@ import software.amazon.smithy.utils.MapUtils;
* Utilities for constructing and validating AWS-specific authentication components for rule-sets. * Utilities for constructing and validating AWS-specific authentication components for rule-sets.
*/ */
public final class EndpointAuthUtils { public final class EndpointAuthUtils {
private static final String SIGV_4 = "sigv4"; private static final String SIGV4 = "sigv4";
private static final String SIG_V4A = "sigv4a"; private static final String SIGV4_SHAPE_ID = SigV4Trait.ID.toString();
private static final String SIGV4_SUB = "sigv4-";
private static final String SIGV4_S3EXPRESS = "sigv4-s3express";
private static final String SIGV4A = "sigv4a";
private static final String SIGV4A_SHAPE_ID = SigV4ATrait.ID.toString();
private static final String SIGNING_NAME = "signingName"; private static final String SIGNING_NAME = "signingName";
private static final String SIGNING_REGION = "signingRegion"; private static final String SIGNING_REGION = "signingRegion";
private static final String SIGNING_REGION_SET = "signingRegionSet"; private static final String SIGNING_REGION_SET = "signingRegionSet";
private static final Identifier ID_SIGNING_NAME = Identifier.of("signingName"); private static final Identifier ID_SIGNING_NAME = Identifier.of(SIGNING_NAME);
private static final Identifier ID_SIGNING_REGION = Identifier.of("signingRegion"); private static final Identifier ID_SIGNING_REGION = Identifier.of(SIGNING_REGION);
private static final Identifier ID_SIGNING_REGION_SET = Identifier.of("signingRegionSet"); private static final Identifier ID_SIGNING_REGION_SET = Identifier.of(SIGNING_REGION_SET);
private static final Identifier ID_DISABLE_DOUBLE_ENCODING = Identifier.of("disableDoubleEncoding"); private static final Identifier ID_DISABLE_DOUBLE_ENCODING = Identifier.of("disableDoubleEncoding");
private static final Identifier ID_DISABLE_NORMALIZE_PATH = Identifier.of("disableNormalizePath"); private static final Identifier ID_DISABLE_NORMALIZE_PATH = Identifier.of("disableNormalizePath");
@ -49,7 +55,7 @@ public final class EndpointAuthUtils {
* @return the updated endpoint builder. * @return the updated endpoint builder.
*/ */
public static Endpoint.Builder sigv4(Endpoint.Builder builder, Literal signingRegion, Literal signingService) { public static Endpoint.Builder sigv4(Endpoint.Builder builder, Literal signingRegion, Literal signingService) {
return builder.addAuthScheme(SIGV_4, MapUtils.of( return builder.addAuthScheme(SIGV4, MapUtils.of(
SIGNING_NAME, signingService, SIGNING_NAME, signingService,
SIGNING_REGION, signingRegion)); SIGNING_REGION, signingRegion));
} }
@ -67,17 +73,49 @@ public final class EndpointAuthUtils {
List<Literal> signingRegionSet, List<Literal> signingRegionSet,
Literal signingService Literal signingService
) { ) {
return builder.addAuthScheme(SIG_V4A, MapUtils.of( return builder.addAuthScheme(SIGV4A, MapUtils.of(
SIGNING_NAME, signingService, SIGNING_NAME, signingService,
SIGNING_REGION_SET, Literal.tupleLiteral(signingRegionSet))); SIGNING_REGION_SET, Literal.tupleLiteral(signingRegionSet)));
} }
/**
* Returns if a given auth scheme is equivalent to {@code aws.auth#sigv4}.
*
* @param authScheme name of the auth scheme.
* @return whether the auth scheme is equivalent to {@code aws.auth#sigv4}.
*/
public static boolean isSigV4EquivalentAuthScheme(String authScheme) {
if (authScheme.equals(SIGV4) || authScheme.equals(SIGV4_SHAPE_ID)) {
return true;
}
if (authScheme.startsWith(SIGV4_SUB) && !authScheme.equals(SIGV4_S3EXPRESS)) {
return true;
}
return false;
}
/**
* Returns if a given auth scheme is equivalent to {@code aws.auth#sigv4a}.
*
* @param authScheme name of the auth scheme.
* @return whether the auth scheme is equivalent to {@code aws.auth#sigv4a}.
*/
public static boolean isSigV4AEquivalentAuthScheme(String authScheme) {
if (authScheme.equals(SIGV4A) || authScheme.equals(SIGV4A_SHAPE_ID)) {
return true;
}
if (authScheme.equals(SIGV4_S3EXPRESS)) {
return true;
}
return false;
}
static final class SigV4SchemeValidator implements AuthSchemeValidator { static final class SigV4SchemeValidator implements AuthSchemeValidator {
SigV4SchemeValidator() {} SigV4SchemeValidator() {}
@Override @Override
public boolean test(String name) { public boolean test(String name) {
return name.equals("sigv4"); return name.equals(SIGV4);
} }
@Override @Override
@ -126,7 +164,7 @@ public final class EndpointAuthUtils {
@Override @Override
public boolean test(String name) { public boolean test(String name) {
return name.equals("sigv4a"); return name.equals(SIGV4A);
} }
@Override @Override
@ -173,7 +211,7 @@ public final class EndpointAuthUtils {
@Override @Override
public boolean test(String name) { public boolean test(String name) {
return name.startsWith("sigv4-"); return name.startsWith(SIGV4_SUB);
} }
@Override @Override

View File

@ -0,0 +1 @@
software.amazon.smithy.rulesengine.aws.diff.EndpointSigV4Migration

View File

@ -0,0 +1,47 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.rulesengine.aws;
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.smithy.diff.ModelDiff;
import software.amazon.smithy.diff.testrunner.SmithyDiffTestCase;
import software.amazon.smithy.diff.testrunner.SmithyDiffTestSuite;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.validation.Severity;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.utils.IoUtils;
import software.amazon.smithy.utils.Pair;
public class DiffTest {
@ParameterizedTest(name = "{0}")
@MethodSource("source")
public void testRunner(String filename, Callable<SmithyDiffTestCase.Result> callable) throws Exception {
callable.call();
}
public static Stream<?> source() {
return SmithyDiffTestSuite.defaultParameterizedTestSource(DiffTest.class);
}
}

View File

@ -0,0 +1,28 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Add.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Remove.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use smithy.rules#endpointRuleSet
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: []
)
service Service2 {}
service Service3 {}

View File

@ -0,0 +1,28 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Add.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Remove.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use smithy.rules#endpointRuleSet
service Service1 {}
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: []
)
service Service3 {}

View File

@ -0,0 +1,74 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Add.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Remove.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "example"
}
]
}
}
}
]
)
@auth([httpBearerAuth])
@httpBearerAuth
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "example"
}
]
}
}
}
]
)
@auth([httpBearerAuth])
@httpBearerAuth
service Service2 {}
@auth([httpBearerAuth])
@httpBearerAuth
service Service3 {}
@auth([httpBearerAuth])
@httpBearerAuth
service Service4 {}

View File

@ -0,0 +1,74 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Add.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Remove.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "example"
}
]
}
}
}
]
)
@auth([httpBearerAuth])
@httpBearerAuth
service Service1 {}
@auth([httpBearerAuth])
@httpBearerAuth
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "example"
}
]
}
}
}
]
)
@auth([httpBearerAuth])
@httpBearerAuth
service Service3 {}
@auth([httpBearerAuth])
@httpBearerAuth
service Service4 {}

View File

@ -0,0 +1,159 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}

View File

@ -0,0 +1,178 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}

View File

@ -0,0 +1,183 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}

View File

@ -0,0 +1,202 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: { hello: "world" }
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}

View File

@ -0,0 +1,11 @@
[DANGER] ns.foo#Service1: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service1` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service2: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service2` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service3: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service3` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service4: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service4` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service5: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service5` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service7: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service7` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration

View File

@ -0,0 +1,116 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}

View File

@ -0,0 +1,114 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}

View File

@ -0,0 +1,5 @@
[DANGER] ns.foo#Service1: The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service1` at: `/rules/0/endpoint`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service2: The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service2` at: `/rules/0/endpoint`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service3: The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service3` at: `/rules/0/endpoint`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration

View File

@ -0,0 +1,210 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@httpBearerAuth
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@httpBearerAuth
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}

View File

@ -0,0 +1,212 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "example"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "example"
}
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "example"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, httpBearerAuth, sigv4a])
@httpBearerAuth
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: { hello: "world" }
}
}
]
)
@auth([sigv4, httpBearerAuth, sigv4a])
@httpBearerAuth
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "example"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}

View File

@ -0,0 +1,226 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Add.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service8")
@sigv4a(name: "service8")
service Service8 {}

View File

@ -0,0 +1,226 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Add.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service8")
@sigv4a(name: "service8")
service Service8 {}

View File

@ -0,0 +1,11 @@
[DANGER] ns.foo#Service1: The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service1` at: `/rules/0/endpoint`. Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service2: The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service2` at: `/rules/0/endpoint`. Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service3: The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service3` at: `/rules/0/endpoint`. Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service5: The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service5` at: `/rules/0/endpoint`. Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service6: The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service6` at: `/rules/0/endpoint`. Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service7: The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service7` at: `/rules/0/endpoint`. Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | EndpointSigV4Migration

View File

@ -0,0 +1,156 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}

View File

@ -0,0 +1,178 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4, sigv4a])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}

View File

@ -0,0 +1,180 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}

View File

@ -0,0 +1,202 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service5")
@sigv4a(name: "service5")
service Service5 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service6")
@sigv4a(name: "service6")
service Service6 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: { hello: "world" }
}
}
]
)
@auth([sigv4a, sigv4])
@sigv4(name: "service7")
@sigv4a(name: "service7")
service Service7 {}

View File

@ -0,0 +1,11 @@
[DANGER] ns.foo#Service1: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service1` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service2: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service2` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service3: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service3` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service4: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service4` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service5: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service5` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service7: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service7` at: `/rules/0/endpoint`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration

View File

@ -0,0 +1,114 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}

View File

@ -0,0 +1,116 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
{
id: "SigV4Migration"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4a"
signingRegionSet: ["*"]
}
]
}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {}
}
}
]
)
@auth([sigv4a])
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}

View File

@ -0,0 +1,5 @@
[DANGER] ns.foo#Service1: The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service1` at: `/rules/0/endpoint`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service2: The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service2` at: `/rules/0/endpoint`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration
-----
[DANGER] ns.foo#Service3: The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for an endpoint in the `@smithy.rules#endpointRuleSet` trait applied to `ns.foo#Service3` at: `/rules/0/endpoint`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | EndpointSigV4Migration

View File

@ -0,0 +1,84 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@httpBearerAuth
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4])
@httpBearerAuth
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@auth([sigv4])
@httpBearerAuth
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@auth([sigv4])
@httpBearerAuth
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}

View File

@ -0,0 +1,90 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
{
id: "ModifiedTrait.Update.smithy.rules#endpointRuleSet"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
use smithy.rules#endpointRuleSet
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "example"
}
{
name: "sigv4"
}
]
}
}
}
]
)
@auth([sigv4, httpBearerAuth])
@httpBearerAuth
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {}
@endpointRuleSet(
version: "1.0"
serviceId: "service"
parameters: {}
rules: [
{
type: "endpoint"
conditions: []
endpoint: {
url: "https://abc.service.com"
properties: {
authSchemes: [
{
name: "sigv4"
}
{
name: "example"
}
]
}
}
}
]
)
@auth([sigv4, httpBearerAuth])
@httpBearerAuth
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {}
@auth([sigv4, httpBearerAuth])
@httpBearerAuth
@sigv4(name: "service3")
@sigv4a(name: "service3")
service Service3 {}
@auth([httpBearerAuth, sigv4])
@httpBearerAuth
@sigv4(name: "service4")
@sigv4a(name: "service4")
service Service4 {}

View File

@ -21,5 +21,6 @@ ext {
} }
dependencies { dependencies {
api project(":smithy-diff")
api project(":smithy-model") api project(":smithy-model")
} }

View File

@ -0,0 +1,210 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.aws.traits.auth.diff;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import software.amazon.smithy.aws.traits.auth.SigV4ATrait;
import software.amazon.smithy.aws.traits.auth.SigV4Trait;
import software.amazon.smithy.diff.ChangedShape;
import software.amazon.smithy.diff.Differences;
import software.amazon.smithy.diff.evaluators.AbstractDiffEvaluator;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.knowledge.TopDownIndex;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.utils.SmithyInternalApi;
/**
* Emit diff validation for SigV4 migration in the {@code @auth} trait.
*
* Specifically, SigV4 ({@code aws.auth#sigv4}) to SigV4A ({@code aws.auth#sigv4a}) due to a subset of credentials
* usable with SigV4 that are not usable with SigV4A.
*
* @see <a href="https://smithy.io/2.0/aws/aws-auth.html">AWS Authentication Traits</a>
*/
@SmithyInternalApi
public final class SigV4Migration extends AbstractDiffEvaluator {
@Override
public List<ValidationEvent> evaluate(Differences differences) {
List<ValidationEvent> events = new ArrayList<>();
Model oldModel = differences.getOldModel();
ServiceIndex oldServiceIndex = ServiceIndex.of(oldModel);
Model newModel = differences.getNewModel();
ServiceIndex newServiceIndex = ServiceIndex.of(newModel);
// Validate Service effective auth schemes
List<ChangedShape<ServiceShape>> serviceChanges = differences
.changedShapes(ServiceShape.class)
.collect(Collectors.toList());
for (ChangedShape<ServiceShape> change : serviceChanges) {
ServiceShape oldServiceShape = change.getOldShape();
List<ShapeId> oldAuthSchemes = oldServiceIndex
.getEffectiveAuthSchemes(oldServiceShape)
.keySet()
.stream()
.collect(Collectors.toList());
ServiceShape newServiceShape = change.getNewShape();
List<ShapeId> newAuthSchemes = newServiceIndex
.getEffectiveAuthSchemes(newServiceShape)
.keySet()
.stream()
.collect(Collectors.toList());
validateMigration(
newServiceShape,
oldAuthSchemes,
newAuthSchemes,
events);
}
Map<OperationShape, Set<ServiceShape>> operationToContainedServiceBindings =
computeOperationToContainedServiceBindings(newModel);
List<ChangedShape<OperationShape>> operationChanges = differences
.changedShapes(OperationShape.class)
.collect(Collectors.toList());
for (ChangedShape<OperationShape> change : operationChanges) {
OperationShape newOperationShape = change.getNewShape();
Set<ServiceShape> newOperationServiceBindings = operationToContainedServiceBindings.get(newOperationShape);
if (newOperationServiceBindings == null) {
continue;
}
// Validate Operation effective auth schemes
for (ServiceShape newServiceShape : newOperationServiceBindings) {
ServiceShape oldServiceShape = oldModel.expectShape(newServiceShape.getId(), ServiceShape.class);
OperationShape oldOperationShape = change.getOldShape();
List<ShapeId> oldAuthSchemes = oldServiceIndex
.getEffectiveAuthSchemes(oldServiceShape, oldOperationShape)
.keySet()
.stream()
.collect(Collectors.toList());
List<ShapeId> newAuthSchemes = newServiceIndex
.getEffectiveAuthSchemes(newServiceShape, newOperationShape)
.keySet()
.stream()
.collect(Collectors.toList());
validateMigration(
newOperationShape,
oldAuthSchemes,
newAuthSchemes,
events);
}
}
return events;
}
private void validateMigration(
Shape shape,
List<ShapeId> oldAuthSchemes,
List<ShapeId> newAuthSchemes,
List<ValidationEvent> events
) {
boolean isOldSigV4Present = oldAuthSchemes.contains(SigV4Trait.ID);
boolean isOldSigV4APresent = oldAuthSchemes.contains(SigV4ATrait.ID);
boolean isNewSigV4Present = newAuthSchemes.contains(SigV4Trait.ID);
boolean isNewSigV4APresent = newAuthSchemes.contains(SigV4ATrait.ID);
boolean isSigV4Replaced = isOldSigV4Present && !isNewSigV4Present && !isOldSigV4APresent && isNewSigV4APresent;
boolean isSigV4AReplaced = !isOldSigV4Present && isNewSigV4Present && isOldSigV4APresent && !isNewSigV4APresent;
boolean noSigV4XRemoved = isOldSigV4Present && isNewSigV4Present && isOldSigV4APresent && isNewSigV4APresent;
boolean isSigV4Added = !isOldSigV4Present && isNewSigV4Present && isOldSigV4APresent && isNewSigV4APresent;
boolean isSigV4AAdded = isOldSigV4Present && isNewSigV4Present && !isOldSigV4APresent && isNewSigV4APresent;
if (isSigV4Replaced) {
events.add(danger(
shape,
"The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` authentication "
+ "scheme in the effective auth schemes for `" + shape.getId() + "`. "
+ "Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication "
+ "scheme directly is not backward compatible since not all credentials usable by `aws.auth#sigv4` are "
+ "compatible with `aws.auth#sigv4a`, and can break existing clients' authentication."));
} else if (isSigV4AReplaced) {
events.add(danger(
shape,
"The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` authentication "
+ "scheme in the effective auth schemes for `" + shape.getId() + "`. "
+ "Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication "
+ "scheme directly may not be backward compatible if the signing scope was narrowed (typically from "
+ "`*`)."));
} else if (noSigV4XRemoved) {
int oldSigV4Index = oldAuthSchemes.indexOf(SigV4Trait.ID);
int oldSigV4aIndex = oldAuthSchemes.indexOf(SigV4ATrait.ID);
int sigV4Index = newAuthSchemes.indexOf(SigV4Trait.ID);
int sigV4aIndex = newAuthSchemes.indexOf(SigV4ATrait.ID);
boolean isOldSigV4BeforeSigV4A = oldSigV4Index < oldSigV4aIndex;
boolean isSigV4BeforeSigV4A = sigV4Index < sigV4aIndex;
if (isOldSigV4BeforeSigV4A && !isSigV4BeforeSigV4A) {
events.add(danger(
shape,
"The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` authentication "
+ "scheme in the effective auth schemes for `" + shape.getId() + "`. "
+ "Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` authentication "
+ "scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are "
+ "compatible with `aws.auth#sigv4a`, and can break existing clients' authentication."));
}
if (!isOldSigV4BeforeSigV4A && isSigV4BeforeSigV4A) {
events.add(danger(
shape,
"The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` authentication "
+ "scheme in the effective auth schemes for `" + shape.getId() + "`. "
+ "Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` authentication "
+ "scheme may not be backward compatible if the signing scope was narrowed (typically from `*`)."));
}
} else if (isSigV4Added) {
int sigV4Index = newAuthSchemes.indexOf(SigV4Trait.ID);
int sigV4aIndex = newAuthSchemes.indexOf(SigV4ATrait.ID);
boolean isSigV4AddedBeforeSigV4A = sigV4Index < sigV4aIndex;
if (isSigV4AddedBeforeSigV4A) {
events.add(danger(
shape,
"The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication "
+ "scheme in the effective auth schemes for `" + shape.getId() + "`. "
+ "Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` "
+ "authentication scheme may not be backward compatible if the signing scope was narrowed "
+ "(typically from `*`)."));
}
} else if (isSigV4AAdded) {
int sigV4Index = newAuthSchemes.indexOf(SigV4Trait.ID);
int sigV4aIndex = newAuthSchemes.indexOf(SigV4ATrait.ID);
boolean isSigV4AAddedBeforeSigV4 = sigV4aIndex < sigV4Index;
if (isSigV4AAddedBeforeSigV4) {
events.add(danger(
shape,
"The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication "
+ "scheme in the effective auth schemes for `" + shape.getId() + "`. "
+ "Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` "
+ "authentication scheme is not backward compatible since not all credentials usable by "
+ "`aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' "
+ "authentication."));
}
}
}
private static Map<OperationShape, Set<ServiceShape>> computeOperationToContainedServiceBindings(Model model) {
Map<OperationShape, Set<ServiceShape>> operationToContainedServiceBindings = new HashMap<>();
TopDownIndex topDownIndex = TopDownIndex.of(model);
for (OperationShape operationShape : model.getOperationShapes()) {
Set<ServiceShape> operationEntry = operationToContainedServiceBindings
.getOrDefault(operationShape, new HashSet());
for (ServiceShape serviceShape : model.getServiceShapes()) {
if (topDownIndex.getContainedOperations(serviceShape).contains(operationShape)) {
operationEntry.add(serviceShape);
}
}
operationToContainedServiceBindings.put(operationShape, operationEntry);
}
return operationToContainedServiceBindings;
}
}

View File

@ -0,0 +1 @@
software.amazon.smithy.aws.traits.auth.diff.SigV4Migration

View File

@ -0,0 +1,47 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.aws.traits;
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.smithy.diff.ModelDiff;
import software.amazon.smithy.diff.testrunner.SmithyDiffTestCase;
import software.amazon.smithy.diff.testrunner.SmithyDiffTestSuite;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.validation.Severity;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.utils.IoUtils;
import software.amazon.smithy.utils.Pair;
public class DiffTest {
@ParameterizedTest(name = "{0}")
@MethodSource("source")
public void testRunner(String filename, Callable<SmithyDiffTestCase.Result> callable) throws Exception {
callable.call();
}
public static Stream<?> source() {
return SmithyDiffTestSuite.defaultParameterizedTestSource(DiffTest.class);
}
}

View File

@ -0,0 +1,21 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
@auth([])
@httpBearerAuth
service Service {
operations: [
Operation
]
}
@auth([])
operation Operation {}

View File

@ -0,0 +1,21 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
@auth([httpBearerAuth])
@httpBearerAuth
service Service {
operations: [
Operation
]
}
@auth([httpBearerAuth])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4a])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a, sigv4])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4a, sigv4])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4a])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4, sigv4a])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4, sigv4a])
operation Operation {}

View File

@ -0,0 +1,3 @@
[DANGER] ns.foo#Service: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for `ns.foo#Service`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | SigV4Migration
-----
[DANGER] ns.foo#Operation: The `aws.auth#sigv4` authentication scheme was added before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for `ns.foo#Operation`. Adding the `aws.auth#sigv4` authentication scheme before an existing `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | SigV4Migration

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4a])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4])
operation Operation {}

View File

@ -0,0 +1,3 @@
[DANGER] ns.foo#Service: The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` authentication scheme in the effective auth schemes for `ns.foo#Service`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly may not be backward compatible if the signing scope was narrowed (typically from `*`). | SigV4Migration
-----
[DANGER] ns.foo#Operation: The `aws.auth#sigv4a` authentication scheme was replaced by the `aws.auth#sigv4` authentication scheme in the effective auth schemes for `ns.foo#Operation`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly may not be backward compatible if the signing scope was narrowed (typically from `*`). | SigV4Migration

View File

@ -0,0 +1,26 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([httpBearerAuth, sigv4, sigv4a])
@httpBearerAuth
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([httpBearerAuth, sigv4, sigv4a])
operation Operation {}

View File

@ -0,0 +1,26 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4, httpBearerAuth, sigv4a])
@httpBearerAuth
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4, httpBearerAuth, sigv4a])
operation Operation {}

View File

@ -0,0 +1,37 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4, sigv4a])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {
operations: [
Operation1
]
}
@auth([sigv4, sigv4a])
operation Operation1 {}
@auth([sigv4a, sigv4])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {
operations: [
Operation2
]
}
@auth([sigv4a, sigv4])
operation Operation2 {}

View File

@ -0,0 +1,37 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a, sigv4])
@sigv4(name: "service1")
@sigv4a(name: "service1")
service Service1 {
operations: [
Operation1
]
}
@auth([sigv4a, sigv4])
operation Operation1 {}
@auth([sigv4, sigv4a])
@sigv4(name: "service2")
@sigv4a(name: "service2")
service Service2 {
operations: [
Operation2
]
}
@auth([sigv4, sigv4a])
operation Operation2 {}

View File

@ -0,0 +1,7 @@
[DANGER] ns.foo#Service1: The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for `ns.foo#Service1`. Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | SigV4Migration
-----
[DANGER] ns.foo#Operation1: The `aws.auth#sigv4a` authentication scheme was moved before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for `ns.foo#Operation1`. Moving the `aws.auth#sigv4a` authentication scheme before the `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | SigV4Migration
-----
[DANGER] ns.foo#Service2: The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for `ns.foo#Service2`. Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | SigV4Migration
-----
[DANGER] ns.foo#Operation2: The `aws.auth#sigv4` authentication scheme was moved before the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for `ns.foo#Operation2`. Moving the `aws.auth#sigv4` authentication scheme before the `aws.auth#sigv4a` authentication scheme may not be backward compatible if the signing scope was narrowed (typically from `*`). | SigV4Migration

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4, sigv4a])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4, sigv4a])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a, sigv4])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4a, sigv4])
operation Operation {}

View File

@ -0,0 +1,3 @@
[DANGER] ns.foo#Service: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for `ns.foo#Service`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | SigV4Migration
-----
[DANGER] ns.foo#Operation: The `aws.auth#sigv4a` authentication scheme was added before the `aws.auth#sigv4` authentication scheme in the effective auth schemes for `ns.foo#Operation`. Adding the `aws.auth#sigv4a` authentication scheme before an existing `aws.auth#sigv4` authentication scheme is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | SigV4Migration

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4])
operation Operation {}

View File

@ -0,0 +1,25 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
use aws.auth#sigv4a
@auth([sigv4a])
@sigv4(name: "service")
@sigv4a(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4a])
operation Operation {}

View File

@ -0,0 +1,3 @@
[DANGER] ns.foo#Service: The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for `ns.foo#Service`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | SigV4Migration
-----
[DANGER] ns.foo#Operation: The `aws.auth#sigv4` authentication scheme was replaced by the `aws.auth#sigv4a` authentication scheme in the effective auth schemes for `ns.foo#Operation`. Replacing the `aws.auth#sigv4` authentication scheme with the `aws.auth#sigv4a` authentication scheme directly is not backward compatible since not all credentials usable by `aws.auth#sigv4` are compatible with `aws.auth#sigv4a`, and can break existing clients' authentication. | SigV4Migration

View File

@ -0,0 +1,24 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
@auth([sigv4])
@httpBearerAuth
@sigv4(name: "service")
service Service {
operations: [
Operation
]
}
@auth([sigv4])
operation Operation {}

View File

@ -0,0 +1,24 @@
$version: "2.0"
metadata suppressions = [
{
id: "ModifiedTrait.Update.smithy.api#auth"
namespace: "ns.foo"
}
]
namespace ns.foo
use aws.auth#sigv4
@auth([httpBearerAuth, sigv4])
@httpBearerAuth
@sigv4(name: "service")
service Service {
operations: [
Operation
]
}
@auth([httpBearerAuth, sigv4])
operation Operation {}

View File

@ -12,8 +12,11 @@ import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.stream.Collectors;
import software.amazon.smithy.model.FromSourceLocation; import software.amazon.smithy.model.FromSourceLocation;
import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.ArrayNode;
@ -42,6 +45,8 @@ public final class Endpoint implements FromSourceLocation, ToNode, ToSmithyBuild
private static final String URL = "url"; private static final String URL = "url";
private static final String PROPERTIES = "properties"; private static final String PROPERTIES = "properties";
private static final String HEADERS = "headers"; private static final String HEADERS = "headers";
private static final Identifier ID_AUTH_SCHEMES = Identifier.of("authSchemes");
private static final Identifier ID_NAME = Identifier.of("name");
private final Map<String, List<Expression>> headers; private final Map<String, List<Expression>> headers;
private final Map<Identifier, Literal> properties; private final Map<Identifier, Literal> properties;
@ -57,12 +62,12 @@ public final class Endpoint implements FromSourceLocation, ToNode, ToSmithyBuild
List<Literal> authSchemes = new ArrayList<>(); List<Literal> authSchemes = new ArrayList<>();
for (Map.Entry<Identifier, Map<Identifier, Literal>> authScheme : builder.authSchemes.get().entrySet()) { for (Map.Entry<Identifier, Map<Identifier, Literal>> authScheme : builder.authSchemes.get().entrySet()) {
Map<Identifier, Literal> base = new TreeMap<>(Comparator.comparing(Identifier::toString)); Map<Identifier, Literal> base = new TreeMap<>(Comparator.comparing(Identifier::toString));
base.put(Identifier.of("name"), Literal.of(authScheme.getKey().toString())); base.put(ID_NAME, Literal.of(authScheme.getKey().toString()));
base.putAll(authScheme.getValue()); base.putAll(authScheme.getValue());
authSchemes.add(Literal.recordLiteral(base)); authSchemes.add(Literal.recordLiteral(base));
} }
if (!authSchemes.isEmpty()) { if (!authSchemes.isEmpty()) {
builder.putProperty(Identifier.of("authSchemes"), Literal.tupleLiteral(authSchemes)); builder.putProperty(ID_AUTH_SCHEMES, Literal.tupleLiteral(authSchemes));
} }
this.properties = builder.properties.copy(); this.properties = builder.properties.copy();
@ -139,6 +144,19 @@ public final class Endpoint implements FromSourceLocation, ToNode, ToSmithyBuild
return properties; return properties;
} }
/**
* Get the endpoint {@code authSchemes} property as a map of {@link Identifier} to {@link Literal} values.
*
* @return the list of endpoint {@code authSchemes}.
*/
public List<Map<Identifier, Literal>> getEndpointAuthSchemes() {
return Optional.ofNullable(getProperties().get(ID_AUTH_SCHEMES))
.map(a -> a.asTupleLiteral().get().stream()
.map(l -> l.asRecordLiteral().get())
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
}
@Override @Override
public Builder toBuilder() { public Builder toBuilder() {
return builder().sourceLocation(sourceLocation).url(url).headers(headers).properties(properties); return builder().sourceLocation(sourceLocation).url(url).headers(headers).properties(properties);

View File

@ -8,7 +8,10 @@ package software.amazon.smithy.rulesengine.language;
import static software.amazon.smithy.rulesengine.language.error.RuleError.context; import static software.amazon.smithy.rulesengine.language.error.RuleError.context;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
@ -17,6 +20,7 @@ import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.ArrayNode;
import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.node.ToNode;
import software.amazon.smithy.rulesengine.language.error.RuleError; import software.amazon.smithy.rulesengine.language.error.RuleError;
import software.amazon.smithy.rulesengine.language.evaluation.Scope; import software.amazon.smithy.rulesengine.language.evaluation.Scope;
@ -27,6 +31,7 @@ import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters; import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters;
import software.amazon.smithy.rulesengine.language.syntax.rule.EndpointRule; import software.amazon.smithy.rulesengine.language.syntax.rule.EndpointRule;
import software.amazon.smithy.rulesengine.language.syntax.rule.Rule; import software.amazon.smithy.rulesengine.language.syntax.rule.Rule;
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
import software.amazon.smithy.rulesengine.validators.AuthSchemeValidator; import software.amazon.smithy.rulesengine.validators.AuthSchemeValidator;
import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.BuilderRef;
import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.SmithyBuilder;
@ -57,10 +62,10 @@ public final class EndpointRuleSet implements FromSourceLocation, ToNode, ToSmit
private EndpointRuleSet(Builder builder) { private EndpointRuleSet(Builder builder) {
super(); super();
parameters = SmithyBuilder.requiredState("parameters", builder.parameters); parameters = SmithyBuilder.requiredState(PARAMETERS, builder.parameters);
rules = builder.rules.copy(); rules = builder.rules.copy();
sourceLocation = SmithyBuilder.requiredState("source", builder.getSourceLocation()); sourceLocation = SmithyBuilder.requiredState("source", builder.getSourceLocation());
version = SmithyBuilder.requiredState("version", builder.version); version = SmithyBuilder.requiredState(VERSION, builder.version);
} }
/** /**
@ -313,4 +318,89 @@ public final class EndpointRuleSet implements FromSourceLocation, ToNode, ToSmit
return ruleSet; return ruleSet;
} }
} }
/**
* {@link EndpointRuleSet} visitor that collects a map of JSON pointer paths to {@link Endpoint}s.
*/
@SmithyInternalApi
public static final class EndpointPathCollector {
private static final String ENDPOINT = "endpoint";
private static final String TYPE = "type";
private final Map<String, Endpoint> visitedEndpoints = new HashMap();
private final ObjectNode endpointRuleSet;
private EndpointPathCollector(EndpointRuleSetTrait endpointRuleSetTrait) {
this.endpointRuleSet = endpointRuleSetTrait.getRuleSet().expectObjectNode();
}
/**
* Creates a collector from an {@link EndpointRuleSetTrait}.
*
* @param endpointRuleSetTrait EndpointRuleSet trait instance.
*/
@SmithyInternalApi
public static EndpointPathCollector from(EndpointRuleSetTrait endpointRuleSetTrait) {
return new EndpointPathCollector(endpointRuleSetTrait);
}
/**
* Collects the mapped JSON pointer paths to {@link Endpoint}s.
*
* @return a map of JSON pointer paths to {@link Endpoint}s.
*/
@SmithyInternalApi
public Map<String, Endpoint> collect() {
arrayNode(endpointRuleSet.expectArrayMember(RULES), "/" + RULES);
return visitedEndpoints;
}
private void objectNode(ObjectNode node, String parentPath) {
boolean isEndpointRuleObject = node
.getMember(TYPE)
.map(n -> n.asStringNode()
.map(s -> s.getValue().equals(ENDPOINT))
.orElse(false))
.orElse(false);
if (isEndpointRuleObject) {
Endpoint endpoint = Endpoint.fromNode(node.expectMember(ENDPOINT));
visitedEndpoints.put(parentPath + "/" + ENDPOINT, endpoint);
return;
}
for (Entry<StringNode, Node> member : node.getMembers().entrySet()) {
String key = member.getKey().getValue();
Node value = member.getValue();
switch (value.getType()) {
case OBJECT: {
objectNode(value.expectObjectNode(), parentPath + "/" + key);
break;
}
case ARRAY: {
arrayNode(value.expectArrayNode(), parentPath + "/" + key);
break;
}
default:
break;
}
}
}
private void arrayNode(ArrayNode node, String parentPath) {
List<Node> elements = node.getElements();
for (int i = 0; i < elements.size(); i++) {
Node element = elements.get(i);
switch (element.getType()) {
case OBJECT: {
objectNode(element.expectObjectNode(), parentPath + "/" + i);
break;
}
case ARRAY: {
arrayNode(element.expectArrayNode(), parentPath + "/" + i);
break;
}
default:
break;
}
}
}
}
} }

View File

@ -1,8 +1,14 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.rulesengine.language; package software.amazon.smithy.rulesengine.language;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import software.amazon.smithy.model.SourceLocation; import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.Node;
@ -10,15 +16,25 @@ import software.amazon.smithy.rulesengine.language.evaluation.RuleEvaluator;
import software.amazon.smithy.rulesengine.language.evaluation.value.EndpointValue; import software.amazon.smithy.rulesengine.language.evaluation.value.EndpointValue;
import software.amazon.smithy.rulesengine.language.evaluation.value.Value; import software.amazon.smithy.rulesengine.language.evaluation.value.Value;
import software.amazon.smithy.rulesengine.language.syntax.Identifier; import software.amazon.smithy.rulesengine.language.syntax.Identifier;
import software.amazon.smithy.rulesengine.language.syntax.expressions.Reference;
import software.amazon.smithy.rulesengine.language.syntax.expressions.literal.Literal; import software.amazon.smithy.rulesengine.language.syntax.expressions.literal.Literal;
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter; import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter;
import software.amazon.smithy.rulesengine.language.syntax.parameters.ParameterType; import software.amazon.smithy.rulesengine.language.syntax.parameters.ParameterType;
import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters; import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters;
import software.amazon.smithy.rulesengine.language.syntax.rule.Rule; import software.amazon.smithy.rulesengine.language.syntax.rule.Rule;
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
import software.amazon.smithy.utils.IoUtils; import software.amazon.smithy.utils.IoUtils;
import software.amazon.smithy.utils.MapUtils; import software.amazon.smithy.utils.MapUtils;
public class EndpointRuleSetTest { public class EndpointRuleSetTest {
private static final Endpoint MINIMAL_ENDPOINT = Endpoint.builder()
.sourceLocation(SourceLocation.none())
.url(Literal.of("https://{Region}.amazonaws.com"))
.addAuthScheme(Identifier.of("sigv4"), MapUtils.of(
Identifier.of("signingRegion"), Literal.of("{Region}"),
Identifier.of("signingName"), Literal.of("serviceName")))
.build();
@Test @Test
public void testRuleEval() { public void testRuleEval() {
EndpointRuleSet actual = TestRunnerTest.getMinimalEndpointRuleSet(); EndpointRuleSet actual = TestRunnerTest.getMinimalEndpointRuleSet();
@ -61,13 +77,62 @@ public class EndpointRuleSetTest {
.addRule(Rule .addRule(Rule
.builder() .builder()
.description("base rule") .description("base rule")
.endpoint(Endpoint.builder() .endpoint(MINIMAL_ENDPOINT))
.sourceLocation(SourceLocation.none())
.url(Literal.of("https://{Region}.amazonaws.com"))
.addAuthScheme(Identifier.of("sigv4"), MapUtils.of(
Identifier.of("signingRegion"), Literal.of("{Region}"),
Identifier.of("signingName"), Literal.of("serviceName")))
.build()))
.build(), actual); .build(), actual);
} }
@Test
public void testEndpointCollectorMinimalRuleset() {
EndpointRuleSet ers = TestRunnerTest.getMinimalEndpointRuleSet();
Map<String, Endpoint> actual = EndpointRuleSet.EndpointPathCollector
.from(EndpointRuleSetTrait.builder()
.ruleSet(ers.toNode())
.build())
.collect();
Map<String, Endpoint> expected = MapUtils.of("/rules/0/endpoint", MINIMAL_ENDPOINT);
assertEquals(expected, actual);
}
@Test
public void testEndpointCollectorEmptyRuleset() {
EndpointRuleSet ers = EndpointRuleSet.builder()
.parameters(Parameters.builder().build())
.build();
Map<String, Endpoint> actual = EndpointRuleSet.EndpointPathCollector
.from(EndpointRuleSetTrait.builder()
.ruleSet(ers.toNode())
.build())
.collect();
Map<String, Endpoint> expected = Collections.emptyMap();
assertEquals(expected, actual);
}
@Test
public void testEndpointCollectorComplexRuleset() {
EndpointRuleSet ers = TestRunnerTest.getEndpointRuleSet(
EndpointRuleSetTest.class, "example-complex-ruleset.json");
Map<String, Endpoint> actual = EndpointRuleSet.EndpointPathCollector
.from(EndpointRuleSetTrait.builder()
.ruleSet(ers.toNode())
.build())
.collect();
Map<String, Endpoint> expected = MapUtils.of(
"/rules/1/rules/0/rules/0/rules/1/endpoint", Endpoint.builder()
.url(Literal.of("https://example.{Region}.dual-stack-dns-suffix.com"))
.build(),
"/rules/1/rules/0/rules/1/rules/0/rules/0/endpoint", Endpoint.builder()
.url(Literal.of("https://example-fips.{Region}.dual-stack-dns-suffix.com"))
.build(),
"/rules/1/rules/0/rules/2/endpoint", Endpoint.builder()
.url(Literal.of("https://example.{Region}.dual-stack-dns-suffix.com"))
.build(),
"/rules/0/rules/1/endpoint", Endpoint.builder()
.url(new Reference(Identifier.of("Endpoint"), SourceLocation.NONE))
.build(),
"/rules/1/rules/0/rules/0/rules/0/rules/0/rules/0/endpoint", Endpoint.builder()
.url(Literal.of("https://example-fips.{Region}.dual-stack-dns-suffix.com"))
.build()
);
assertEquals(expected, actual);
}
} }

View File

@ -0,0 +1,62 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package software.amazon.smithy.rulesengine.language;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.junit.jupiter.api.Test;
import software.amazon.smithy.rulesengine.language.syntax.Identifier;
import software.amazon.smithy.rulesengine.language.syntax.expressions.literal.Literal;
import software.amazon.smithy.utils.ListUtils;
import software.amazon.smithy.utils.MapUtils;
import software.amazon.smithy.utils.Pair;
public class EndpointTest {
private static final Pair<String, Map<Identifier, Literal>> SIGV4_AUTH_SCHEME = Pair.of(
"sigv4",
Collections.emptyMap());
private static final Pair<String, Map<Identifier, Literal>> SIGV4A_AUTH_SCHEME = Pair.of(
"sigv4a",
MapUtils.of(
Identifier.of("signingRegionSet"),
Literal.tupleLiteral(ListUtils.of(Literal.of("*")))));
@Test
public void testGetEndpointAuthSchemes() {
Endpoint endpoint = Endpoint.builder()
.url(Literal.of("https://abc.service.com"))
.addAuthScheme(Identifier.of(SIGV4A_AUTH_SCHEME.getLeft()), SIGV4A_AUTH_SCHEME.getRight())
.addAuthScheme(Identifier.of(SIGV4_AUTH_SCHEME.getLeft()), SIGV4_AUTH_SCHEME.getRight())
.build();
List<Map<Identifier, Literal>> actual = endpoint.getEndpointAuthSchemes();
List<Map<Identifier, Literal>> expected = ListUtils.of(
convertAuthSchemeToMap(SIGV4A_AUTH_SCHEME),
convertAuthSchemeToMap(SIGV4_AUTH_SCHEME));
assertEquals(expected, actual);
}
@Test
public void testEmptyGetEndpointAuthSchemes() {
Endpoint endpoint = Endpoint.builder()
.url(Literal.of("https://abc.service.com"))
.build();
List<Map<Identifier, Literal>> actual = endpoint.getEndpointAuthSchemes();
List<Map<Identifier, Literal>> expected = Collections.emptyList();
assertEquals(expected, actual);
}
private static Map<Identifier, Literal> convertAuthSchemeToMap(Pair<String, Map<Identifier, Literal>> authScheme) {
Map<Identifier, Literal> base = new TreeMap<>(Comparator.comparing(Identifier::toString));
base.put(Identifier.of("name"), Literal.of(authScheme.getLeft()));
base.putAll(authScheme.getRight());
return base;
}
}

View File

@ -15,8 +15,11 @@ public class TestRunnerTest {
} }
public static EndpointRuleSet getMinimalEndpointRuleSet() { public static EndpointRuleSet getMinimalEndpointRuleSet() {
return EndpointRuleSet.fromNode(Node.parse(IoUtils.readUtf8Resource( return getEndpointRuleSet(TestRunnerTest.class, "minimal-ruleset.json");
TestRunnerTest.class, "minimal-ruleset.json"))); }
public static EndpointRuleSet getEndpointRuleSet(Class klass, String file) {
return EndpointRuleSet.fromNode(Node.parseJsonWithComments(IoUtils.readUtf8Resource(klass, file)));
} }
@ParameterizedTest(name = "{0}") @ParameterizedTest(name = "{0}")

View File

@ -0,0 +1,243 @@
// Modified AWS service ruleset (may not actually resolve any endpoints correctly)
{
"version": "1.0",
"parameters": {
"Region": {
"required": false,
"type": "String"
},
"UseFIPS": {
"required": true,
"type": "Boolean"
},
"Endpoint": {
"builtIn": "SDK::Endpoint",
"required": false,
"documentation": "Override the endpoint used to send this request",
"type": "String"
}
},
"rules": [
{
"conditions": [
{
"fn": "isSet",
"argv": [
{
"ref": "Endpoint"
}
]
}
],
"rules": [
{
"conditions": [
{
"fn": "booleanEquals",
"argv": [
{
"ref": "UseFIPS"
},
true
]
}
],
"error": "Invalid Configuration: FIPS and custom endpoint are not supported",
"type": "error"
},
{
"conditions": [],
"endpoint": {
"url": {
"ref": "Endpoint"
},
"properties": {},
"headers": {}
},
"type": "endpoint"
}
],
"type": "tree"
},
{
"conditions": [
{
"fn": "isSet",
"argv": [
{
"ref": "Region"
}
]
}
],
"rules": [
{
"conditions": [
{
"fn": "parseURL",
"argv": [
{
"ref": "Region"
}
],
"assign": "PartitionResult"
}
],
"rules": [
{
"conditions": [
{
"fn": "booleanEquals",
"argv": [
true,
{
"fn": "getAttr",
"argv": [
{
"ref": "PartitionResult"
},
"isIp"
]
}
]
}
],
"rules": [
{
"conditions": [
{
"fn": "booleanEquals",
"argv": [
{
"ref": "UseFIPS"
},
true
]
}
],
"rules": [
{
"conditions": [
{
"fn": "booleanEquals",
"argv": [
{
"fn": "getAttr",
"argv": [
{
"ref": "PartitionResult"
},
"isIp"
]
},
true
]
}
],
"rules": [
{
"conditions": [],
"endpoint": {
"url": "https://example-fips.{Region}.dual-stack-dns-suffix.com",
"properties": {},
"headers": {}
},
"type": "endpoint"
}
],
"type": "tree"
},
{
"conditions": [],
"error": "FIPS is enabled but this partition does not support FIPS",
"type": "error"
}
],
"type": "tree"
},
{
"conditions": [],
"endpoint": {
"url": "https://example.{Region}.dual-stack-dns-suffix.com",
"properties": {},
"headers": {}
},
"type": "endpoint"
}
],
"type": "tree"
},
{
"conditions": [
{
"fn": "booleanEquals",
"argv": [
{
"ref": "UseFIPS"
},
true
]
}
],
"rules": [
{
"conditions": [
{
"fn": "booleanEquals",
"argv": [
{
"fn": "getAttr",
"argv": [
{
"ref": "PartitionResult"
},
"isIp"
]
},
true
]
}
],
"rules": [
{
"conditions": [],
"endpoint": {
"url": "https://example-fips.{Region}.dual-stack-dns-suffix.com",
"properties": {},
"headers": {}
},
"type": "endpoint"
}
],
"type": "tree"
},
{
"conditions": [],
"error": "FIPS is enabled but this partition does not support FIPS",
"type": "error"
}
],
"type": "tree"
},
{
"conditions": [],
"endpoint": {
"url": "https://example.{Region}.dual-stack-dns-suffix.com",
"properties": {},
"headers": {}
},
"type": "endpoint"
}
],
"type": "tree"
}
],
"type": "tree"
},
{
"conditions": [],
"error": "Invalid Configuration: Missing Region",
"type": "error"
}
]
}