Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

FIPS & DualStack Endpoint Resolver Support #1274

Merged
merged 7 commits into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 10 additions & 8 deletions .github/workflows/license-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: License Scan
on: [pull_request]

jobs:
build:

licensescan:
name: License Scan
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -14,15 +14,17 @@ jobs:
- name: Checkout target
uses: actions/checkout@v2
with:
path: sdkmain
path: sdkbase
ref: ${{ github.base_ref }}
- name: Checkout this ref
uses: actions/checkout@v2
with:
path: new-ref
fetch-depth: 0
- name: Get Diff
run: git --git-dir ./new-ref/.git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }}| xargs > fileList.txt
run: git --git-dir ./new-ref/.git diff --name-only --diff-filter=ACMRT ${{ github.event.pull_request.base.sha }} ${{ github.sha }} > refDiffFiles.txt
- name: Get Target Files
run: git --git-dir ./sdkbase/.git ls-files | grep -xf refDiffFiles.txt - > targetFiles.txt
- name: Checkout scancode
uses: actions/checkout@v2
with:
Expand All @@ -37,10 +39,10 @@ jobs:
- name: Self-configure scancode
working-directory: ./scancode-toolkit
run: ./scancode --help
- name: Run Scan code on pr ref
run: for filename in $(< fileList.txt); do ./scancode-toolkit/scancode -l -n 30 --json-pp - ./sdkmain/$filename | grep short_name | sort | uniq >> old-licenses.txt; done
- name: Run Scan code on target
run: for filename in $(< fileList.txt); do ./scancode-toolkit/scancode -l -n 30 --json-pp - ./new-ref/$filename | grep short_name | sort | uniq >> new-licenses.txt; done
run: cat targetFiles.txt | while read filename; do echo ./sdkbase/$filename; done | xargs ./scancode-toolkit/scancode -l -n 30 --json-pp - | grep short_name | sort | uniq >> old-licenses.txt
- name: Run Scan code on pr ref
run: cat refDiffFiles.txt | while read filename; do echo ./new-ref/$filename; done | xargs ./scancode-toolkit/scancode -l -n 30 --json-pp - | grep short_name | sort | uniq >> new-licenses.txt
# compare
- name: License test
run: if ! cmp old-licenses.txt new-licenses.txt; then echo "Licenses differ! Failing."; exit -1; else echo "Licenses are the same. Success."; exit 0; fi
run: if ! cmp old-licenses.txt new-licenses.txt; then echo "Licenses differ! Failing."; exit -1; else echo "Licenses are the same. Success."; exit 0; fi
6 changes: 6 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,14 @@ type Config struct {

// An endpoint resolver that can be used to provide or override an endpoint for the given
// service and region Please see the `aws.EndpointResolver` documentation on usage.
//
// Deprecated: See Config.EndpointResolverWithOptions
EndpointResolver EndpointResolver

// An endpoint resolver that can be used to provide or override an endpoint for the given
// service and region Please see the `aws.EndpointResolverWithOptions` documentation on usage.
EndpointResolverWithOptions EndpointResolverWithOptions

// Retryer is a function that provides a Retryer implementation. A Retryer guides how HTTP requests should be
// retried in case of recoverable failures. When nil the API client will use a default
// retryer.
Expand Down
110 changes: 110 additions & 0 deletions aws/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,66 @@ import (
"fmt"
)

// DualStackEndpointState is a constant to describe the dual-stack endpoint resolution behavior.
type DualStackEndpointState uint

const (
// DualStackEndpointStateUnset is the default value behavior for dual-stack endpoint resolution.
DualStackEndpointStateUnset DualStackEndpointState = iota

// DualStackEndpointStateEnabled enables dual-stack endpoint resolution for service endpoints.
DualStackEndpointStateEnabled

// DualStackEndpointStateDisabled disables dual-stack endpoint resolution for endpoints.
DualStackEndpointStateDisabled
)

// GetUseDualStackEndpoint takes a service's EndpointResolverOptions and returns the UseDualStackEndpoint value.
// Returns boolean false if the provided options does not have a method to retrieve the DualStackEndpointState.
func GetUseDualStackEndpoint(options ...interface{}) (value DualStackEndpointState, found bool) {
type iface interface {
GetUseDualStackEndpoint() DualStackEndpointState
}
for _, option := range options {
if i, ok := option.(iface); ok {
value = i.GetUseDualStackEndpoint()
found = true
break
}
}
return value, found
}

// FIPSEndpointState is a constant to describe the FIPS endpoint resolution behavior.
type FIPSEndpointState uint

const (
// FIPSEndpointStateUnset is the default value behavior for FIPS endpoint resolution.
FIPSEndpointStateUnset FIPSEndpointState = iota

// FIPSEndpointStateEnabled enables FIPS endpoint resolution for service endpoints.
FIPSEndpointStateEnabled

// FIPSEndpointStateDisabled disables FIPS endpoint resolution for endpoints.
FIPSEndpointStateDisabled
)

// GetUseFIPSEndpoint takes a service's EndpointResolverOptions and returns the UseDualStackEndpoint value.
// Returns boolean false if the provided options does not have a method to retrieve the DualStackEndpointState.
func GetUseFIPSEndpoint(options ...interface{}) (value FIPSEndpointState, found bool) {
type iface interface {
GetUseFIPSEndpoint() FIPSEndpointState
}
for _, option := range options {
if i, ok := option.(iface); ok {
value = i.GetUseFIPSEndpoint()
found = true
break
}
}
return value, found
}

// Endpoint represents the endpoint a service client should make API operation
// calls to.
//
Expand Down Expand Up @@ -111,3 +171,53 @@ type EndpointResolverFunc func(service, region string) (Endpoint, error)
func (e EndpointResolverFunc) ResolveEndpoint(service, region string) (Endpoint, error) {
return e(service, region)
}

// EndpointResolverWithOptions is an endpoint resolver that can be used to provide or
// override an endpoint for the given service, region, and the service clients EndpointOptions. API clients will
// attempt to use the EndpointResolver first to resolve an endpoint if
// available. If the EndpointResolver returns an EndpointNotFoundError error,
// API clients will fallback to attempting to resolve the endpoint using its
// internal default endpoint resolver.
type EndpointResolverWithOptions interface {
ResolveEndpoint(service, region string, options ...interface{}) (Endpoint, error)
}

// EndpointResolverWithOptionsFunc wraps a function to satisfy the EndpointResolverWithOptions interface.
type EndpointResolverWithOptionsFunc func(service, region string, options interface{}) (Endpoint, error)

// ResolveEndpoint calls the wrapped function and returns the results.
func (e EndpointResolverWithOptionsFunc) ResolveEndpoint(service, region string, options interface{}) (Endpoint, error) {
return e(service, region, options)
}

// GetDisableHTTPS takes a service's EndpointResolverOptions and returns the DisableHTTPS value.
// Returns boolean false if the provided options does not have a method to retrieve the DisableHTTPS.
func GetDisableHTTPS(options ...interface{}) (value bool, found bool) {
type iface interface {
GetDisableHTTPS() bool
}
for _, option := range options {
if i, ok := option.(iface); ok {
value = i.GetDisableHTTPS()
found = true
break
}
}
return value, found
}

// GetResolvedRegion takes a service's EndpointResolverOptions and returns the ResolvedRegion value.
// Returns boolean false if the provided options does not have a method to retrieve the ResolvedRegion.
func GetResolvedRegion(options ...interface{}) (value string, found bool) {
type iface interface {
GetResolvedRegion() string
}
for _, option := range options {
if i, ok := option.(iface); ok {
value = i.GetResolvedRegion()
found = true
break
}
}
return value, found
}
189 changes: 189 additions & 0 deletions aws/endpoints_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package aws

import (
"strconv"
"testing"
)

type mockOptions struct {
Bool bool
Str string
DualStackEndpointState DualStackEndpointState
FIPSEndpointState FIPSEndpointState
}

func (m mockOptions) GetDisableHTTPS() bool {
return m.Bool
}

func (m mockOptions) GetUseDualStackEndpoint() DualStackEndpointState {
return m.DualStackEndpointState
}

func (m mockOptions) GetUseFIPSEndpoint() FIPSEndpointState {
return m.FIPSEndpointState
}

func (m mockOptions) GetResolvedRegion() string {
return m.Str
}

func TestGetDisableHTTPS(t *testing.T) {
cases := []struct {
Options []interface{}
ExpectFound bool
ExpectValue bool
}{
{
Options: []interface{}{struct{}{}},
},
{
Options: []interface{}{mockOptions{
Bool: false,
}},
ExpectFound: true,
ExpectValue: false,
},
{
Options: []interface{}{mockOptions{
Bool: true,
}},
ExpectFound: true,
ExpectValue: true,
},
{
Options: []interface{}{struct{}{}, mockOptions{Bool: true}, mockOptions{Bool: false}},
ExpectFound: true,
ExpectValue: true,
},
}

for i, tt := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
value, found := GetDisableHTTPS(tt.Options...)
if found != tt.ExpectFound {
t.Fatalf("expect value to not be found")
}
if value != tt.ExpectValue {
t.Errorf("expect %v, got %v", tt.ExpectValue, value)
}
})
}
}

