...

Source file src/github.com/sigstore/rekor/cmd/rekor-cli/app/pflags_test.go

Documentation: github.com/sigstore/rekor/cmd/rekor-cli/app

     1  //
     2  // Copyright 2021 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package app
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"net/http"
    22  	"net/http/httptest"
    23  	"os"
    24  	"testing"
    25  
    26  	"github.com/spf13/cobra"
    27  	"github.com/spf13/viper"
    28  
    29  	"github.com/sigstore/rekor/pkg/types"
    30  )
    31  
    32  func TestArtifactPFlags(t *testing.T) {
    33  	type test struct {
    34  		caseDesc              string
    35  		typeStr               string
    36  		entry                 string
    37  		artifact              string
    38  		signature             string
    39  		publicKey             string
    40  		multiPublicKey        []string
    41  		uuid                  string
    42  		aad                   string
    43  		uuidRequired          bool
    44  		logIndex              string
    45  		logIndexRequired      bool
    46  		expectParseSuccess    bool
    47  		expectValidateSuccess bool
    48  	}
    49  
    50  	testServer := httptest.NewServer(http.HandlerFunc(
    51  		func(w http.ResponseWriter, r *http.Request) {
    52  			file := []byte{}
    53  			var err error
    54  
    55  			switch r.URL.Path {
    56  			case "/artifact":
    57  				file, err = os.ReadFile("tests/test_file.txt")
    58  			case "/signature":
    59  				file, err = os.ReadFile("tests/test_file.sig")
    60  			case "/publicKey":
    61  				file, err = os.ReadFile("tests/test_public_key.key")
    62  			case "/rekord":
    63  				file, err = os.ReadFile("tests/rekor.json")
    64  			case "/rpmEntry":
    65  				file, err = os.ReadFile("tests/rpm.json")
    66  			case "/rpm":
    67  				file, err = os.ReadFile("tests/test.rpm")
    68  			case "/rpmPublicKey":
    69  				file, err = os.ReadFile("tests/test_rpm_public_key.key")
    70  			case "/alpine":
    71  				file, err = os.ReadFile("tests/test_alpine.apk")
    72  			case "/alpinePublicKey":
    73  				file, err = os.ReadFile("tests/test_alpine.pub")
    74  			case "/alpineEntry":
    75  				file, err = os.ReadFile("tests/alpine.json")
    76  			case "/helmEntry":
    77  				file, err = os.ReadFile("tests/helm.json")
    78  			case "/not_found":
    79  				err = errors.New("file not found")
    80  			}
    81  			if err != nil {
    82  				w.WriteHeader(http.StatusNotFound)
    83  				return
    84  			}
    85  			w.WriteHeader(http.StatusOK)
    86  			_, _ = w.Write(file)
    87  		}))
    88  	defer testServer.Close()
    89  
    90  	tests := []test{
    91  		{
    92  			caseDesc:              "valid rekord file",
    93  			entry:                 "tests/rekor.json",
    94  			expectParseSuccess:    true,
    95  			expectValidateSuccess: true,
    96  		},
    97  		{
    98  			caseDesc:              "valid rekord URL",
    99  			entry:                 testServer.URL + "/rekord",
   100  			expectParseSuccess:    true,
   101  			expectValidateSuccess: true,
   102  		},
   103  		{
   104  			caseDesc:              "valid rekord file, wrong type",
   105  			typeStr:               "rpm",
   106  			entry:                 "tests/rekor.json",
   107  			expectParseSuccess:    true,
   108  			expectValidateSuccess: false,
   109  		},
   110  		{
   111  			caseDesc:              "valid rpm file",
   112  			entry:                 "tests/rpm.json",
   113  			typeStr:               "rpm",
   114  			expectParseSuccess:    true,
   115  			expectValidateSuccess: true,
   116  		},
   117  		{
   118  			caseDesc:              "valid rpm URL",
   119  			entry:                 testServer.URL + "/rpmEntry",
   120  			typeStr:               "rpm",
   121  			expectParseSuccess:    true,
   122  			expectValidateSuccess: true,
   123  		},
   124  		{
   125  			caseDesc:              "valid alpine URL",
   126  			entry:                 testServer.URL + "/alpineEntry",
   127  			typeStr:               "alpine",
   128  			expectParseSuccess:    true,
   129  			expectValidateSuccess: true,
   130  		},
   131  		{
   132  			caseDesc:              "valid helm URL",
   133  			entry:                 testServer.URL + "/helmEntry",
   134  			typeStr:               "helm",
   135  			expectParseSuccess:    true,
   136  			expectValidateSuccess: true,
   137  		},
   138  
   139  		{
   140  			caseDesc:              "valid rpm file, wrong type",
   141  			typeStr:               "rekord",
   142  			entry:                 "tests/rpm.json",
   143  			expectParseSuccess:    true,
   144  			expectValidateSuccess: false,
   145  		},
   146  		{
   147  			caseDesc:              "non-existent rekord file",
   148  			entry:                 "tests/not_there.json",
   149  			expectParseSuccess:    false,
   150  			expectValidateSuccess: false,
   151  		},
   152  		{
   153  			caseDesc:              "non-existent rekord url",
   154  			entry:                 testServer.URL + "/not_found",
   155  			expectParseSuccess:    true,
   156  			expectValidateSuccess: false,
   157  		},
   158  		{
   159  			caseDesc:              "valid rekord - local artifact with required flags",
   160  			artifact:              "tests/test_file.txt",
   161  			signature:             "tests/test_file.sig",
   162  			publicKey:             "tests/test_public_key.key",
   163  			expectParseSuccess:    true,
   164  			expectValidateSuccess: true,
   165  		},
   166  		{
   167  			caseDesc:              "valid rpm - local artifact with required flags",
   168  			typeStr:               "rpm",
   169  			artifact:              "tests/test.rpm",
   170  			publicKey:             "tests/test_rpm_public_key.key",
   171  			expectParseSuccess:    true,
   172  			expectValidateSuccess: true,
   173  		},
   174  		{
   175  			caseDesc:              "valid alpine - local artifact with required flags",
   176  			typeStr:               "alpine",
   177  			artifact:              "tests/test_alpine.apk",
   178  			publicKey:             "tests/test_alpine.pub",
   179  			expectParseSuccess:    true,
   180  			expectValidateSuccess: true,
   181  		},
   182  		{
   183  			caseDesc:              "nonexistent local artifact",
   184  			artifact:              "tests/not_a_file",
   185  			signature:             "tests/test_file.sig",
   186  			publicKey:             "tests/test_public_key.key",
   187  			expectParseSuccess:    false,
   188  			expectValidateSuccess: false,
   189  		},
   190  		{
   191  			caseDesc:              "nonexistent remote artifact",
   192  			artifact:              testServer.URL + "/not_found",
   193  			signature:             "tests/test_file.sig",
   194  			publicKey:             "tests/test_public_key.key",
   195  			expectParseSuccess:    true,
   196  			expectValidateSuccess: false,
   197  		},
   198  		{
   199  			caseDesc:              "local artifact without required local signature",
   200  			artifact:              "tests/test_file.txt",
   201  			publicKey:             "tests/test_public_key.key",
   202  			expectParseSuccess:    true,
   203  			expectValidateSuccess: false,
   204  		},
   205  		{
   206  			caseDesc:              "local artifact with missing remote signature",
   207  			artifact:              "tests/test_file.txt",
   208  			publicKey:             "tests/test_public_key.key",
   209  			signature:             testServer.URL + "/not_found",
   210  			expectParseSuccess:    true,
   211  			expectValidateSuccess: false,
   212  		},
   213  		{
   214  			caseDesc:              "local artifact with invalid local signature",
   215  			artifact:              "tests/test_file.txt",
   216  			signature:             "tests/not_a_file",
   217  			publicKey:             "tests/test_public_key.key",
   218  			expectParseSuccess:    false,
   219  			expectValidateSuccess: false,
   220  		},
   221  		{
   222  			caseDesc:              "local artifact with invalid remote signature",
   223  			artifact:              "tests/test_file.txt",
   224  			signature:             testServer.URL + "/artifact",
   225  			publicKey:             "tests/test_public_key.key",
   226  			expectParseSuccess:    true,
   227  			expectValidateSuccess: false,
   228  		},
   229  		{
   230  			caseDesc:              "local artifact without required public key",
   231  			artifact:              "tests/test_file.txt",
   232  			signature:             "tests/test_file.sig",
   233  			expectParseSuccess:    true,
   234  			expectValidateSuccess: false,
   235  		},
   236  		{
   237  			caseDesc:              "local artifact with invalid local public key",
   238  			artifact:              "tests/test_file.txt",
   239  			signature:             "tests/test_file.sig",
   240  			publicKey:             "tests/not_a_file",
   241  			expectParseSuccess:    false,
   242  			expectValidateSuccess: false,
   243  		},
   244  		{
   245  			caseDesc:              "local artifact with invalid remote public key",
   246  			artifact:              "tests/test_file.txt",
   247  			signature:             "tests/test_file.sig",
   248  			publicKey:             testServer.URL + "/artifact",
   249  			expectParseSuccess:    true,
   250  			expectValidateSuccess: false,
   251  		},
   252  		{
   253  			caseDesc:              "valid rekord - remote artifact with required flags",
   254  			artifact:              testServer.URL + "/artifact",
   255  			signature:             "tests/test_file.sig",
   256  			publicKey:             "tests/test_public_key.key",
   257  			expectParseSuccess:    true,
   258  			expectValidateSuccess: true,
   259  		},
   260  		{
   261  			caseDesc:              "valid rpm - remote artifact with required flags",
   262  			typeStr:               "rpm",
   263  			artifact:              testServer.URL + "/rpm",
   264  			publicKey:             "tests/test_rpm_public_key.key",
   265  			expectParseSuccess:    true,
   266  			expectValidateSuccess: true,
   267  		},
   268  		{
   269  			caseDesc:              "valid alpine - remote artifact with required flags",
   270  			typeStr:               "alpine",
   271  			artifact:              testServer.URL + "/alpine",
   272  			publicKey:             "tests/test_alpine.pub",
   273  			expectParseSuccess:    true,
   274  			expectValidateSuccess: true,
   275  		},
   276  		{
   277  			caseDesc:              "remote artifact with invalid URL",
   278  			artifact:              "hteeteep%**/test_file.txt",
   279  			signature:             "tests/test_file.sig",
   280  			publicKey:             "tests/test_public_key.key",
   281  			expectParseSuccess:    false,
   282  			expectValidateSuccess: false,
   283  		},
   284  		{
   285  			caseDesc:              "valid uuid",
   286  			uuid:                  "3030303030303030303030303030303030303030303030303030303030303030",
   287  			uuidRequired:          true,
   288  			expectParseSuccess:    true,
   289  			expectValidateSuccess: true,
   290  		},
   291  		{
   292  			caseDesc:              "invalid uuid",
   293  			uuid:                  "not_a_uuid",
   294  			uuidRequired:          true,
   295  			expectParseSuccess:    false,
   296  			expectValidateSuccess: false,
   297  		},
   298  		{
   299  			caseDesc:              "unwanted uuid",
   300  			uuid:                  "3030303030303030303030303030303030303030303030303030303030303030",
   301  			uuidRequired:          false,
   302  			expectParseSuccess:    true,
   303  			expectValidateSuccess: false,
   304  		},
   305  		{
   306  			caseDesc:              "valid log index",
   307  			logIndex:              "1",
   308  			logIndexRequired:      true,
   309  			expectParseSuccess:    true,
   310  			expectValidateSuccess: true,
   311  		},
   312  		{
   313  			caseDesc:              "invalid log index",
   314  			logIndex:              "not_a_int",
   315  			logIndexRequired:      true,
   316  			expectParseSuccess:    false,
   317  			expectValidateSuccess: false,
   318  		},
   319  		{
   320  			caseDesc:              "invalid log index - less than 0",
   321  			logIndex:              "-1",
   322  			logIndexRequired:      true,
   323  			expectParseSuccess:    false,
   324  			expectValidateSuccess: false,
   325  		},
   326  		{
   327  			caseDesc:              "unwanted log index",
   328  			logIndex:              "1",
   329  			logIndexRequired:      false,
   330  			expectParseSuccess:    true,
   331  			expectValidateSuccess: false,
   332  		},
   333  		{
   334  			caseDesc:              "no flags when either uuid, rekord, or artifact++ are needed",
   335  			uuidRequired:          false,
   336  			expectParseSuccess:    true,
   337  			expectValidateSuccess: false,
   338  		},
   339  		{
   340  			caseDesc:              "missing uuid flag when it is needed",
   341  			uuidRequired:          true,
   342  			expectParseSuccess:    true,
   343  			expectValidateSuccess: false,
   344  		},
   345  		{
   346  			caseDesc:              "missing log index flag when it is needed",
   347  			logIndexRequired:      true,
   348  			expectParseSuccess:    true,
   349  			expectValidateSuccess: false,
   350  		},
   351  		{
   352  			caseDesc:              "valid cose, with aad",
   353  			typeStr:               "cose",
   354  			artifact:              "tests/test_cose.cbor",
   355  			publicKey:             "tests/test_cose.pub",
   356  			expectParseSuccess:    true,
   357  			expectValidateSuccess: true,
   358  			aad:                   "dGVzdCBhYWQ=",
   359  		},
   360  		{
   361  			caseDesc:              "valid cose, malformed base64 aad",
   362  			typeStr:               "cose",
   363  			artifact:              "tests/test_cose.cbor",
   364  			publicKey:             "tests/test_cose.pub",
   365  			expectParseSuccess:    false,
   366  			expectValidateSuccess: true,
   367  			aad:                   "dGVzdCBhYWQ]",
   368  		},
   369  		{
   370  			caseDesc:              "valid cose, missing aad",
   371  			typeStr:               "cose",
   372  			artifact:              "tests/test_cose.cbor",
   373  			publicKey:             "tests/test_cose.pub",
   374  			expectParseSuccess:    true,
   375  			expectValidateSuccess: false,
   376  		},
   377  		{
   378  			caseDesc:              "valid intoto - one keys",
   379  			typeStr:               "intoto",
   380  			artifact:              "tests/intoto_dsse.json",
   381  			publicKey:             "tests/intoto_dsse.pem",
   382  			expectParseSuccess:    true,
   383  			expectValidateSuccess: true,
   384  		},
   385  		{
   386  			caseDesc:              "valid intoto - multi keys",
   387  			typeStr:               "intoto",
   388  			artifact:              "tests/intoto_multi_dsse.json",
   389  			multiPublicKey:        []string{"tests/intoto_dsse.pem", "tests/intoto_multi_pub2.pem"},
   390  			expectParseSuccess:    true,
   391  			expectValidateSuccess: true,
   392  		},
   393  	}
   394  
   395  	for _, tc := range tests {
   396  		initializePFlagMap()
   397  		var blankCmd = &cobra.Command{}
   398  		if err := addArtifactPFlags(blankCmd); err != nil {
   399  			t.Fatalf("unexpected error adding flags in '%v': %v", tc.caseDesc, err)
   400  		}
   401  		if err := addUUIDPFlags(blankCmd, tc.uuidRequired); err != nil {
   402  			t.Fatalf("unexpected error adding uuid flags in '%v': %v", tc.caseDesc, err)
   403  		}
   404  		if err := addLogIndexFlag(blankCmd, tc.logIndexRequired); err != nil {
   405  			t.Fatalf("unexpected error adding log index flags in '%v': %v", tc.caseDesc, err)
   406  		}
   407  
   408  		args := []string{}
   409  
   410  		if tc.entry != "" {
   411  			args = append(args, "--entry", tc.entry)
   412  		}
   413  		if tc.typeStr != "" {
   414  			args = append(args, "--type", tc.typeStr)
   415  		}
   416  		if tc.artifact != "" {
   417  			args = append(args, "--artifact", tc.artifact)
   418  		}
   419  		if tc.signature != "" {
   420  			args = append(args, "--signature", tc.signature)
   421  		}
   422  		if tc.publicKey != "" {
   423  			args = append(args, "--public-key", tc.publicKey)
   424  		}
   425  		if len(tc.multiPublicKey) > 0 {
   426  			for _, key := range tc.multiPublicKey {
   427  				args = append(args, "--public-key", key)
   428  			}
   429  		}
   430  		if tc.uuid != "" {
   431  			args = append(args, "--uuid", tc.uuid)
   432  		}
   433  		if tc.logIndex != "" {
   434  			args = append(args, "--log-index", tc.logIndex)
   435  		}
   436  		if tc.aad != "" {
   437  			args = append(args, "--aad", tc.aad)
   438  		}
   439  
   440  		if err := blankCmd.ParseFlags(args); (err == nil) != tc.expectParseSuccess {
   441  			t.Errorf("unexpected result parsing '%v': %v", tc.caseDesc, err)
   442  			continue
   443  		}
   444  
   445  		if tc.expectValidateSuccess {
   446  			if err := viper.BindPFlags(blankCmd.Flags()); err != nil {
   447  				t.Fatalf("unexpected result initializing viper in '%v': %v", tc.caseDesc, err)
   448  			}
   449  			if err := validateArtifactPFlags(tc.uuidRequired, tc.logIndexRequired); (err == nil) != tc.expectValidateSuccess {
   450  				t.Errorf("unexpected result validating '%v': %v", tc.caseDesc, err)
   451  				continue
   452  			}
   453  			if !tc.uuidRequired && !tc.logIndexRequired && tc.entry == "" {
   454  				typeStr, versionStr, err := ParseTypeFlag(viper.GetString("type"))
   455  				if err != nil {
   456  					t.Fatalf("error parsing typeStr: %v", err)
   457  				}
   458  				props := CreatePropsFromPflags()
   459  				if _, err := types.NewProposedEntry(context.Background(), typeStr, versionStr, *props); err != nil {
   460  					t.Errorf("unexpected result in '%v' building entry: %v", tc.caseDesc, err)
   461  				}
   462  			}
   463  		}
   464  	}
   465  }
   466  
   467  func TestValidateRekorServerURL(t *testing.T) {
   468  	type test struct {
   469  		caseDesc      string
   470  		rekorServer   string
   471  		expectSuccess bool
   472  	}
   473  
   474  	tests := []test{
   475  		{
   476  			caseDesc:      "value not specified",
   477  			expectSuccess: false,
   478  		},
   479  		{
   480  			caseDesc:      "valid rekor_server value",
   481  			rekorServer:   "http://localhost:3000",
   482  			expectSuccess: true,
   483  		},
   484  		{
   485  			caseDesc:      "valid URL, invalid scheme",
   486  			rekorServer:   "ldap://localhost:3000",
   487  			expectSuccess: false,
   488  		},
   489  		{
   490  			caseDesc:      "invalid URL",
   491  			rekorServer:   "hteeteepeeColonSlashSlashlocalhost:3000",
   492  			expectSuccess: false,
   493  		},
   494  		{
   495  			caseDesc:      "local path",
   496  			rekorServer:   "/localhost",
   497  			expectSuccess: false,
   498  		},
   499  	}
   500  
   501  	for _, tc := range tests {
   502  		if err := rootCmd.PersistentFlags().Set("rekor_server", tc.rekorServer); (err == nil) != tc.expectSuccess {
   503  			t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err)
   504  		}
   505  	}
   506  }
   507  
   508  // TestValidateRetryCount tests the validation of the retry count flag
   509  func TestValidateRetryCount(t *testing.T) {
   510  	type test struct {
   511  		caseDesc      string
   512  		retryCount    string
   513  		expectSuccess bool
   514  	}
   515  
   516  	tests := []test{
   517  		{
   518  			caseDesc:      "value not specified",
   519  			expectSuccess: false,
   520  		},
   521  		{
   522  			caseDesc:      "valid retry_count value: 0",
   523  			retryCount:    "0",
   524  			expectSuccess: true,
   525  		},
   526  		{
   527  			caseDesc:      "valid retry_count value: 1",
   528  			retryCount:    "1",
   529  			expectSuccess: true,
   530  		},
   531  		{
   532  			caseDesc:      "invalid retry_count value: asdf",
   533  			retryCount:    "asdf",
   534  			expectSuccess: false,
   535  		},
   536  		{
   537  			caseDesc:      "invalid retry_count value: -1",
   538  			retryCount:    "-1",
   539  			expectSuccess: false,
   540  		},
   541  	}
   542  
   543  	for _, tc := range tests {
   544  		if err := rootCmd.PersistentFlags().Set("retry", tc.retryCount); (err == nil) != tc.expectSuccess {
   545  			t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err)
   546  		}
   547  	}
   548  }
   549  
   550  func TestSearchPFlags(t *testing.T) {
   551  	type test struct {
   552  		caseDesc              string
   553  		artifact              string
   554  		publicKey             string
   555  		sha                   string
   556  		email                 string
   557  		pkiFormat             string
   558  		expectParseSuccess    bool
   559  		expectValidateSuccess bool
   560  	}
   561  
   562  	testServer := httptest.NewServer(http.HandlerFunc(
   563  		func(w http.ResponseWriter, r *http.Request) {
   564  			file := []byte{}
   565  			var err error
   566  
   567  			switch r.URL.Path {
   568  			case "/artifact":
   569  				file, err = os.ReadFile("tests/test_file.txt")
   570  			case "/publicKey":
   571  				file, err = os.ReadFile("tests/test_public_key.key")
   572  			case "/not_found":
   573  				err = errors.New("file not found")
   574  			}
   575  			if err != nil {
   576  				w.WriteHeader(http.StatusNotFound)
   577  				return
   578  			}
   579  			w.WriteHeader(http.StatusOK)
   580  			_, _ = w.Write(file)
   581  		}))
   582  	defer testServer.Close()
   583  
   584  	tests := []test{
   585  		{
   586  			caseDesc:              "valid local artifact",
   587  			artifact:              "tests/test_file.txt",
   588  			expectParseSuccess:    true,
   589  			expectValidateSuccess: true,
   590  		},
   591  		{
   592  			caseDesc:              "valid remote artifact",
   593  			artifact:              testServer.URL + "/artifact",
   594  			expectParseSuccess:    true,
   595  			expectValidateSuccess: true,
   596  		},
   597  		{
   598  			caseDesc:              "nonexistent local artifact",
   599  			artifact:              "tests/not_a_file",
   600  			expectParseSuccess:    false,
   601  			expectValidateSuccess: false,
   602  		},
   603  		{
   604  			caseDesc:              "nonexistent remote artifact",
   605  			artifact:              testServer.URL + "/not_found",
   606  			expectParseSuccess:    true,
   607  			expectValidateSuccess: true,
   608  		},
   609  		{
   610  			caseDesc:              "valid local public key",
   611  			publicKey:             "tests/test_public_key.key",
   612  			expectParseSuccess:    true,
   613  			expectValidateSuccess: true,
   614  		},
   615  		{
   616  			caseDesc:              "valid local minisign public key",
   617  			publicKey:             "../../../pkg/pki/minisign/testdata/minisign.pub",
   618  			pkiFormat:             "minisign",
   619  			expectParseSuccess:    true,
   620  			expectValidateSuccess: true,
   621  		},
   622  		{
   623  			caseDesc:              "valid remote public key",
   624  			publicKey:             testServer.URL + "/publicKey",
   625  			expectParseSuccess:    true,
   626  			expectValidateSuccess: true,
   627  		},
   628  		{
   629  			caseDesc:              "nonexistent local public key",
   630  			publicKey:             "tests/not_a_file",
   631  			expectParseSuccess:    false,
   632  			expectValidateSuccess: false,
   633  		},
   634  		{
   635  			caseDesc:              "nonexistent remote public key",
   636  			publicKey:             testServer.URL + "/not_found",
   637  			expectParseSuccess:    true,
   638  			expectValidateSuccess: true,
   639  		},
   640  		{
   641  			caseDesc:              "valid SHA1",
   642  			sha:                   "84374135959eacf60cf3fed7520a01b336332efe",
   643  			expectParseSuccess:    true,
   644  			expectValidateSuccess: true,
   645  		},
   646  		{
   647  			caseDesc:              "valid SHA1 with prefix",
   648  			sha:                   "sha1:84374135959eacf60cf3fed7520a01b336332efe",
   649  			expectParseSuccess:    true,
   650  			expectValidateSuccess: true,
   651  		},
   652  		{
   653  			caseDesc:              "valid SHA256",
   654  			sha:                   "45c7b11fcbf07dec1694adecd8c5b85770a12a6c8dfdcf2580a2db0c47c31779",
   655  			expectParseSuccess:    true,
   656  			expectValidateSuccess: true,
   657  		},
   658  		{
   659  			caseDesc:              "valid SHA256 with prefix",
   660  			sha:                   "sha256:45c7b11fcbf07dec1694adecd8c5b85770a12a6c8dfdcf2580a2db0c47c31779",
   661  			expectParseSuccess:    true,
   662  			expectValidateSuccess: true,
   663  		},
   664  		{
   665  			caseDesc:              "valid SHA512",
   666  			sha:                   "a5d575f245588b64bcec78a1bb9d92a66bfb4d68d7de1aea4162ad0b232753860cb764fd0645ada1f5d935163522987359e515e0594068d7bc108f0584d6da29",
   667  			expectParseSuccess:    true,
   668  			expectValidateSuccess: true,
   669  		},
   670  		{
   671  			caseDesc:              "valid SHA512 with prefix",
   672  			sha:                   "sha512:a5d575f245588b64bcec78a1bb9d92a66bfb4d68d7de1aea4162ad0b232753860cb764fd0645ada1f5d935163522987359e515e0594068d7bc108f0584d6da29",
   673  			expectParseSuccess:    true,
   674  			expectValidateSuccess: true,
   675  		},
   676  		{
   677  			caseDesc:              "invalid SHA prefix",
   678  			sha:                   "sha257:45c7b11fcbf07dec1694adecd8c5b85770a12a6c8dfdcf2580a2db0c47c31779",
   679  			expectParseSuccess:    false,
   680  			expectValidateSuccess: false,
   681  		},
   682  		{
   683  			caseDesc:              "invalid SHA",
   684  			sha:                   "45c7b11fcbf",
   685  			expectParseSuccess:    false,
   686  			expectValidateSuccess: false,
   687  		},
   688  		{
   689  			caseDesc:              "invalid hash alg",
   690  			sha:                   "md5:d408f34c27cf5930be6394a455f23d40",
   691  			expectParseSuccess:    false,
   692  			expectValidateSuccess: false,
   693  		},
   694  		{
   695  			caseDesc:              "valid email",
   696  			email:                 "cat@foo.com",
   697  			expectParseSuccess:    true,
   698  			expectValidateSuccess: true,
   699  		},
   700  		{
   701  			caseDesc:              "invalid email",
   702  			email:                 "SignaMeseCat",
   703  			expectParseSuccess:    false,
   704  			expectValidateSuccess: false,
   705  		},
   706  		{
   707  			caseDesc:              "no flags when either artifact, sha, public key, or email are needed",
   708  			expectParseSuccess:    true,
   709  			expectValidateSuccess: false,
   710  		},
   711  	}
   712  
   713  	for _, tc := range tests {
   714  		initializePFlagMap()
   715  		var blankCmd = &cobra.Command{}
   716  		if err := addSearchPFlags(blankCmd); err != nil {
   717  			t.Fatalf("unexpected error adding flags in '%v': %v", tc.caseDesc, err)
   718  		}
   719  
   720  		args := []string{}
   721  
   722  		if tc.artifact != "" {
   723  			args = append(args, "--artifact", tc.artifact)
   724  		}
   725  		if tc.publicKey != "" {
   726  			args = append(args, "--public-key", tc.publicKey)
   727  		}
   728  		if tc.pkiFormat != "" {
   729  			args = append(args, "--pki-format", tc.pkiFormat)
   730  		}
   731  		if tc.sha != "" {
   732  			args = append(args, "--sha", tc.sha)
   733  		}
   734  		if tc.email != "" {
   735  			args = append(args, "--email", tc.email)
   736  		}
   737  
   738  		if err := blankCmd.ParseFlags(args); (err == nil) != tc.expectParseSuccess {
   739  			t.Errorf("unexpected result parsing '%v': %v", tc.caseDesc, err)
   740  			continue
   741  		}
   742  
   743  		if err := viper.BindPFlags(blankCmd.Flags()); err != nil {
   744  			t.Fatalf("unexpected result initializing viper in '%v': %v", tc.caseDesc, err)
   745  		}
   746  		if err := validateSearchPFlags(); (err == nil) != tc.expectValidateSuccess {
   747  			t.Errorf("unexpected result validating '%v': %v", tc.caseDesc, err)
   748  			continue
   749  		}
   750  	}
   751  }
   752  
   753  func TestParseTypeFlag(t *testing.T) {
   754  	type test struct {
   755  		caseDesc      string
   756  		typeStr       string
   757  		expectSuccess bool
   758  	}
   759  
   760  	tests := []test{
   761  		{
   762  			caseDesc:      "bogus",
   763  			typeStr:       "bogus",
   764  			expectSuccess: false,
   765  		},
   766  		{
   767  			caseDesc:      "rekord",
   768  			typeStr:       "rekord",
   769  			expectSuccess: true,
   770  		},
   771  		{
   772  			caseDesc:      "explicit rekord v0.0.1",
   773  			typeStr:       "rekord:0.0.1",
   774  			expectSuccess: true,
   775  		},
   776  		{
   777  			caseDesc:      "non-existent rekord v0.0.0",
   778  			typeStr:       "rekord:0.0.0",
   779  			expectSuccess: false,
   780  		},
   781  		{
   782  			caseDesc:      "hashedrekord",
   783  			typeStr:       "hashedrekord",
   784  			expectSuccess: true,
   785  		},
   786  		{
   787  			caseDesc:      "explicit hashedrekord v0.0.1",
   788  			typeStr:       "hashedrekord:0.0.1",
   789  			expectSuccess: true,
   790  		},
   791  		{
   792  			caseDesc:      "non-existent hashedrekord v0.0.0",
   793  			typeStr:       "hashedrekord:0.0.0",
   794  			expectSuccess: false,
   795  		},
   796  		{
   797  			caseDesc:      "alpine",
   798  			typeStr:       "alpine",
   799  			expectSuccess: true,
   800  		},
   801  		{
   802  			caseDesc:      "explicit alpine v0.0.1",
   803  			typeStr:       "alpine:0.0.1",
   804  			expectSuccess: true,
   805  		},
   806  		{
   807  			caseDesc:      "non-existent alpine v0.0.0",
   808  			typeStr:       "alpine:0.0.0",
   809  			expectSuccess: false,
   810  		},
   811  		{
   812  			caseDesc:      "cose",
   813  			typeStr:       "cose",
   814  			expectSuccess: true,
   815  		},
   816  		{
   817  			caseDesc:      "explicit cose v0.0.1",
   818  			typeStr:       "cose:0.0.1",
   819  			expectSuccess: true,
   820  		},
   821  		{
   822  			caseDesc:      "non-existent cose v0.0.0",
   823  			typeStr:       "cose:0.0.0",
   824  			expectSuccess: false,
   825  		},
   826  		{
   827  			caseDesc:      "helm",
   828  			typeStr:       "helm",
   829  			expectSuccess: true,
   830  		},
   831  		{
   832  			caseDesc:      "explicit helm v0.0.1",
   833  			typeStr:       "helm:0.0.1",
   834  			expectSuccess: true,
   835  		},
   836  		{
   837  			caseDesc:      "non-existent helm v0.0.0",
   838  			typeStr:       "helm:0.0.0",
   839  			expectSuccess: false,
   840  		},
   841  		{
   842  			caseDesc:      "intoto",
   843  			typeStr:       "intoto",
   844  			expectSuccess: true,
   845  		},
   846  		{
   847  			caseDesc:      "explicit intoto v0.0.1",
   848  			typeStr:       "intoto:0.0.1",
   849  			expectSuccess: true,
   850  		},
   851  		{
   852  			caseDesc:      "explicit intoto v0.0.2",
   853  			typeStr:       "intoto:0.0.2",
   854  			expectSuccess: true,
   855  		},
   856  		{
   857  			caseDesc:      "non-existent intoto v0.0.0",
   858  			typeStr:       "intoto:0.0.0",
   859  			expectSuccess: false,
   860  		},
   861  		{
   862  			caseDesc:      "jar",
   863  			typeStr:       "jar",
   864  			expectSuccess: true,
   865  		},
   866  		{
   867  			caseDesc:      "explicit jar v0.0.1",
   868  			typeStr:       "jar:0.0.1",
   869  			expectSuccess: true,
   870  		},
   871  		{
   872  			caseDesc:      "non-existent jar v0.0.0",
   873  			typeStr:       "jar:0.0.0",
   874  			expectSuccess: false,
   875  		},
   876  		{
   877  			caseDesc:      "rfc3161",
   878  			typeStr:       "rfc3161",
   879  			expectSuccess: true,
   880  		},
   881  		{
   882  			caseDesc:      "explicit rfc3161 v0.0.1",
   883  			typeStr:       "rfc3161:0.0.1",
   884  			expectSuccess: true,
   885  		},
   886  		{
   887  			caseDesc:      "non-existent rfc3161 v0.0.0",
   888  			typeStr:       "rfc3161:0.0.0",
   889  			expectSuccess: false,
   890  		},
   891  		{
   892  			caseDesc:      "rpm",
   893  			typeStr:       "rpm",
   894  			expectSuccess: true,
   895  		},
   896  		{
   897  			caseDesc:      "explicit rpm v0.0.1",
   898  			typeStr:       "rpm:0.0.1",
   899  			expectSuccess: true,
   900  		},
   901  		{
   902  			caseDesc:      "non-existent rpm v0.0.0",
   903  			typeStr:       "rpm:0.0.0",
   904  			expectSuccess: false,
   905  		},
   906  		{
   907  			caseDesc:      "tuf",
   908  			typeStr:       "tuf",
   909  			expectSuccess: true,
   910  		},
   911  		{
   912  			caseDesc:      "explicit tuf v0.0.1",
   913  			typeStr:       "tuf:0.0.1",
   914  			expectSuccess: true,
   915  		},
   916  		{
   917  			caseDesc:      "non-existent tuf v0.0.0",
   918  			typeStr:       "tuf:0.0.0",
   919  			expectSuccess: false,
   920  		},
   921  	}
   922  
   923  	for _, tc := range tests {
   924  		if _, _, err := ParseTypeFlag(tc.typeStr); (err == nil) != tc.expectSuccess {
   925  			t.Fatalf("unexpected error parsing type flag in '%v': %v", tc.caseDesc, err)
   926  		}
   927  	}
   928  }
   929  

View as plain text