...

Source file src/github.com/sigstore/cosign/v2/test/helpers.go

Documentation: github.com/sigstore/cosign/v2/test

     1  //
     2  // Copyright 2024 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  //go:build e2e
    17  
    18  package test
    19  
    20  import (
    21  	"context"
    22  	"crypto"
    23  	"net/http/httptest"
    24  	"net/url"
    25  	"os"
    26  	"path/filepath"
    27  	"testing"
    28  
    29  	"github.com/google/go-cmp/cmp"
    30  	"github.com/google/go-containerregistry/pkg/authn"
    31  	"github.com/google/go-containerregistry/pkg/name"
    32  	"github.com/google/go-containerregistry/pkg/registry"
    33  	"github.com/google/go-containerregistry/pkg/v1/random"
    34  	"github.com/google/go-containerregistry/pkg/v1/remote"
    35  
    36  	// Initialize all known client auth plugins
    37  	_ "k8s.io/client-go/plugin/pkg/client/auth"
    38  
    39  	"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
    40  	cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify"
    41  	"github.com/sigstore/cosign/v2/pkg/cosign"
    42  	ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
    43  	sigs "github.com/sigstore/cosign/v2/pkg/signature"
    44  )
    45  
    46  const (
    47  	rekorURL  = "http://127.0.0.1:3000"
    48  	fulcioURL = "http://127.0.0.1:5555"
    49  	certID    = "foo@bar.com"
    50  )
    51  
    52  var keyPass = []byte("hello")
    53  
    54  var passFunc = func(_ bool) ([]byte, error) {
    55  	return keyPass, nil
    56  }
    57  
    58  var verify = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment string, skipTlogVerify bool) error {
    59  	cmd := cliverify.VerifyCommand{
    60  		KeyRef:        keyRef,
    61  		RekorURL:      rekorURL,
    62  		CheckClaims:   checkClaims,
    63  		Annotations:   sigs.AnnotationsMap{Annotations: annotations},
    64  		Attachment:    attachment,
    65  		HashAlgorithm: crypto.SHA256,
    66  		MaxWorkers:    10,
    67  		IgnoreTlog:    skipTlogVerify,
    68  	}
    69  
    70  	args := []string{imageRef}
    71  
    72  	return cmd.Exec(context.Background(), args)
    73  }
    74  
    75  var verifyTSA = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment, tsaCertChain string, skipTlogVerify bool) error {
    76  	cmd := cliverify.VerifyCommand{
    77  		KeyRef:           keyRef,
    78  		RekorURL:         rekorURL,
    79  		CheckClaims:      checkClaims,
    80  		Annotations:      sigs.AnnotationsMap{Annotations: annotations},
    81  		Attachment:       attachment,
    82  		HashAlgorithm:    crypto.SHA256,
    83  		TSACertChainPath: tsaCertChain,
    84  		IgnoreTlog:       skipTlogVerify,
    85  		MaxWorkers:       10,
    86  	}
    87  
    88  	args := []string{imageRef}
    89  
    90  	return cmd.Exec(context.Background(), args)
    91  }
    92  
    93  var verifyKeylessTSA = func(imageRef string, tsaCertChain string, skipSCT bool, skipTlogVerify bool) error {
    94  	cmd := cliverify.VerifyCommand{
    95  		CertVerifyOptions: options.CertVerifyOptions{
    96  			CertOidcIssuerRegexp: ".*",
    97  			CertIdentityRegexp:   ".*",
    98  		},
    99  		RekorURL:         rekorURL,
   100  		HashAlgorithm:    crypto.SHA256,
   101  		TSACertChainPath: tsaCertChain,
   102  		IgnoreSCT:        skipSCT,
   103  		IgnoreTlog:       skipTlogVerify,
   104  		MaxWorkers:       10,
   105  	}
   106  
   107  	args := []string{imageRef}
   108  
   109  	return cmd.Exec(context.Background(), args)
   110  }
   111  
   112  // Used to verify local images stored on disk
   113  var verifyLocal = func(keyRef, path string, checkClaims bool, annotations map[string]interface{}, attachment string) error {
   114  	cmd := cliverify.VerifyCommand{
   115  		KeyRef:        keyRef,
   116  		RekorURL:      rekorURL,
   117  		CheckClaims:   checkClaims,
   118  		Annotations:   sigs.AnnotationsMap{Annotations: annotations},
   119  		Attachment:    attachment,
   120  		HashAlgorithm: crypto.SHA256,
   121  		LocalImage:    true,
   122  		MaxWorkers:    10,
   123  	}
   124  
   125  	args := []string{path}
   126  
   127  	return cmd.Exec(context.Background(), args)
   128  }
   129  
   130  var verifyOffline = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment string) error {
   131  	cmd := cliverify.VerifyCommand{
   132  		KeyRef:        keyRef,
   133  		RekorURL:      "notreal",
   134  		Offline:       true,
   135  		CheckClaims:   checkClaims,
   136  		Annotations:   sigs.AnnotationsMap{Annotations: annotations},
   137  		Attachment:    attachment,
   138  		HashAlgorithm: crypto.SHA256,
   139  		MaxWorkers:    10,
   140  	}
   141  
   142  	args := []string{imageRef}
   143  
   144  	return cmd.Exec(context.Background(), args)
   145  }
   146  
   147  var ro = &options.RootOptions{Timeout: options.DefaultTimeout}
   148  
   149  func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) {
   150  	wd, err := os.Getwd()
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  	if err := os.Chdir(td); err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	defer func() {
   158  		os.Chdir(wd)
   159  	}()
   160  	keys, err := cosign.GenerateKeyPair(passFunc)
   161  	if err != nil {
   162  		t.Fatal(err)
   163  	}
   164  
   165  	privKeyPath := filepath.Join(td, "cosign.key")
   166  	if err := os.WriteFile(privKeyPath, keys.PrivateBytes, 0600); err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	pubKeyPath := filepath.Join(td, "cosign.pub")
   171  	if err := os.WriteFile(pubKeyPath, keys.PublicBytes, 0600); err != nil {
   172  		t.Fatal(err)
   173  	}
   174  	return keys, privKeyPath, pubKeyPath
   175  }
   176  
   177  func importKeyPair(t *testing.T, td string) (*cosign.KeysBytes, string, string) {
   178  
   179  	const validrsa1 = `-----BEGIN RSA PRIVATE KEY-----
   180  MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+
   181  25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb
   182  4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o
   183  SUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcHRuw5RsB+C0RbjRtbJ/5VxmE/vd3M
   184  lafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeOddS0yb19ShSuW3PPRadruBM1mq15
   185  js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHxawIDAQABAoIBAH+sgLwmHa9zJfEo
   186  klAe5NFe/QpydN/ziXbkAnzqzH9URC3wD+TpkWj4JoK3Sw635NWtasjf+3XDV9S/
   187  9L7j/g5N91r6sziWcJykEsWaXXKQmm4lI6BdFjwsHyLKz1W7bZOiJXDWLu1rbrqu
   188  DqEQuLoc9WXCKrYrFy0maoXNtfla/1p05kKN0bMigcnnyAQ+xBTwoyco4tkIz5se
   189  IYxorz7qzXrkHQI+knz5BawmNe3ekoSaXUPoLoOR7TRTGsLteL5yukvWAi8S/0rE
   190  gftC+PZCQpoQhSUYq7wXe7RowJ1f+kXb7HsSedOTfTSW1D/pUb/uW+CcRKig42ZI
   191  I9H9TAECgYEA5XGBML6fJyWVqx64sHbUAjQsmQ0RwU6Zo7sqHIEPf6tYVYp7KtzK
   192  KOfi8seOOL5FSy4pjCo11Dzyrh9bn45RNmtjSYTgOnVPSoCfuRNfOcpG+/wCHjYf
   193  EjDvdrCpbg59kVUeaMeBDiyWAlM48HJAn8O7ez2U/iKQCyJmOIwFhSkCgYEA3rSz
   194  Fi1NzqYWxWos4NBmg8iKcQ9SMkmPdgRLAs/WNnZJ8fdgJZwihevkXGytRGJEmav2
   195  GMKRx1g6ey8fjXTQH9WM8X/kJC5fv8wLHnUCH/K3Mcp9CYwn7PFvSnBr4kQoc/el
   196  bURhcF1+/opEC8vNX/Wk3zAG7Xs1PREXlH2SIHMCgYBV/3kgwBH/JkM25EjtO1yz
   197  hsLAivmAruk/SUO7c1RP0fVF+qW3pxHOyztxLALOmeJ3D1JbSubqKf377Zz17O3b
   198  q9yHDdrNjnKtxhAX2n7ytjJs+EQC9t4mf1kB761RpvTBqFnBhCWHHocLUA4jcW9v
   199  cnmu86IIrwO2aKpPv4vCIQKBgHU9gY3qOazRSOmSlJ+hdmZn+2G7pBTvHsQNTIPl
   200  cCrpqNHl3crO4GnKHkT9vVVjuiOAIKU2QNJFwzu4Og8Y8LvhizpTjoHxm9x3iV72
   201  UDELcJ+YrqyJCTe2flUcy96o7Pbn50GXnwgtYD6WAW6IUszyn2ITgYIhu4wzZEt6
   202  s6O7AoGAPTKbRA87L34LMlXyUBJma+etMARIP1zu8bXJ7hSJeMcog8zaLczN7ruT
   203  pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ
   204  qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA=
   205  -----END RSA PRIVATE KEY-----`
   206  
   207  	wd, err := os.Getwd()
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	if err := os.Chdir(td); err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	defer func() {
   215  		os.Chdir(wd)
   216  	}()
   217  
   218  	err = os.WriteFile("validrsa1.key", []byte(validrsa1), 0600)
   219  	if err != nil {
   220  		t.Fatal(err)
   221  	}
   222  
   223  	keys, err := cosign.ImportKeyPair("validrsa1.key", passFunc)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  
   228  	privKeyPath := filepath.Join(td, "import-cosign.key")
   229  	if err := os.WriteFile(privKeyPath, keys.PrivateBytes, 0600); err != nil {
   230  		t.Fatal(err)
   231  	}
   232  
   233  	pubKeyPath := filepath.Join(td, "import-cosign.pub")
   234  	if err := os.WriteFile(pubKeyPath, keys.PublicBytes, 0600); err != nil {
   235  		t.Fatal(err)
   236  	}
   237  	return keys, privKeyPath, pubKeyPath
   238  
   239  }
   240  
   241  func mockStdin(contents, td string, t *testing.T) func() {
   242  	origin := os.Stdin
   243  
   244  	p := mkfile(contents, td, t)
   245  	f, err := os.Open(p)
   246  	if err != nil {
   247  		t.Fatal(err)
   248  	}
   249  	os.Stdin = f
   250  
   251  	return func() { os.Stdin = origin }
   252  }
   253  
   254  func mkfile(contents, td string, t *testing.T) string {
   255  	f, err := os.CreateTemp(td, "")
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	defer f.Close()
   260  	if _, err := f.Write([]byte(contents)); err != nil {
   261  		t.Fatal(err)
   262  	}
   263  	return f.Name()
   264  }
   265  
   266  func mkfileWithExt(contents, td, ext string, t *testing.T) string {
   267  	f := mkfile(contents, td, t)
   268  	newName := f + ext
   269  	err := os.Rename(f, newName)
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  	return newName
   274  }
   275  
   276  func mkimage(t *testing.T, n string) (name.Reference, *remote.Descriptor, func()) {
   277  	ref, err := name.ParseReference(n, name.WeakValidation)
   278  	if err != nil {
   279  		t.Fatal(err)
   280  	}
   281  	img, err := random.Image(512, 5)
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	}
   285  
   286  	regClientOpts := registryClientOpts(context.Background())
   287  
   288  	if err := remote.Write(ref, img, regClientOpts...); err != nil {
   289  		t.Fatal(err)
   290  	}
   291  
   292  	remoteImage, err := remote.Get(ref, regClientOpts...)
   293  	if err != nil {
   294  		t.Fatal(err)
   295  	}
   296  
   297  	cleanup := func() {
   298  		_ = remote.Delete(ref, regClientOpts...)
   299  		ref, _ := ociremote.SignatureTag(ref.Context().Digest(remoteImage.Descriptor.Digest.String()), ociremote.WithRemoteOptions(regClientOpts...))
   300  		_ = remote.Delete(ref, regClientOpts...)
   301  	}
   302  	return ref, remoteImage, cleanup
   303  }
   304  
   305  func mkimageindex(t *testing.T, n string) (name.Reference, *remote.Descriptor, func()) {
   306  	ref, err := name.ParseReference(n, name.WeakValidation)
   307  	if err != nil {
   308  		t.Fatal(err)
   309  	}
   310  	ii, err := random.Index(512, 5, 4)
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  
   315  	regClientOpts := registryClientOpts(context.Background())
   316  
   317  	if err := remote.WriteIndex(ref, ii, regClientOpts...); err != nil {
   318  		t.Fatal(err)
   319  	}
   320  
   321  	remoteIndex, err := remote.Get(ref, regClientOpts...)
   322  	if err != nil {
   323  		t.Fatal(err)
   324  	}
   325  
   326  	cleanup := func() {
   327  		_ = remote.Delete(ref, regClientOpts...)
   328  		ref, _ := ociremote.SignatureTag(ref.Context().Digest(remoteIndex.Descriptor.Digest.String()), ociremote.WithRemoteOptions(regClientOpts...))
   329  		_ = remote.Delete(ref, regClientOpts...)
   330  	}
   331  	return ref, remoteIndex, cleanup
   332  }
   333  
   334  func must(err error, t *testing.T) {
   335  	t.Helper()
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  }
   340  
   341  func mustErr(err error, t *testing.T) {
   342  	t.Helper()
   343  	if err == nil {
   344  		t.Fatal("expected error")
   345  	}
   346  }
   347  
   348  func equals(v1, v2 interface{}, t *testing.T) {
   349  	if diff := cmp.Diff(v1, v2); diff != "" {
   350  		t.Error(diff)
   351  	}
   352  }
   353  
   354  func reg(t *testing.T) (string, func()) {
   355  	repo := os.Getenv("COSIGN_TEST_REPO")
   356  	if repo != "" {
   357  		return repo, func() {}
   358  	}
   359  
   360  	t.Log("COSIGN_TEST_REPO unset, using fake registry")
   361  	r := httptest.NewServer(registry.New())
   362  	u, err := url.Parse(r.URL)
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  	return u.Host, r.Close
   367  }
   368  
   369  func registryClientOpts(ctx context.Context) []remote.Option {
   370  	return []remote.Option{
   371  		remote.WithAuthFromKeychain(authn.DefaultKeychain),
   372  		remote.WithContext(ctx),
   373  	}
   374  }
   375  

View as plain text