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

Implement both the Add and Delete operations as no-ops #847

Merged
merged 11 commits into from
Aug 7, 2024
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Docker to work with the helper.
To build and install the Amazon ECR Docker Credential Helper, we suggest Go
1.19 or later, `git` and `make` installed on your system.

If you just installed Go, make sure you also have added it to your PATH or
If you just installed Go, make sure you also have added it to your PATH or
Environment Vars (Windows). For example:

```
Expand Down Expand Up @@ -213,7 +213,7 @@ include:
* An [IAM role for Amazon EC2](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)

To use credentials associated with a different named profile in the shared credentials file (`~/.aws/credentials`), you
may set the `AWS_PROFILE` environment variable.
may set the `AWS_PROFILE` environment variable.

The Amazon ECR Docker Credential Helper reads and supports some configuration options specified in the AWS
shared configuration file (`~/.aws/config`). To disable these options, you must set the `AWS_SDK_LOAD_CONFIG` environment
Expand All @@ -236,12 +236,13 @@ in the *AWS Command Line Interface User Guide*.
The credentials must have a policy applied that
[allows access to Amazon ECR](http://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html).

### Amazon ECR Docker Credential Helper
### Amazon ECR Docker Credential Helper

| Environment Variable | Sample Value | Description |
| --------------------- | ------------- | ------------------------------------------------------------------ |
| AWS_ECR_DISABLE_CACHE | true | Disables the local file auth cache if set to a non-empty value |
| AWS_ECR_CACHE_DIR | ~/.ecr | Specifies the local file auth cache directory location |
| Environment Variable | Sample Value | Description |
| ---------------------------- | ------------- | ------------------------------------------------------------------ |
| AWS_ECR_DISABLE_CACHE | true | Disables the local file auth cache if set to a non-empty value |
| AWS_ECR_CACHE_DIR | ~/.ecr | Specifies the local file auth cache directory location |
| AWS_ECR_IGNORE_CREDS_STORAGE | true | Ignore calls to docker login or logout and pretend they succeeded |

## Usage

Expand Down
37 changes: 31 additions & 6 deletions ecr-login/ecr.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"errors"
"fmt"
"io"
"os"

"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -70,14 +71,38 @@ func NewECRHelper(opts ...Option) *ECRHelper {
// ensure ECRHelper adheres to the credentials.Helper interface
var _ credentials.Helper = (*ECRHelper)(nil)

func (ECRHelper) Add(creds *credentials.Credentials) error {
// This does not seem to get called
return notImplemented
func shouldIgnoreCredsStorage() bool {
return os.Getenv("AWS_ECR_IGNORE_CREDS_STORAGE") == "true"
}

func (ECRHelper) Delete(serverURL string) error {
// This does not seem to get called
return notImplemented
// Add tries to store credentials when docker requests it. This usually happens during `docker login` calls. In our context,
// storing arbitrary user given credentials makes no sense.
func (self ECRHelper) Add(creds *credentials.Credentials) error {
if shouldIgnoreCredsStorage() {
self.logger.
WithField("serverURL", creds.ServerURL).
Warning("Ignoring request to store credentials since AWS_ECR_IGNORE_CREDS_STORAGE env variable is set." +
"ecr-login does not require 'docker login', and does not support persisting temporary ECR-issued credentials.")
return nil
} else {
self.logger.Warning("Add() is not supported by the ecr-login credentials helper as all issued credentials are temporary. Consider setting the AWS_ECR_IGNORE_CREDS_STORAGE env variable (see documentation for details).")
return notImplemented
}
}

// Delete tries to delete credentials when docker requests it. This usually happens during `docker logout` calls. In our context, we
// don't store arbitrary user given credentials so deleting them makes no sense.
func (self ECRHelper) Delete(serverURL string) error {
if shouldIgnoreCredsStorage() {
self.logger.
WithField("serverURL", serverURL).
Warning("Ignoring request to store credentials since AWS_ECR_IGNORE_CREDS_STORAGE env variable is set." +
"ecr-login does not require 'docker login', and does not support persisting temporary ECR-issued credentials.")
return nil
} else {
self.logger.Warning("Delete() credentials is not supported by the ecr-login credentials helper as all issued credentials are temporary. Consider setting the AWS_ECR_IGNORE_CREDS_STORAGE env variable (see documentation for details).")
return notImplemented
}
}

func (self ECRHelper) Get(serverURL string) (string, string, error) {
Expand Down
103 changes: 103 additions & 0 deletions ecr-login/ecr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ecr
import (
"errors"
"fmt"
"os"
"testing"

ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login/api"
Expand All @@ -32,6 +33,28 @@ const (
expectedPassword = "password"
)

// unsetEnv unsets an environment variable and registers a cleanup function that
// restores it after the test is complete. Note: tests that modify environment
// variables may not be run in parallel.
//
// See also [testing.T.Setenv]
func unsetEnv(t *testing.T, key string) {
t.Helper()

// save original value
originalValue, wasSet := os.LookupEnv(key)

// unset the environment variable
os.Unsetenv(key)

// restore the original value if necessary
if wasSet {
t.Cleanup(func() {
os.Setenv(key, originalValue)
})
}
}

func TestGetSuccess(t *testing.T) {
factory := &mock_api.MockClientFactory{}
client := &mock_api.MockClient{}
Expand Down Expand Up @@ -118,3 +141,83 @@ func TestListFailure(t *testing.T) {
assert.Error(t, err)
assert.Len(t, serverList, 0)
}

func TestAddIgnored(t *testing.T) {
factory := &mock_api.MockClientFactory{}

helper := NewECRHelper(WithClientFactory(factory))

t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "true")
err := helper.Add(&credentials.Credentials{
ServerURL: proxyEndpoint,
Username: "AWS",
Secret: "supersecret",
})

assert.Nil(t, err)
}

func TestAddNotImplemented(t *testing.T) {
tests := []struct {
name string
setEnv func(*testing.T)
}{
{"unset", func(*testing.T) { unsetEnv(t, "AWS_ECR_IGNORE_CREDS_STORAGE") }},
{"false", func(*testing.T) { t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "false") }},
{"0", func(*testing.T) { t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "0") }},
{"empty string", func(*testing.T) { t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "") }},
}

for _, test := range tests {
t.Run(test.name, func(tt *testing.T) {
factory := &mock_api.MockClientFactory{}

helper := NewECRHelper(WithClientFactory(factory))

test.setEnv(tt)
err := helper.Add(&credentials.Credentials{
ServerURL: proxyEndpoint,
Username: "AWS",
Secret: "supersecret",
})

assert.Error(tt, err, "not implemented")
})
}
}

func TestDeleteIgnored(t *testing.T) {
factory := &mock_api.MockClientFactory{}

helper := NewECRHelper(WithClientFactory(factory))

t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "true")
err := helper.Delete(proxyEndpoint)

assert.Nil(t, err)
}

func TestDeleteNotImplemented(t *testing.T) {
tests := []struct {
name string
setEnv func(*testing.T)
}{
{"unset", func(*testing.T) { unsetEnv(t, "AWS_ECR_IGNORE_CREDS_STORAGE") }},
{"false", func(*testing.T) { t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "false") }},
{"0", func(*testing.T) { t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "0") }},
{"empty string", func(*testing.T) { t.Setenv("AWS_ECR_IGNORE_CREDS_STORAGE", "") }},
}

for _, test := range tests {
t.Run(test.name, func(tt *testing.T) {
factory := &mock_api.MockClientFactory{}

helper := NewECRHelper(WithClientFactory(factory))

test.setEnv(tt)
err := helper.Delete(proxyEndpoint)

assert.Error(tt, err, "not implemented")
})
}
}
Loading