Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ require (
github.com/docker/docker-credential-helpers v0.9.3
github.com/docker/go-connections v0.5.0
github.com/go-jose/go-jose/v4 v4.1.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/sigstore/protobuf-specs v0.4.1
github.com/sigstore/scaffolding v0.7.22
github.com/sigstore/sigstore-go v0.7.2
Expand Down
199 changes: 199 additions & 0 deletions pkg/apis/policy/common/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package common

import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -72,3 +73,201 @@ func TestValidateOCI(t *testing.T) {
})
}
}

func TestValidAWSKMSRegex(t *testing.T) {
tests := []struct {
name string
ref string
shouldMatch bool
}{
{
name: "valid key ID",
ref: "awskms:///1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: true,
},
{
name: "valid key ID with endpoint",
ref: "awskms://localhost:4566/1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: true,
},
{
name: "valid key ARN",
ref: "awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: true,
},
{
name: "valid key ARN with endpoint",
ref: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: true,
},
{
name: "valid alias name",
ref: "awskms:///alias/ExampleAlias",
shouldMatch: true,
},
{
name: "valid alias name with endpoint",
ref: "awskms://localhost:4566/alias/ExampleAlias",
shouldMatch: true,
},
{
name: "valid alias ARN",
ref: "awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias",
shouldMatch: true,
},
{
name: "valid alias ARN with endpoint",
ref: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias",
shouldMatch: true,
},
{
name: "invalid format - missing prefix",
ref: "kms:///1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: false,
},
{
name: "invalid format - missing slashes",
ref: "awskms:/1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: false,
},
{
name: "invalid format - malformed UUID",
ref: "awskms:///1234abcd-12ab-34cd-56ef-1234567890",
shouldMatch: false,
},
{
name: "invalid format - malformed ARN",
ref: "awskms:///arn:aws:kms:us-east-2:key/1234abcd-12ab-34cd-56ef-1234567890ab",
shouldMatch: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := validAWSKMSRegex(test.ref)
if test.shouldMatch && err != nil {
t.Errorf("Expected regex to match, but got error: %v", err)
}
if !test.shouldMatch && err == nil {
t.Errorf("Expected regex not to match, but it did")
}
})
}
}

func TestValidateAWSKMS(t *testing.T) {
tests := []struct {
name string
kms string
expectError bool
errorContains string
}{
// Only ARN formats don't cause errors with the current arn.Parse implementation
{
name: "valid key ARN",
kms: "awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
expectError: false,
},
{
name: "too few parts",
kms: "awskms://keyid",
expectError: true,
errorContains: "malformed AWS KMS format",
},
{
name: "invalid regex",
kms: "awskms:///invalid-key-id",
expectError: true,
errorContains: "kms key should be in the format",
},
{
name: "ARN as endpoint",
kms: "awskms://arn:aws:kms:us-east-2:111122223333/key/1234abcd-12ab-34cd-56ef-1234567890ab",
expectError: true,
errorContains: "kms key should be in the format",
},
{
name: "invalid endpoint",
kms: "awskms://invalid_endpoint/1234abcd-12ab-34cd-56ef-1234567890ab",
expectError: true,
errorContains: "malformed endpoint",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := validateAWSKMS(test.kms)
if test.expectError {
if err == nil {
t.Errorf("Expected error but got none")
} else if test.errorContains != "" && !strings.Contains(err.Error(), test.errorContains) {
t.Errorf("Expected error containing %q but got %q", test.errorContains, err.Error())
}
} else if err != nil {
t.Errorf("Expected no error but got: %v", err)
}
})
}
}

