github.com/fnproject/cli@v0.0.0-20240508150455-e5d88bd86117/commands/image_signature_test.go (about)

     1  package commands
     2  
     3  import (
     4  	"crypto/rsa"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"github.com/fnproject/cli/common"
     8  	"github.com/fnproject/cli/config"
     9  	"github.com/fnproject/fn_go/provider/oracle"
    10  	ociCommon "github.com/oracle/oci-go-sdk/v65/common"
    11  	"github.com/spf13/viper"
    12  	"net/url"
    13  	"testing"
    14  )
    15  
    16  type mockConfigurationProvider struct {
    17  	region string
    18  }
    19  
    20  func (mcp *mockConfigurationProvider) TenancyOCID() (string, error)            { return "", nil }
    21  func (mcp *mockConfigurationProvider) UserOCID() (string, error)               { return "", nil }
    22  func (mcp *mockConfigurationProvider) KeyID() (string, error)                  { return "", nil }
    23  func (mcp *mockConfigurationProvider) KeyFingerprint() (string, error)         { return "", nil }
    24  func (mcp *mockConfigurationProvider) PrivateRSAKey() (*rsa.PrivateKey, error) { return nil, nil }
    25  func (mcp *mockConfigurationProvider) AuthType() (ociCommon.AuthConfig, error) {
    26  	return ociCommon.AuthConfig{}, nil
    27  }
    28  func (mcp *mockConfigurationProvider) Region() (string, error) { return mcp.region, nil }
    29  
    30  var _ ociCommon.ConfigurationProvider = &mockConfigurationProvider{}
    31  
    32  func TestIsSignatureConfigured(t *testing.T) {
    33  	// signature configuration is valid if all 4 values are set
    34  	signingDetails := common.SigningDetails{
    35  		ImageCompartmentId: "ocid1.compartment.test",
    36  		KmsKeyId:           "ocid1.kmskey.test",
    37  		KmsKeyVersionId:    "ocid1.kmskeyversion.test",
    38  		SigningAlgorithm:   "SHA_256_RSA_PKCS_PSS",
    39  	}
    40  	configured, err := isSignatureConfigured(signingDetails)
    41  	if !configured {
    42  		t.Fatal("expected true")
    43  	}
    44  	if err != nil {
    45  		t.Fatalf("expected no error, but found %s", err)
    46  	}
    47  	// signature configuration is invalid if partial values are set
    48  	signingDetails.ImageCompartmentId = ""
    49  	configured, err = isSignatureConfigured(signingDetails)
    50  	if err == nil {
    51  		t.Fatal("expected error")
    52  	}
    53  	// signature configuration is valid if no values are set
    54  	signingDetails = common.SigningDetails{}
    55  	configured, err = isSignatureConfigured(signingDetails)
    56  	if configured {
    57  		t.Fatal("expected false")
    58  	}
    59  	if err != nil {
    60  		t.Fatalf("expected no error, but found %s", err)
    61  	}
    62  }
    63  
    64  func TestGetRegion(t *testing.T) {
    65  	// when FnApiUrl is set, retrieve region from the URL
    66  	oracleProvider := &oracle.OracleProvider{
    67  		FnApiUrl: &url.URL{Host: "functions.us-ashburn-1.oci.oraclecloud.com"},
    68  	}
    69  	region := getRegion(oracleProvider)
    70  	expected := "us-ashburn-1"
    71  	if region != expected {
    72  		t.Fatalf("expected %s, but found %s", expected, region)
    73  	}
    74  	// when FnApiUrl is not set or cannot be parsed, retrieve region from OCI configuration provider
    75  	oracleProvider.FnApiUrl.Host = "functions.com"
    76  	oracleProvider.ConfigurationProvider = &mockConfigurationProvider{"us-phoenix-1"}
    77  	region = getRegion(oracleProvider)
    78  	expected = "us-phoenix-1"
    79  	if region != expected {
    80  		t.Fatalf("expected %s, but found %s", expected, region)
    81  	}
    82  }
    83  
    84  func TestGetRepositoryName(t *testing.T) {
    85  	viper.Set(config.EnvFnRegistry, "iad.ocir.io/test")
    86  	ff := &common.FuncFileV20180708{
    87  		Version: "1.0.0",
    88  		Name:    "testfn",
    89  	}
    90  	repositoryName, err := getRepositoryName(ff)
    91  	if err != nil {
    92  		t.Fatalf("expected no error, but found %s", err)
    93  	}
    94  	expected := "testfn"
    95  	if repositoryName != expected {
    96  		t.Fatalf("expected %s, but found %s", expected, repositoryName)
    97  	}
    98  	viper.Set(config.EnvFnRegistry, "iad.ocir.io/test/test2")
    99  	repositoryName, err = getRepositoryName(ff)
   100  	if err != nil {
   101  		t.Fatalf("expected no error, but found %s", err)
   102  	}
   103  	expected = "test2/testfn"
   104  	if repositoryName != expected {
   105  		t.Fatalf("expected %s, but found %s", expected, repositoryName)
   106  	}
   107  }
   108  
   109  func TestCreateImageSignatureMessage(t *testing.T) {
   110  	region, imageDigest, repositoryName := "us-ashburn-1", "sha256:digestvalue", "test/reponame"
   111  	signingDetails := common.SigningDetails{
   112  		ImageCompartmentId: "ocid1.compartment.test",
   113  		KmsKeyId:           "ocid1.key.test",
   114  		KmsKeyVersionId:    "ocid1.keyversion.test",
   115  		SigningAlgorithm:   "SHA_256_RSA_PKCS_PSS",
   116  	}
   117  	message, err := createImageSignatureMessage(region, imageDigest, repositoryName, signingDetails)
   118  	if err != nil {
   119  		t.Fatalf("expected no error, but found %s", err)
   120  	}
   121  	messageBytes, _ := json.Marshal(&Message{
   122  		Description:      "image signed by fn CLI",
   123  		ImageDigest:      imageDigest,
   124  		KmsKeyId:         signingDetails.KmsKeyId,
   125  		KmsKeyVersionId:  signingDetails.KmsKeyVersionId,
   126  		Metadata:         "{\"signedBy\":\"fn CLI\"}",
   127  		Region:           region,
   128  		RepositoryName:   repositoryName,
   129  		SigningAlgorithm: signingDetails.SigningAlgorithm,
   130  	})
   131  	expectedMessage := base64.StdEncoding.EncodeToString(messageBytes)
   132  	if message != expectedMessage {
   133  		t.Fatalf("expected %s, but found %s", expectedMessage, message)
   134  	}
   135  }
   136  
   137  func TestBuildCryptoEndpoint(t *testing.T) {
   138  	// test old style regional endpoints
   139  	region, keyId := "us-ashburn-1", "ocid1.key.oc1.iad.testvault.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh"
   140  	endpoint, err := buildCryptoEndpoint(region, keyId)
   141  	if err != nil {
   142  		t.Fatalf("expected no error, but found %s", err)
   143  	}
   144  	expected := "https://testvault-crypto.kms.us-ashburn-1.oraclecloud.com"
   145  	if endpoint != expected {
   146  		t.Fatalf("expected %s, found %s", expected, endpoint)
   147  	}
   148  	// test new style regional endpoints
   149  	region, keyId = "us-sanjose-1", "ocid1.key.oc1.us-sanjose-1.testvault.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefgh"
   150  	endpoint, err = buildCryptoEndpoint(region, keyId)
   151  	if err != nil {
   152  		t.Fatalf("expected no error, but found %s", err)
   153  	}
   154  	expected = "https://testvault-crypto.kms.us-sanjose-1.oci.oraclecloud.com"
   155  	if endpoint != expected {
   156  		t.Fatalf("expected %s, found %s", expected, endpoint)
   157  	}
   158  	// invalid key results in error
   159  	keyId = "invalidocid"
   160  	endpoint, err = buildCryptoEndpoint(region, keyId)
   161  	if err == nil {
   162  		t.Fatalf("expected error, but found %s", endpoint)
   163  	}
   164  }
   165  
   166  func TestFindMissingValues(t *testing.T) {
   167  	tests := map[string]common.SigningDetails{
   168  		"kms_key_id,kms_key_version_id,signing_algorithm": {ImageCompartmentId: "test"},
   169  		"kms_key_version_id,signing_algorithm":            {ImageCompartmentId: "test", KmsKeyId: "test"},
   170  		"signing_algorithm":                               {ImageCompartmentId: "test", KmsKeyId: "test", KmsKeyVersionId: "test"},
   171  	}
   172  	for expected, signingDetails := range tests {
   173  		actual := findMissingValues(signingDetails)
   174  		if actual != expected {
   175  			t.Fatalf("input: %+v, expected: %s, actual: %s", signingDetails, expected, actual)
   176  		}
   177  	}
   178  }