func TestGetResolvedRegion(t *testing.T) {
cases := []struct {
Options []interface{}
ExpectFound bool
ExpectValue string
}{
{
Options: []interface{}{struct{}{}},
},
{
Options: []interface{}{mockOptions{Str: ""}},
ExpectFound: true,
ExpectValue: "",
},
{
Options: []interface{}{mockOptions{Str: "foo"}},
ExpectFound: true,
ExpectValue: "foo",
},
{
Options: []interface{}{struct{}{}, mockOptions{Str: "bar"}, mockOptions{Str: "baz"}},
ExpectFound: true,
ExpectValue: "bar",
},
}

for i, tt := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
value, found := GetResolvedRegion(tt.Options...)
if found != tt.ExpectFound {
t.Fatalf("expect value to not be found")
}
if value != tt.ExpectValue {
t.Errorf("expect %v, got %v", tt.ExpectValue, value)
}
})
}
}

func TestGetUseDualStackEndpoint(t *testing.T) {
cases := []struct {
Options []interface{}
ExpectFound bool
ExpectValue DualStackEndpointState
}{
{
Options: []interface{}{struct{}{}},
},
{
Options: []interface{}{mockOptions{DualStackEndpointState: DualStackEndpointStateUnset}},
ExpectFound: true,
ExpectValue: DualStackEndpointStateUnset,
},
{
Options: []interface{}{mockOptions{DualStackEndpointState: DualStackEndpointStateEnabled}},
ExpectFound: true,
ExpectValue: DualStackEndpointStateEnabled,
},
{
Options: []interface{}{struct{}{}, mockOptions{DualStackEndpointState: DualStackEndpointStateEnabled}, mockOptions{DualStackEndpointState: DualStackEndpointStateDisabled}},
ExpectFound: true,
ExpectValue: DualStackEndpointStateEnabled,
},
}

for i, tt := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
value, found := GetUseDualStackEndpoint(tt.Options...)
if found != tt.ExpectFound {
t.Fatalf("expect value to not be found")
}
if value != tt.ExpectValue {
t.Errorf("expect %v, got %v", tt.ExpectValue, value)
}
})
}
}

func TestGetUseFIPSEndpoint(t *testing.T) {
cases := []struct {
Options []interface{}
ExpectFound bool
ExpectValue FIPSEndpointState
}{
{
Options: []interface{}{struct{}{}},
},
{
Options: []interface{}{mockOptions{FIPSEndpointState: FIPSEndpointStateUnset}},
ExpectFound: true,
ExpectValue: FIPSEndpointStateUnset,
},
{
Options: []interface{}{mockOptions{FIPSEndpointState: FIPSEndpointStateEnabled}},
ExpectFound: true,
ExpectValue: FIPSEndpointStateEnabled,
},
{
Options: []interface{}{struct{}{}, mockOptions{FIPSEndpointState: FIPSEndpointStateEnabled}, mockOptions{FIPSEndpointState: FIPSEndpointStateDisabled}},
ExpectFound: true,
ExpectValue: FIPSEndpointStateEnabled,
},
}

for i, tt := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
value, found := GetUseFIPSEndpoint(tt.Options...)
if found != tt.ExpectFound {
t.Fatalf("expect value to not be found")
}
if value != tt.ExpectValue {
t.Errorf("expect %v, got %v", tt.ExpectValue, value)
}
})
}
}
Loading