func TestValidateKMS(t *testing.T) {
tests := []struct {
name string
kms string
expectError bool
errorContains string
}{
{
name: "valid AWS KMS reference",
kms: "awskms:///1234abcd-12ab-34cd-56ef-1234567890ab",
expectError: false,
},
{
name: "valid Azure KMS reference",
kms: "azurekms://",
expectError: false,
},
{
name: "valid GCP KMS reference",
kms: "gcpkms://",
expectError: false,
},
{
name: "valid HashiVault KMS reference",
kms: "hashivault://",
expectError: false,
},
{
name: "unsupported KMS provider",
kms: "unsupportedkms://keyid",
expectError: true,
errorContains: "malformed KMS format, should be prefixed by any of the supported providers",
},
{
name: "invalid AWS KMS reference",
kms: "awskms://invalid",
expectError: true,
errorContains: "malformed AWS KMS format",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := ValidateKMS(test.kms)
if test.expectError {
if err == nil {
t.Errorf("Expected error but got none")
} else if test.errorContains != "" && !strings.Contains(err.Error(), test.errorContains) {
t.Errorf("Expected error containing %q but got %q", test.errorContains, err.Error())
}
} else if err != nil {
// For AWS KMS we do deeper validation which could fail
if strings.HasPrefix(test.kms, "awskms://") {
// Skip detailed AWS KMS validation errors as they're tested separately
} else if err != nil {
t.Errorf("Expected no error but got: %v", err)
}
}
})
}
}
127 changes: 127 additions & 0 deletions pkg/webhook/registryauth/azure/acrhelper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// Copyright 2024 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package azure

import (
"strings"
"testing"
)

func TestNewACRHelper(t *testing.T) {
helper := NewACRHelper()
if helper == nil {
t.Fatal("Expected non-nil helper, got nil")
}

// The helper type already implements credentials.Helper, so we don't need a type assertion
// Just verify it's not nil
if helper == nil {
t.Error("Helper is nil")
}
}

func TestIsACR(t *testing.T) {
tests := []struct {
name string
registry string
want bool
}{
{
name: "valid ACR registry",
registry: "myregistry.azurecr.io",
want: true,
},
{
name: "valid ACR with subdomain",
registry: "myteam.myregistry.azurecr.io",
want: true,
},
{
name: "not an ACR registry",
registry: "gcr.io",
want: false,
},
{
name: "Docker Hub",
registry: "docker.io",
want: false,
},
{
name: "ECR registry",
registry: "123456789012.dkr.ecr.us-west-2.amazonaws.com",
want: false,
},
{
name: "missing registry name",
registry: ".azurecr.io",
want: true, // This is technically valid based on the current implementation
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isACR(tt.registry); got != tt.want {
t.Errorf("isACR() = %v, want %v", got, tt.want)
}
})
}
}

func TestAddOperation(t *testing.T) {
helper := &ACRHelper{}
err := helper.Add(nil)
if err == nil {
t.Error("Expected error for unimplemented Add operation, got nil")
}
if !strings.Contains(err.Error(), "unimplemented") {
t.Errorf("Expected 'unimplemented' in error message, got: %s", err.Error())
}
}

func TestDeleteOperation(t *testing.T) {
helper := &ACRHelper{}
err := helper.Delete("registry.azurecr.io")
if err == nil {
t.Error("Expected error for unimplemented Delete operation, got nil")
}
if !strings.Contains(err.Error(), "unimplemented") {
t.Errorf("Expected 'unimplemented' in error message, got: %s", err.Error())
}
}

func TestListOperation(t *testing.T) {
helper := &ACRHelper{}
_, err := helper.List()
if err == nil {
t.Error("Expected error for unimplemented List operation, got nil")
}
if !strings.Contains(err.Error(), "unimplemented") {
t.Errorf("Expected 'unimplemented' in error message, got: %s", err.Error())
}
}

// We can't easily test the Get method without mocking Azure SDK components,
// but we can at least test the non-ACR registry case
func TestGetNonACRRegistry(t *testing.T) {
helper := &ACRHelper{}
_, _, err := helper.Get("gcr.io")
if err == nil {
t.Error("Expected error for non-ACR registry, got nil")
}
if !strings.Contains(err.Error(), "not an ACR registry") {
t.Errorf("Expected 'not an ACR registry' in error message, got: %s", err.Error())
}
}
Loading
Loading