diff --git a/README.md b/README.md index 8415882a..87c0ef5e 100644 --- a/README.md +++ b/README.md @@ -101,67 +101,13 @@ INFO[0000] The SHA sums are equal: 540cc4dc213548ebbdffb2ab0ef58729e089d1887edbc - Add in-toto metadata when signing a thin bundle: ``` -$ ./scripts/signy-sign.sh testdata/cnab/bundle.json localhost:5000/thin-intoto:v2 --in-toto --layout testdata/intoto/root.layout --links testdata/intoto --layout-key testdata/intoto/alice.pub -INFO[0000] Adding In-Toto layout and links metadata to TUF -INFO[0000] Pushed trust data for localhost:5000/thin-intoto:v2: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5 -INFO[0000] Starting to copy image cnab/helloworld:0.1.1 -INFO[0001] Completed image cnab/helloworld:0.1.1 copy -INFO[0001] Generated relocation map: relocation.ImageRelocationMap{"cnab/helloworld:0.1.1":"localhost:5000/thin-intoto@sha256:a59a4e74d9cc89e4e75dfb2cc7ea5c108e4236ba6231b53081a9e2506d1197b6"} -INFO[0001] Pushed successfully, with digest "sha256:b4936e42304c184bafc9b06dde9ea1f979129e09a021a8f40abc07f736de9268" +$ ./scripts/signy-sign.sh testdata/intoto/minimal/bundle.json localhost:5000/minimal:latest --in-toto --layout testdata/intoto/minimal/root.layout --links testdata/intoto/minimal/d374df2f6946233546bb4ca97dcee3a01fe07aaef11be1fb09abd37ceb4ecfb7/ --layout-key testdata/intoto/minimal/root.layout.pub ``` - verifying the signature of a thin bundle and running the in-toto verifications in a container: ``` -$ ./scripts/signy-verify.sh localhost:5000/thin-intoto:v2 --in-toto -INFO[0000] Pulled trust data for localhost:5000/thin-intoto:v2, with role targets - SHA256: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5 -INFO[0000] Pulling bundle from registry: localhost:5000/thin-intoto:v2 -INFO[0000] Computed SHA: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5 -INFO[0000] The SHA sums are equal: c7e92bd51f059d60b15ad456edf194648997d739f60799b37e08edafd88a81b5 -INFO[0000] Writing In-Toto metadata files into /tmp/intoto-verification169227773 -INFO[0000] copying file /in-toto/layout.template in container for verification... -INFO[0000] copying file /in-toto/key.pub in container for verification... -INFO[0000] copying file in-toto/package.2f89b927.link in container for verification... -INFO[0000] copying file in-toto/write-code.776a00e2.link in container for verification... -INFO[0000] copying file in-toto/foo.tar.gz in container for verification... -INFO[0000] Loading layout... -INFO[0000] Loading layout key(s)... -INFO[0000] Verifying layout signatures... -INFO[0001] Verifying layout expiration... -INFO[0001] Reading link metadata files... -INFO[0001] Verifying link metadata signatures... -INFO[0001] Verifying sublayouts... -INFO[0001] Verifying alignment of reported commands... -INFO[0001] Verifying command alignment for 'write-code.776a00e2.link'... -INFO[0001] Verifying command alignment for 'package.2f89b927.link'... -INFO[0001] Verifying threshold constraints... -INFO[0001] Skipping threshold verification for step 'write-code' with threshold '1'... -INFO[0001] Skipping threshold verification for step 'package' with threshold '1'... -INFO[0001] Verifying Step rules... -INFO[0001] Verifying material rules for 'write-code'... -INFO[0001] Verifying product rules for 'write-code'... -INFO[0001] Verifying 'ALLOW foo.py'... -INFO[0001] Verifying material rules for 'package'... -INFO[0001] Verifying 'MATCH foo.py WITH PRODUCTS FROM write-code'... -INFO[0001] Verifying 'DISALLOW *'... -INFO[0001] Verifying product rules for 'package'... -INFO[0001] Verifying 'ALLOW foo.tar.gz'... -INFO[0001] Verifying 'ALLOW foo.py'... -INFO[0001] Executing Inspection commands... -INFO[0001] Executing command for inspection 'untar'... -INFO[0001] Running 'untar'... -INFO[0001] Recording materials '.'... -INFO[0001] Running command 'tar xfz foo.tar.gz'... -INFO[0001] Recording products '.'... -INFO[0001] Creating link metadata... -INFO[0001] Verifying Inspection rules... -INFO[0001] Verifying material rules for 'untar'... -INFO[0001] Verifying 'MATCH foo.tar.gz WITH PRODUCTS FROM package'... -INFO[0001] Verifying 'DISALLOW foo.tar.gz'... -INFO[0001] Verifying product rules for 'untar'... -INFO[0001] Verifying 'MATCH foo.py WITH PRODUCTS FROM write-code'... -INFO[0001] Verifying 'DISALLOW foo.py'... -INFO[0001] The software product passed all verification. +$ ./scripts/signy-verify.sh localhost:5000/minimal:latest --in-toto ``` - similarly for a thick bundle: diff --git a/cmd/sign.go b/cmd/sign.go index b2ad06cd..4d9c5469 100644 --- a/cmd/sign.go +++ b/cmd/sign.go @@ -1,14 +1,13 @@ package main import ( - "encoding/hex" "fmt" - canonicaljson "github.com/docker/go/canonical/json" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/cnabio/signy/pkg/cnab" + "github.com/cnabio/signy/pkg/docker" "github.com/cnabio/signy/pkg/intoto" "github.com/cnabio/signy/pkg/tuf" ) @@ -89,28 +88,47 @@ INFO[0001] Pushed successfully, with digest "sha256:b4936e42304c184bafc9b06dde9e } func (s *signCmd) run() error { - var cm *canonicaljson.RawMessage + var publicKeys intoto.PublicKeys + var rootLayout intoto.RootLayout + var links intoto.Links + var bundleCustom intoto.Custom + + gun, err := docker.GetGUN(s.ref) + if err != nil { + return fmt.Errorf("cannot initialize GUN from %s: %v", s.ref, err) + } + if s.intoto { if s.layout == "" || s.layoutKey == "" || s.linkDir == "" { return fmt.Errorf("required in-toto metadata not found") } log.Infof("Adding In-Toto layout and links metadata to TUF") + err := intoto.ValidateFromPath(s.layout) if err != nil { return fmt.Errorf("validation for in-toto metadata failed: %v", err) } - custom, err := intoto.GetMetadataRawMessage(s.layout, s.linkDir, s.layoutKey) + + publicKeys, err = intoto.GetPublicKeys(gun, s.layoutKey) + if err != nil { + return fmt.Errorf("cannot read public keys: %v", err) + } + + rootLayout, err = intoto.GetRootLayout(gun, s.layout, publicKeys) if err != nil { - return fmt.Errorf("cannot get metadata message: %v", err) + return fmt.Errorf("cannot read root layout: %v", err) } - // TODO: Radu M - // Refactor GetMatedataRawMessage to return a pointer to a raw message - cm = &custom + + links, err = intoto.GetLinks(gun, s.linkDir) + if err != nil { + return fmt.Errorf("cannot read links: %v", err) + } + + bundleCustom = intoto.GetBundleCustom(rootLayout, links) } // NOTE: We first push to the Registry, and then Notary. This is so that if we modify the bundle locally, // we will not invalidate its signature by first pushing to Notary, and then the Registry. - // We push only thin bundles to the Registry. if !s.thick { if err := cnab.Push(s.file, s.ref); err != nil { @@ -118,11 +136,11 @@ func (s *signCmd) run() error { } } - target, err := tuf.SignAndPublish(trustDir, trustServer, s.ref, s.file, tlscacert, s.rootKey, timeout, cm) + bundleDigest, err := tuf.SignAndPublish(trustDir, trustServer, s.ref, s.file, tlscacert, s.rootKey, timeout, rootLayout, publicKeys, links, bundleCustom) if err != nil { return fmt.Errorf("cannot sign and publish trust data: %v", err) } - log.Infof("Pushed trust data for %v: %v\n", s.ref, hex.EncodeToString(target.Hashes["sha256"])) + log.Infof("Pushed trust data for %v: %v\n", s.ref, bundleDigest) return nil } diff --git a/cmd/verify.go b/cmd/verify.go index ab87ea9d..1928f913 100644 --- a/cmd/verify.go +++ b/cmd/verify.go @@ -110,6 +110,12 @@ func (v *verifyCmd) run() error { } if v.intoto { + // TODO: Put back TUF verification of in-toto metadata. + err = tuf.VerifyInTotoMetadata(v.ref, trustServer, tlscacert, trustDir, timeout) + if err != nil { + return err + } + if v.verifyOnOS { log.Warn("Running in-toto inspections on the OS instead of in container...") return intoto.VerifyOnOS(target, bundle) diff --git a/pkg/docker/docker.go b/pkg/docker/docker.go index 004f52ce..675f3d8f 100644 --- a/pkg/docker/docker.go +++ b/pkg/docker/docker.go @@ -32,6 +32,19 @@ const ( workingDir = "/in-toto" // Where we expect to copy in-toto artifacts to ) +// GetGUN returns the Globally Unique Name for a reference image name +func GetGUN(name string) (string, error) { + r, err := reference.ParseNormalizedNamed(name) + if err != nil { + return "", err + } + repo, err := registry.ParseRepositoryInfo(r) + if err != nil { + return "", err + } + return repo.Name.Name(), nil +} + // Run will start a container, copy all In-Toto metadata in /in-toto // then run in-toto-verification func Run(verificationImage, verificationDir, logLevel string) error { diff --git a/pkg/docker/docker_test.go b/pkg/docker/docker_test.go index 2f028dd7..2936d30e 100644 --- a/pkg/docker/docker_test.go +++ b/pkg/docker/docker_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" ) -var testDir = "../../testdata/intoto" +var testDir = "../../testdata/intoto/minimal" func TestRun(t *testing.T) { // NOTE: Tag will be empty since we cannot inject build-time variables during testing. @@ -15,3 +15,34 @@ func TestRun(t *testing.T) { err := Run(VerificationImage+"latest", testDir, log.InfoLevel.String()) assert.NoError(t, err) } + +func TestParseReference(t *testing.T) { + tests := []struct { + input string + gun string + }{ + { + input: "localhost:5000/local-test-simple:v1", + gun: "localhost:5000/local-test-simple", + }, + { + input: "localhost:5000/multi-path/some/bundle:v1", + gun: "localhost:5000/multi-path/some/bundle", + }, + { + input: "dockerhubusername/bundle:v3", + gun: "docker.io/dockerhubusername/bundle", + }, + { + input: "mycnabregistry.azurecr.io/org/sub-org/bundle:latest", + gun: "mycnabregistry.azurecr.io/org/sub-org/bundle", + }, + } + + is := assert.New(t) + for _, test := range tests { + gun, err := GetGUN(test.input) + is.NoError(err) + is.Equal(test.gun, gun) + } +} diff --git a/pkg/intoto/metadata.go b/pkg/intoto/metadata.go index 70f67227..9de82477 100644 --- a/pkg/intoto/metadata.go +++ b/pkg/intoto/metadata.go @@ -9,89 +9,158 @@ import ( canonicaljson "github.com/docker/go/canonical/json" ) -// Metadata represents the In-Toto metadata stored in TUF. -// All fields are represented as []byte in order to be stored in the Custom field for TUF metadata. +// Metadata points to root layout, its public keys, and/or links type Metadata struct { - // TODO: remove this once the TUF targets key is used to sign the root layout - Key []byte `json:"key"` - Layout []byte `json:"layout"` - Links map[string][]byte `json:"links"` + Data []byte `json:"data"` + PublicKeys []string `json:"pubkeys"` // filenames + Links []string `json:"links"` // filenames } -// WriteMetadataFiles writes the content of a metadata object into files in a directory -func WriteMetadataFiles(m *Metadata, dir string) error { - abs, err := filepath.Abs(dir) - if err != nil { - return err - } +// Custom is a generic structure that contains in-toto Metadata +type Custom struct { + InToto Metadata `json:"intoto"` +} + +// PublicKeys is a map from the GUN-qualified filename +// (e.g., "example.com/example-org/example-bundle/in-toto-pubkeys/keyid.pub") +// to a Custom struct +type PublicKeys map[string]Custom + +// RootLayout maps a GUN-qualified filename +// (e.g., "example.com/example-org/example-bundle/in-toto-metadata/root.layout") +// to a Custom struct +type RootLayout struct { + Filename string + Custom Custom +} + +// Links is a map from the GUN-qualified filename +// (e.g., "example.com/example-org/example-bundle/in-toto-metadata/DIGEST/step.link") +// to a Custom struct +type Links map[string]Custom - //FIXME: no need to actually write filename. - err = ioutil.WriteFile(filepath.Join(abs, "root.layout"), m.Layout, ReadOnlyMask) +// GetRawMessage transforms a Custom struct into a raw Canonical JSON message +func (custom *Custom) GetRawMessage() (canonicaljson.RawMessage, error) { + marshalled, err := canonicaljson.MarshalCanonical(custom) if err != nil { - return err + return nil, fmt.Errorf("cannot encode custom metadata into canonical json: %v", err) } + return canonicaljson.RawMessage(marshalled), nil +} - //FIXME: no need to actually write filenames. - err = ioutil.WriteFile(filepath.Join(abs, "root.layout.pub"), m.Key, ReadOnlyMask) +// ReadRawMessage reads a raw Canonical JSON message into this Custom +func (custom *Custom) ReadRawMessage(rm *canonicaljson.RawMessage) error { + // TODO: check that the types/deferencing are correct + err := canonicaljson.Unmarshal(*rm, custom) if err != nil { - return err + return fmt.Errorf("cannot decode canonical json into custom metadata: %v", err) } + return nil +} + +// GetPublicKeys reads public keys off disk into a PublicKeys map +func GetPublicKeys(gun string, filenames ...string) (PublicKeys, error) { + publicKeys := make(PublicKeys) - for n, c := range m.Links { - err = ioutil.WriteFile(filepath.Join(abs, n), c, ReadOnlyMask) + for _, filename := range filenames { + if !strings.HasSuffix(filename, ".pub") { + return nil, fmt.Errorf("%s does not have a .pub suffix", filename) + } + + data, err := readFile(filename) if err != nil { - return err + return nil, err } + + metadata := Metadata{Data: data} + custom := Custom{InToto: metadata} + filename = gun + "/in-toto-pubkeys/" + filename + publicKeys[filename] = custom } - return nil + return publicKeys, nil } -// GetMetadataRawMessage takes In-Toto metadata and returns a canonical RawMessage -// that can be stored in the TUF targets custom field. -// -// TODO: layout signing key should not be passed by the library. -// Layouts should be signed with the targets key used to sign the TUF collection. -func GetMetadataRawMessage(layout string, linkDir string, layoutKey string) (canonicaljson.RawMessage, error) { - k, err := ioutil.ReadFile(layoutKey) - if err != nil { - return nil, fmt.Errorf("cannot get canonical JSON from file %v: %v", layoutKey, err) +// GetRootLayout reads root layout off disk into a RootLayout struct +func GetRootLayout(gun string, filename string, publicKeys PublicKeys) (RootLayout, error) { + var rootLayout RootLayout + + if !strings.HasSuffix(filename, ".layout") { + return rootLayout, fmt.Errorf("%s does not have a .layout suffix", filename) } - l, err := ioutil.ReadFile(layout) + data, err := readFile(filename) if err != nil { - return nil, fmt.Errorf("cannot get canonical JSON from file %v: %v", layout, err) + return rootLayout, err } - links := make(map[string][]byte) - files, err := ioutil.ReadDir(linkDir) + filenames := make([]string, len(publicKeys)) + for filename := range publicKeys { + filenames = append(filenames, filename) + } + + metadata := Metadata{Data: data, PublicKeys: filenames} + custom := Custom{InToto: metadata} + filename = gun + "/in-toto-metadata/" + filename + rootLayout.Filename = filename + rootLayout.Custom = custom + return rootLayout, nil +} + +// GetLinks reads link metadata off disk into a Links struct +func GetLinks(gun string, dir string) (Links, error) { + fileinfos, err := ioutil.ReadDir(dir) if err != nil { - return nil, fmt.Errorf("cannot read links directory %v: %v", linkDir, err) + return nil, fmt.Errorf("cannot read links directory %v: %v", dir, err) } - for _, f := range files { - // TODO - Radu M - // - // robust check if file is actually a link - if !strings.Contains(f.Name(), ".link") { - continue + + // NOTE: We assume that the base directory used to hold the links are unique + // (e.g., identified by the digest of the first link metadata file corresponding to the first step). + // This is so that different versions of links corresponding to the same root layout can be safely isolated from each other. + // TODO: If they are not unique, should we raise an error later when adding them to the TUF targets metadata? + digest := filepath.Base(dir) + links := make(Links) + for _, fileinfo := range fileinfos { + filename := fileinfo.Name() + if !strings.Contains(filename, ".link") { + return nil, fmt.Errorf("%s does not have a .link suffix", filename) } - b, err := ioutil.ReadFile(filepath.Join(linkDir, f.Name())) + + data, err := readFile(filepath.Join(dir, filename)) if err != nil { - return nil, fmt.Errorf("cannot get canonical JSON from file %v: %v", f.Name(), err) + return nil, err } - links[f.Name()] = b + + metadata := Metadata{Data: data} + custom := Custom{InToto: metadata} + filename = gun + "/in-toto-metadata/" + digest + "/" + filename + links[filename] = custom } - m := &Metadata{ - Key: k, - Layout: l, - Links: links, + return links, nil +} + +// GetBundleCustom returns a Custom struct pointing to a list of root layout and links +func GetBundleCustom(rootLayout RootLayout, links Links) Custom { + filenames := make([]string, len(links)+1) + filenames = append(filenames, rootLayout.Filename) + for filename := range links { + filenames = append(filenames, filename) } + metadata := Metadata{Links: filenames} + return Custom{InToto: metadata} +} + +// WriteMetadataFiles writes the content of a metadata object into files in a directory +// TODO +func WriteMetadataFiles(m *Metadata, dir string) error { + return fmt.Errorf("not implemented") +} - raw, err := canonicaljson.MarshalCanonical(m) +func readFile(filename string) ([]byte, error) { + bytes, err := ioutil.ReadFile(filename) if err != nil { - return nil, fmt.Errorf("cannot encode in-toto metadata into canonical json %v: %v", m, err) + return nil, err } - - return canonicaljson.RawMessage(raw), nil + return bytes, nil } diff --git a/pkg/intoto/os_test.go b/pkg/intoto/os_test.go index 8bdd6241..ef7ff5d6 100644 --- a/pkg/intoto/os_test.go +++ b/pkg/intoto/os_test.go @@ -2,6 +2,7 @@ package intoto import ( "os" + "path" "path/filepath" "testing" @@ -11,7 +12,7 @@ import ( var testDir = "../../testdata/intoto" func TestVerify(t *testing.T) { - err := verifyOnOS(testDir) + err := verifyOnOS(path.Join(testDir, "minimal")) assert.NoError(t, err) // the verification step generates a file called untar.link @@ -19,7 +20,7 @@ func TestVerify(t *testing.T) { } func TestValidate(t *testing.T) { - layoutPath := filepath.Join(testDir, "root.layout") + layoutPath := filepath.Join(testDir, "minimal", "root.layout") l, err := getLayout(layoutPath) assert.NoError(t, err) @@ -29,7 +30,7 @@ func TestValidate(t *testing.T) { } func TestValidateMalformed(t *testing.T) { - layoutPath := filepath.Join(testDir, "malformed.template") + layoutPath := filepath.Join(testDir, "malformed.root.layout") // we can load the file and unmarshal a layout l, err := getLayout(layoutPath) diff --git a/pkg/intoto/verify.go b/pkg/intoto/verify.go index 1500745c..463a5c97 100644 --- a/pkg/intoto/verify.go +++ b/pkg/intoto/verify.go @@ -13,10 +13,13 @@ import ( ) const ( + // BundleFilename is the name written to disk during verification BundleFilename = "bundle.json" - ReadOnlyMask = 0400 + // ReadOnlyMask is applied to files written to disk for verification + ReadOnlyMask = 0400 ) +// VerifyOnOS verifies a bundle directly on the OS func VerifyOnOS(target *client.TargetWithRole, bundle []byte) error { verificationDir, err := getVerificationDir(target, bundle) if err != nil { @@ -29,6 +32,7 @@ func VerifyOnOS(target *client.TargetWithRole, bundle []byte) error { return verifyOnOS(verificationDir) } +// VerifyInContainer verifies a bundle within a container func VerifyInContainer(target *client.TargetWithRole, bundle []byte, verificationImage string, logLevel string) error { verificationDir, err := getVerificationDir(target, bundle) if err != nil { @@ -42,6 +46,7 @@ func VerifyInContainer(target *client.TargetWithRole, bundle []byte, verificatio } func getVerificationDir(target *client.TargetWithRole, bundle []byte) (string, error) { + // FIXME m := &Metadata{} err := json.Unmarshal(*target.Custom, m) if err != nil { @@ -53,6 +58,7 @@ func getVerificationDir(target *client.TargetWithRole, bundle []byte) (string, e return "", err } + // FIXME log.Infof("Writing in-toto metadata files into %v", verificationDir) err = WriteMetadataFiles(m, verificationDir) if err != nil { diff --git a/pkg/tuf/common.go b/pkg/tuf/common.go index 1f4b17a2..ebfa5fd7 100644 --- a/pkg/tuf/common.go +++ b/pkg/tuf/common.go @@ -1,9 +1,3 @@ -// Most of the helper functions are adapted from github.com/theupdateframework/notary -// -// Figure out the proper way of making sure we are respecting the licensing from Notary -// While we are also vendoring Notary directly (see LICENSE in vendor/github.com/theupdateframework/notary/LICENSE), -// copying unexported functions could fall under different licensing, so we need to make sure. - package tuf import ( @@ -11,14 +5,15 @@ import ( "path/filepath" "runtime" - "github.com/docker/distribution/reference" - "github.com/docker/docker/registry" + "github.com/theupdateframework/notary/tuf/data" ) const ( - dockerConfigDir = ".docker" + dockerConfigDir = ".docker" + releasesRoleName = data.RoleName("targets/releases") ) +// DefaultTrustDir returns where the Signy trust data lives func DefaultTrustDir() string { homeEnvPath := os.Getenv("HOME") if homeEnvPath == "" && runtime.GOOS == "windows" { @@ -28,6 +23,7 @@ func DefaultTrustDir() string { return filepath.Join(homeEnvPath, ".signy") } +// DefaultDockerCfgDir returns where the Docker config directory lives func DefaultDockerCfgDir() string { homeEnvPath := os.Getenv("HOME") if homeEnvPath == "" && runtime.GOOS == "windows" { @@ -37,31 +33,7 @@ func DefaultDockerCfgDir() string { return filepath.Join(homeEnvPath, dockerConfigDir) } -// ensures the trust directory exists +// EnsureTrustDir ensures the trust directory exists func EnsureTrustDir(trustDir string) error { return os.MkdirAll(trustDir, 0700) } - -func getRepoAndTag(name string) (*registry.RepositoryInfo, string, error) { - r, err := reference.ParseNormalizedNamed(name) - if err != nil { - return nil, "", err - } - repo, err := registry.ParseRepositoryInfo(r) - if err != nil { - return nil, "", err - } - - return repo, getTag(r), nil -} - -func getTag(ref reference.Named) string { - switch x := ref.(type) { - case reference.Canonical, reference.Digested: - return "" - case reference.NamedTagged: - return x.Tag() - default: - return "" - } -} diff --git a/pkg/tuf/common_test.go b/pkg/tuf/common_test.go deleted file mode 100644 index 0007702f..00000000 --- a/pkg/tuf/common_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package tuf - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestParseReference(t *testing.T) { - tests := []struct { - input string - repository string - registry string - tag string - }{ - { - input: "localhost:5000/local-test-simple:v1", - repository: "localhost:5000/local-test-simple", - registry: "localhost:5000", - tag: "v1", - }, - { - input: "localhost:5000/multi-path/some/bundle:v1", - repository: "localhost:5000/multi-path/some/bundle", - registry: "localhost:5000", - tag: "v1", - }, - { - input: "dockerhubusername/bundle:v3", - repository: "docker.io/dockerhubusername/bundle", - registry: "docker.io", - tag: "v3", - }, - { - input: "mycnabregistry.azurecr.io/org/sub-org/bundle:latest", - repository: "mycnabregistry.azurecr.io/org/sub-org/bundle", - registry: "mycnabregistry.azurecr.io", - tag: "latest", - }, - } - - is := assert.New(t) - for _, test := range tests { - repo, tag, err := getRepoAndTag(test.input) - is.NoError(err) - is.Equal(test.repository, repo.Name.Name()) - is.Equal(test.tag, tag) - is.Equal(test.registry, repo.Index.Name) - } -} diff --git a/pkg/tuf/delegations.go b/pkg/tuf/delegations.go new file mode 100644 index 00000000..1fd5984a --- /dev/null +++ b/pkg/tuf/delegations.go @@ -0,0 +1,33 @@ +package tuf + +import ( + "fmt" + + "github.com/theupdateframework/notary/client" + "github.com/theupdateframework/notary/tuf/data" +) + +func getReleasesPathPattern(gun string) []string { + paths := make([]string, 2) + tags := gun + ":" + links := gun + "/in-toto-links/" + paths = append(paths, tags, links) + return paths +} + +// Delegate all paths ("*") to targets/releases. +// https://github.com/theupdateframework/notary/blob/f255ae779066dc28ae4aee196061e58bb38a2b49/cmd/notary/delegations.go +func delegateToReleases(repo client.Repository, publicKey data.PublicKey) error { + // the public keys used to verify the delegatee + publicKeys := []data.PublicKey{publicKey} + // the target paths entrusted to the delegatee + paths := getReleasesPathPattern(repo.GetGUN().String()) + + // Add the delegation to the repository + err := repo.AddDelegation(releasesRoleName, publicKeys, paths) + if err != nil { + return fmt.Errorf("failed to create delegation: %v", err) + } + + return nil +} diff --git a/pkg/tuf/keys.go b/pkg/tuf/keys.go index 2edcc43d..c19b0397 100644 --- a/pkg/tuf/keys.go +++ b/pkg/tuf/keys.go @@ -24,9 +24,9 @@ import ( func getPassphraseRetriever() notary.PassRetriever { baseRetriever := passphrase.PromptRetriever() env := map[string]string{ - "root": os.Getenv("SIGNY_ROOT_PASSPHRASE"), - "targets": os.Getenv("SIGNY_TARGETS_PASSPHRASE"), - "releases": os.Getenv("SIGNY_RELEASES_PASSPHRASE"), + "root": os.Getenv("SIGNY_ROOT_PASSPHRASE"), + "targets": os.Getenv("SIGNY_TARGETS_PASSPHRASE"), + "targets/releases": os.Getenv("SIGNY_RELEASES_PASSPHRASE"), } return func(keyName string, alias string, createNew bool, numAttempts int) (string, bool, error) { @@ -39,11 +39,12 @@ func getPassphraseRetriever() notary.PassRetriever { // Attempt to read a role key from a file, and return it as a data.PrivateKey // If key is for the Root role, it must be encrypted -func readKey(role data.RoleName, keyFilename string, retriever notary.PassRetriever) (data.PrivateKey, error) { +func readPrivateKey(role data.RoleName, keyFilename string, retriever notary.PassRetriever) (data.PrivateKey, error) { pemBytes, err := ioutil.ReadFile(keyFilename) if err != nil { return nil, fmt.Errorf("Error reading input root key file: %v", err) } + isEncrypted := true if err = cryptoservice.CheckRootKeyIsEncrypted(pemBytes); err != nil { if role == data.CanonicalRootRole { @@ -51,6 +52,7 @@ func readKey(role data.RoleName, keyFilename string, retriever notary.PassRetrie } isEncrypted = false } + var privKey data.PrivateKey if isEncrypted { privKey, _, err = trustmanager.GetPasswdDecryptBytes(retriever, pemBytes, "", data.CanonicalRootRole.String()) @@ -71,7 +73,7 @@ func importRootKey(rootKey string, nRepo client.Repository, retriever notary.Pas var rootKeyList []string if rootKey != "" { - privKey, err := readKey(data.CanonicalRootRole, rootKey, retriever) + privKey, err := readPrivateKey(data.CanonicalRootRole, rootKey, retriever) if err != nil { return nil, err } @@ -89,57 +91,71 @@ func importRootKey(rootKey string, nRepo client.Repository, retriever notary.Pas // Chooses the first root key available, which is initialization specific // but should return the HW one first. rootKeyID := rootKeyList[0] - log.Debugf("Signy found root key, using: %s\n", rootKeyID) - + log.Debugf("found root key: %s\n", rootKeyID) return []string{rootKeyID}, nil } return []string{}, nil } +// Try to reuse a single targets/releases key across repositories. +func reuseReleasesKey(r client.Repository) (data.PublicKey, error) { + // Get all known targets keys. + cryptoService := r.GetCryptoService() + keyList := cryptoService.ListKeys(releasesRoleName) + + // Try to extract a single targets/releases key we can reuse. + switch len(keyList) { + case 0: + log.Debugf("No %s key available, need to make one", releasesRoleName) + return cryptoService.Create(releasesRoleName, r.GetGUN(), data.ECDSAKey) + case 1: + log.Debugf("Nothing to do, only one %s key available", releasesRoleName) + return cryptoService.GetKey(keyList[0]), nil + default: + return nil, fmt.Errorf("there is more than one %s keys", releasesRoleName) + } +} + // Try to reuse a single targets key across repositories. // FIXME: Unfortunately, short of forking Notary or sending a PR upstream, there isn't an easy way to prevent it // from automagically creating a new, local targets key per TUF metadata repository. We fix this here by undoing // more than one new, local targets key, and reusing any existing local targets key, just like the way Notary // reuses the root key. func reuseTargetsKey(r client.Repository) error { - var ( - err error - thisTargetsKeyID, thatTargetsKeyID string - ) - // Get all known targets keys. - targetsKeyList := r.GetCryptoService().ListKeys(data.CanonicalTargetsRole) + keyList := r.GetCryptoService().ListKeys(data.CanonicalTargetsRole) + // Try to extract a single targets key we can reuse. - switch len(targetsKeyList) { + switch len(keyList) { case 0: - err = fmt.Errorf("no targets key despite having initialized a repo") + return fmt.Errorf("no targets key despite having initialized a repo") case 1: log.Debug("Nothing to do, only one targets key available") + return nil case 2: // First, we publish current changes to repository in order to list roles. // FIXME: Find a find better way to list roles w/o publishing changes first. - publishErr := r.Publish() - if publishErr != nil { - err = publishErr - break + err := r.Publish() + if err != nil { + return err } // Get the current top-level roles. - roleWithSigs, listRolesErr := r.ListRoles() - if listRolesErr != nil { - err = listRolesErr - break + roleWithSigs, err := r.ListRoles() + if err != nil { + return err } // Get the current targets key. // NOTE: We do not delete it, in case the user wants to keep it. + var thisKeyID string for _, roleWithSig := range roleWithSigs { role := roleWithSig.Role if role.Name == data.CanonicalTargetsRole { if len(role.KeyIDs) == 1 { - thisTargetsKeyID = role.KeyIDs[0] - log.Debugf("This targets keyid: %s", thisTargetsKeyID) + thisKeyID = role.KeyIDs[0] + log.Debugf("This targets keyid: %s", thisKeyID) } else { return fmt.Errorf("this targets role has more than 1 key") } @@ -147,19 +163,19 @@ func reuseTargetsKey(r client.Repository) error { } // Get and reuse the other targets key. - for _, keyID := range targetsKeyList { - if keyID != thisTargetsKeyID { - thatTargetsKeyID = keyID + var thatKeyID string + for _, keyID := range keyList { + if keyID != thisKeyID { + thatKeyID = keyID break } } - log.Debugf("That targets keyID: %s", thatTargetsKeyID) - log.Debugf("Before rotating targets key from %s to %s", thisTargetsKeyID, thatTargetsKeyID) - err = r.RotateKey(data.CanonicalTargetsRole, false, []string{thatTargetsKeyID}) + log.Debugf("That targets keyID: %s", thatKeyID) + log.Debugf("Before rotating targets key from %s to %s", thisKeyID, thatKeyID) + err = r.RotateKey(data.CanonicalTargetsRole, false, []string{thatKeyID}) log.Debugf("After targets key rotation") + return err default: - err = fmt.Errorf("there are more than 2 targets keys") + return fmt.Errorf("there are more than two targets keys") } - - return err } diff --git a/pkg/tuf/list.go b/pkg/tuf/list.go index 3f4f5d53..b4d71891 100644 --- a/pkg/tuf/list.go +++ b/pkg/tuf/list.go @@ -1,45 +1,104 @@ package tuf import ( + "bytes" "encoding/hex" "fmt" + "strings" + "github.com/cnabio/signy/pkg/intoto" "github.com/theupdateframework/notary/client" "github.com/theupdateframework/notary/trustpinning" "github.com/theupdateframework/notary/tuf/data" ) -// PrintTargets prints all the targets for a specific GUN from a trust server -func PrintTargets(gun, trustServer, tlscacert, trustDir, timeout string) error { +// GetTargetWithRole returns a single target by name from the trusted collection +func GetTargetWithRole(gun, targetName, trustServer, tlscacert, trustDir, timeout string) (*client.TargetWithRole, error) { targets, err := GetTargets(gun, trustServer, tlscacert, trustDir, timeout) if err != nil { - return fmt.Errorf("cannot list targets:%v", err) + return nil, fmt.Errorf("cannot list targets:%v", err) } - for _, tgt := range targets { - fmt.Printf("%s\t%s\n", tgt.Name, hex.EncodeToString(tgt.Hashes["sha256"])) + for _, target := range targets { + if target.Name == targetName { + return target, nil + } } - return nil + + return nil, fmt.Errorf("cannot find target %v in trusted collection %v", targetName, gun) } -// GetTargetWithRole returns a single target by name from the trusted collection -func GetTargetWithRole(gun, name, trustServer, tlscacert, trustDir, timeout string) (*client.TargetWithRole, error) { - targets, err := GetTargets(gun, trustServer, tlscacert, trustDir, timeout) +// VerifyInToto ensures that the in-toto root layout, pubkeys, and links match the TUF metadata +func VerifyInTotoMetadata(gun, trustServer, tlscacert, trustDir, timeout string) error { + // get targets from releases + targets, err := GetTargets(gun, trustServer, tlscacert, trustDir, timeout, releasesRoleName) if err != nil { - return nil, fmt.Errorf("cannot list targets:%v", err) + return fmt.Errorf("cannot list %v :%v", releasesRoleName, err) } + // verify that releases signs ONLY links + // the target paths entrusted to the delegatee + paths := getReleasesPathPattern(gun) for _, target := range targets { - if target.Name == name { - return target, nil + if target.Role.String() != releasesRoleName.String() { + return fmt.Errorf("expected %v but got :%v", releasesRoleName, target.Role.String()) + } + // check the target name matches links + match := false + for _, path := range paths { + if strings.HasPrefix(target.Name, path) { + match = true + break + } + } + if !match { + return fmt.Errorf("%v does not match %v", target.Name, paths) + } + // check the hash and length matches + custom := intoto.Custom{} + custom.ReadRawMessage(target.Custom) + linkMeta, err := data.NewFileMeta(bytes.NewBuffer(custom.InToto.Data), data.NotaryDefaultHashes...) + if err != nil { + return err + } + if linkMeta.Length != target.Length { + return fmt.Errorf("%v has observed length %v but expected %v", target.Name, linkMeta.Length, target.Length) + } + err = data.CompareMultiHashes(linkMeta.Hashes, target.Hashes) + if err != nil { + return fmt.Errorf("%v has observed hashes %v but expected %v", target.Name, linkMeta.Hashes, target.Hashes) + } + } + + // get targets from the top-level targets role + targets, err = GetTargets(gun, trustServer, tlscacert, trustDir, timeout) + if err != nil { + return fmt.Errorf("cannot list %v :%v", data.CanonicalTargetsRole, err) + } + // TODO: verify that targets signs ONLY layouts and pubkeys + for _, target := range targets { + if target.Role.String() != data.CanonicalTargetsRole.String() { + return fmt.Errorf("expected %v but got :%v", data.CanonicalTargetsRole, target.Role.String()) + } + // check the target name matches links + match := false + for _, path := range paths { + if strings.HasPrefix(target.Name, path) { + match = true + break + } } + if !match { + return fmt.Errorf("%v does not match %v", target.Name, paths) + } + } - return nil, fmt.Errorf("cannot find target %v in trusted collection %v", name, gun) + return nil } // GetTargets returns all targets for a given gun from the trusted collection -func GetTargets(gun, trustServer, tlscacert, trustDir, timeout string) ([]*client.TargetWithRole, error) { +func GetTargets(gun, trustServer, tlscacert, trustDir, timeout string, roles ...data.RoleName) ([]*client.TargetWithRole, error) { if err := EnsureTrustDir(trustDir); err != nil { return nil, fmt.Errorf("cannot ensure trust directory: %v", err) } @@ -61,5 +120,18 @@ func GetTargets(gun, trustServer, tlscacert, trustDir, timeout string) ([]*clien return nil, fmt.Errorf("cannot create new file cached repository: %v", err) } - return repo.ListTargets() + return repo.ListTargets(roles...) +} + +// PrintTargets prints all the targets for a specific GUN from a trust server +func PrintTargets(gun, trustServer, tlscacert, trustDir, timeout string) error { + targets, err := GetTargets(gun, trustServer, tlscacert, trustDir, timeout) + if err != nil { + return fmt.Errorf("cannot list targets:%v", err) + } + + for _, tgt := range targets { + fmt.Printf("%s\t%s\n", tgt.Name, hex.EncodeToString(tgt.Hashes["sha256"])) + } + return nil } diff --git a/pkg/tuf/sign.go b/pkg/tuf/sign.go index 9fce8292..97ccce0f 100644 --- a/pkg/tuf/sign.go +++ b/pkg/tuf/sign.go @@ -1,97 +1,192 @@ package tuf import ( + "bytes" + "encoding/hex" "fmt" - canonicaljson "github.com/docker/go/canonical/json" + "github.com/cnabio/signy/pkg/docker" + "github.com/cnabio/signy/pkg/intoto" + "github.com/theupdateframework/notary/client" "github.com/theupdateframework/notary/trustpinning" "github.com/theupdateframework/notary/tuf/data" ) -// clearChangelist clears the notary staging changelist -func clearChangeList(notaryRepo client.Repository) error { - cl, err := notaryRepo.GetChangelist() - if err != nil { - return err - } - return cl.Clear("") -} - // SignAndPublish signs an artifact, then publishes the metadata to a trust server -func SignAndPublish(trustDir, trustServer, ref, file, tlscacert, rootKey, timeout string, custom *canonicaljson.RawMessage) (*client.Target, error) { +func SignAndPublish(trustDir, trustServer, ref, file, tlscacert, rootKey, timeout string, rootLayout intoto.RootLayout, publicKeys intoto.PublicKeys, links intoto.Links, bundleCustom intoto.Custom) (string, error) { if err := EnsureTrustDir(trustDir); err != nil { - return nil, fmt.Errorf("cannot ensure trust directory: %v", err) + return "", fmt.Errorf("cannot ensure trust directory: %v", err) } - repoInfo, tag, err := getRepoAndTag(ref) + gun, err := docker.GetGUN(ref) if err != nil { - return nil, fmt.Errorf("cannot get repo and tag from reference: %v", err) + return "", fmt.Errorf("cannot get GUN reference: %v", err) } - transport, err := makeTransport(trustServer, repoInfo.Name.Name(), tlscacert, timeout) + transport, err := makeTransport(trustServer, gun, tlscacert, timeout) if err != nil { - return nil, fmt.Errorf("cannot make transport: %v", err) + return "", fmt.Errorf("cannot make transport: %v", err) } repo, err := client.NewFileCachedRepository( trustDir, - data.GUN(repoInfo.Name.Name()), + data.GUN(gun), trustServer, transport, getPassphraseRetriever(), trustpinning.TrustPinConfig{}, ) if err != nil { - return nil, fmt.Errorf("cannot create new file cached repository: %v", err) + return "", fmt.Errorf("cannot create new file cached repository: %v", err) } err = clearChangeList(repo) if err != nil { - return nil, fmt.Errorf("cannot clear change list: %v", err) + return "", fmt.Errorf("cannot clear change list: %v", err) } - defer clearChangeList(repo) - if _, err = repo.ListTargets(); err != nil { + err = reuseKeys(repo, rootKey) + if err != nil { + return "", fmt.Errorf("cannot reuse keys: %v", err) + } + + err = addRootLayout(repo, rootLayout, publicKeys) + if err != nil { + return "", fmt.Errorf("cannot add root layout: %v", err) + } + + bundleDigest, err := addBundle(repo, ref, file, links, bundleCustom) + if err != nil { + return "", fmt.Errorf("cannot add bundle: %v", err) + } + + err = repo.Publish() + return bundleDigest, err +} + +func addBundle(repo client.Repository, ref, file string, links intoto.Links, bundleCustom intoto.Custom) (string, error) { + for linkFilename, linkCustom := range links { + linkMeta, err := data.NewFileMeta(bytes.NewBuffer(linkCustom.InToto.Data), data.NotaryDefaultHashes...) + if err != nil { + return "", fmt.Errorf("cannot get link meta: %v", err) + } + + linkCustomRawMessage, err := linkCustom.GetRawMessage() + if err != nil { + return "", fmt.Errorf("cannot get raw message for link custom: %v", err) + } + + linkTarget := client.Target{Name: linkFilename, Hashes: linkMeta.Hashes, Length: linkMeta.Length, Custom: &linkCustomRawMessage} + if err = repo.AddTarget(&linkTarget, releasesRoleName); err != nil { + return "", fmt.Errorf("cannot add link target: %v", err) + } + + } + + bundleCustomRawMessage, err := bundleCustom.GetRawMessage() + if err != nil { + return "", fmt.Errorf("cannot get raw message for bundle custom: %v", err) + } + + // NOTE: We use the full reference for the target filename of the bundle. + bundleTarget, err := client.NewTarget(ref, file, &bundleCustomRawMessage) + if err != nil { + return "", fmt.Errorf("cannot get bundle target: %v", err) + } + + // NOTE: And we add the bundle to the "targets/releases" instead of the top-level "targets" role. + if err = repo.AddTarget(bundleTarget, releasesRoleName); err != nil { + return "", fmt.Errorf("cannot add bundle target: %v", err) + } + + return hex.EncodeToString(bundleTarget.Hashes["sha256"]), nil +} + +func addRootLayout(repo client.Repository, rootLayout intoto.RootLayout, publicKeys intoto.PublicKeys) error { + for publicKeyFilename, publicKeyCustom := range publicKeys { + meta, err := data.NewFileMeta(bytes.NewBuffer(publicKeyCustom.InToto.Data), data.NotaryDefaultHashes...) + if err != nil { + return fmt.Errorf("cannot get public key meta: %v", err) + } + + publicKeyCustomRawMessage, err := publicKeyCustom.GetRawMessage() + if err != nil { + return fmt.Errorf("cannot get raw message for public key custom: %v", err) + } + + linkTarget := client.Target{Name: publicKeyFilename, Hashes: meta.Hashes, Length: meta.Length, Custom: &publicKeyCustomRawMessage} + if err = repo.AddTarget(&linkTarget, data.CanonicalTargetsRole); err != nil { + return fmt.Errorf("cannot add public key target: %v", err) + } + } + + rootLayoutMeta, err := data.NewFileMeta(bytes.NewBuffer(rootLayout.Custom.InToto.Data), data.NotaryDefaultHashes...) + if err != nil { + return fmt.Errorf("cannot get root layout meta: %v", err) + } + + rootLayoutCustomRawMessage, err := rootLayout.Custom.GetRawMessage() + if err != nil { + return fmt.Errorf("cannot get raw message for root layout custom: %v", err) + } + + linkTarget := client.Target{Name: rootLayout.Filename, Hashes: rootLayoutMeta.Hashes, Length: rootLayoutMeta.Length, Custom: &rootLayoutCustomRawMessage} + if err = repo.AddTarget(&linkTarget, data.CanonicalTargetsRole); err != nil { + return fmt.Errorf("cannot add root layout target: %v", err) + } + + return nil +} + +// clearChangelist clears the notary staging changelist +func clearChangeList(notaryRepo client.Repository) error { + cl, err := notaryRepo.GetChangelist() + if err != nil { + return err + } + return cl.Clear("") +} + +// reuse root and top-level targets keys +func reuseKeys(repo client.Repository, rootKey string) error { + if _, err := repo.ListTargets(); err != nil { switch err.(type) { case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist: // Reuse root key. rootKeyIDs, err := importRootKey(rootKey, repo, getPassphraseRetriever()) if err != nil { - return nil, err + return err } // NOTE: 2nd variadic argument is to indicate that snapshot is managed remotely. // The impact of a timestamp + snapshot key compromise is not terrible: // https://docs.docker.com/notary/service_architecture/#threat-model if err = repo.Initialize(rootKeyIDs, data.CanonicalSnapshotRole); err != nil { - return nil, fmt.Errorf("cannot initialize repo: %v", err) + return fmt.Errorf("cannot initialize repo: %v", err) } // Reuse targets key. if err = reuseTargetsKey(repo); err != nil { - return nil, fmt.Errorf("cannot reuse targets keys: %v", err) + return fmt.Errorf("cannot reuse %s keys: %v", data.CanonicalTargetsRole, err) } - default: - return nil, fmt.Errorf("cannot list targets: %v", err) - } - } - - target, err := client.NewTarget(tag, file, custom) - if err != nil { - return nil, err - } + // Reuse targets/releases key. + releasesPublicKey, err := reuseReleasesKey(repo) + if err != nil { + return fmt.Errorf("cannot reuse %s keys: %v", releasesRoleName, err) + } - // TODO - Radu M - // decide whether to allow actually passing roles as flags + // Delegate to targets/releases. + err = delegateToReleases(repo, releasesPublicKey) + if err != nil { + return fmt.Errorf("cannot delegate to %s: %v", releasesRoleName, err) + } - // If roles is empty, we default to adding to targets - if err = repo.AddTarget(target, data.NewRoleList([]string{})...); err != nil { - return nil, err + default: + return fmt.Errorf("cannot list targets while reusing keys: %v", err) + } } - - err = repo.Publish() - return target, err + return nil } diff --git a/pkg/tuf/verify.go b/pkg/tuf/verify.go index 28a933dd..95c1c707 100644 --- a/pkg/tuf/verify.go +++ b/pkg/tuf/verify.go @@ -11,13 +11,33 @@ import ( "github.com/theupdateframework/notary/client" "github.com/cnabio/signy/pkg/cnab" + "github.com/cnabio/signy/pkg/docker" ) +// GetTargetAndSHA returns the target with roles and the SHA256 of the target file +func GetTargetAndSHA(targetName, trustServer, tlscacert, trustDir, timeout string) (*client.TargetWithRole, string, error) { + gun, err := docker.GetGUN(targetName) + if err != nil { + return nil, "", fmt.Errorf("cannot get repo and tag from reference: %v", err) + } + + target, err := GetTargetWithRole(gun, targetName, trustServer, tlscacert, trustDir, timeout) + if err != nil { + return nil, "", err + } + + trustedSHA := hex.EncodeToString(target.Hashes["sha256"]) + log.Infof("Pulled trust data for %v, with role %v - SHA256: %v", targetName, target.Role, trustedSHA) + return target, trustedSHA, nil +} + +// GetThickBundle reads the thick bundle from disk func GetThickBundle(localFile string) ([]byte, error) { log.Infof("Reading thick bundle on disk: %v", localFile) return ioutil.ReadFile(localFile) } +// GetThinBundle reads the thin bundle from the OCI registry func GetThinBundle(ref string) ([]byte, error) { log.Infof("Pulling thin bundle from registry: %v", ref) bun, err := cnab.Pull(ref) @@ -51,20 +71,3 @@ func verifyTargetSHAFromBytes(buf []byte, trustedSHA string) error { } return nil } - -// GetTargetAndSHA returns the target with roles and the SHA256 of the target file -func GetTargetAndSHA(ref, trustServer, tlscacert, trustDir, timeout string) (*client.TargetWithRole, string, error) { - repoInfo, tag, err := getRepoAndTag(ref) - if err != nil { - return nil, "", fmt.Errorf("cannot get repo and tag from reference: %v", err) - } - - target, err := GetTargetWithRole(repoInfo.Name.Name(), tag, trustServer, tlscacert, trustDir, timeout) - if err != nil { - return nil, "", err - } - - trustedSHA := hex.EncodeToString(target.Hashes["sha256"]) - log.Infof("Pulled trust data for %v, with role %v - SHA256: %v", ref, target.Role, trustedSHA) - return target, trustedSHA, nil -} diff --git a/scripts/live-reload.sh b/scripts/live-reload.sh index fbe80c4e..a3f8070e 100755 --- a/scripts/live-reload.sh +++ b/scripts/live-reload.sh @@ -6,6 +6,7 @@ build () { echo "Building..." # Build an image containing python-in-toto to verify bundles/images with. docker build --rm -t cnabio/signy-in-toto-verifier:$TAG -f in-toto-container.Dockerfile . + make lint make TAG=$TAG install echo "...done." echo diff --git a/testdata/intoto/alice.pub b/testdata/intoto/alice.pub deleted file mode 100644 index 0e200eac..00000000 --- a/testdata/intoto/alice.pub +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxPX3kFs/z645x4UOC3KF -Y3V80YQtKrp6YS3qU+Jlvx/XzK53lb4sCDRU9jqBBx3We45TmFUibroMd8tQXCUS -e8gYCBUBqBmmz0dEHJYbW0tYF7IoapMIxhRYn76YqNdl1JoRTcmzIaOJ7QrHxQrS -GpivvTm6kQ9WLeApG1GLYJ3C3Wl4bnsI1bKSv55Zi45/JawHzTzYUAIXX9qCd3Io -HzDucz9IAj9Ookw0va/q9FjoPGrRB80IReVxLVnbo6pYJfu/O37jvEobHFa8ckHd -YxUIg8wvkIOy1O3M74lBDm6CVI0ZO25xPlDB/4nHAE1PbA3aF3lw8JGuxLDsetxm -fzgAleVt4vXLQiCrZaLf+0cM97JcT7wdHcbIvRLsij9LNP+2tWZgeZ/hIAOEdaDq -cYANPDIAxfTvbe9I0sXrCtrLer1SS7GqUmdFCdkdun8erXdNF0ls9Rp4cbYhjdf3 -yMxdI/24LUOOQ71cHW3ITIDImm6I8KmrXFM2NewTARKfAgMBAAE= ------END PUBLIC KEY----- diff --git a/testdata/intoto/foo.tar.gz b/testdata/intoto/foo.tar.gz deleted file mode 100644 index 5de7b881..00000000 Binary files a/testdata/intoto/foo.tar.gz and /dev/null differ diff --git a/testdata/intoto/malformed.template b/testdata/intoto/malformed.root.layout similarity index 100% rename from testdata/intoto/malformed.template rename to testdata/intoto/malformed.root.layout diff --git a/testdata/intoto/minimal/bundle.json b/testdata/intoto/minimal/bundle.json new file mode 100644 index 00000000..a9d0aa7a --- /dev/null +++ b/testdata/intoto/minimal/bundle.json @@ -0,0 +1,91 @@ +{ + "credentials": { + "hostkey": { + "env": "HOST_KEY", + "path": "/etc/hostkey.txt" + } + }, + "custom": { + "com.example.backup-preferences": { + "frequency": "daily" + }, + "com.example.duffle-bag": { + "icon": "https://example.com/icon.png", + "iconType": "PNG" + } + }, + "definitions": { + "http_port": { + "default": 80, + "maximum": 10240, + "minimum": 10, + "type": "integer" + }, + "port": { + "maximum": 65535, + "minimum": 1024, + "type": "integer" + }, + "string": { + "type": "string" + }, + "x509Certificate": { + "contentEncoding": "base64", + "contentMediaType": "application/x-x509-user-cert", + "type": "string", + "writeOnly": true + } + }, + "description": "An example 'thin' helloworld Cloud-Native Application Bundle", + "images": { + "my-microservice": { + "contentDigest": "sha256:aaaaaaaaaaaa...", + "description": "my microservice", + "image": "example/microservice:1.2.3" + } + }, + "invocationImages": [ + { + "contentDigest": "sha256:aaaaaaa...", + "image": "example/helloworld:0.1.0", + "imageType": "docker" + } + ], + "maintainers": [ + { + "email": "matt.butcher@microsoft.com", + "name": "Matt Butcher", + "url": "https://example.com" + } + ], + "name": "helloworld", + "outputs": { + "clientCert": { + "definition": "x509Certificate", + "path": "/cnab/app/outputs/clientCert" + }, + "hostName": { + "applyTo": [ + "install" + ], + "definition": "string", + "description": "the hostname produced installing the bundle", + "path": "/cnab/app/outputs/hostname" + }, + "port": { + "definition": "port", + "path": "/cnab/app/outputs/port" + } + }, + "parameters": { + "backend_port": { + "definition": "http_port", + "description": "The port that the back-end will listen on", + "destination": { + "env": "BACKEND_PORT" + } + } + }, + "schemaVersion": "v1.0.0", + "version": "0.1.2" +} \ No newline at end of file diff --git a/testdata/intoto/minimal/links/developer.2d2e5437.link b/testdata/intoto/minimal/links/developer.2d2e5437.link new file mode 100644 index 00000000..2348595f --- /dev/null +++ b/testdata/intoto/minimal/links/developer.2d2e5437.link @@ -0,0 +1,141 @@ +{ + "signatures": [ + { + "keyid": "2d2e5437de978b123ed8a50692cdb38c198ced0f1f356398abe9dd5206e890e2", + "sig": "6e477535c7df002e09a7badbb3159c4265e8d209a026d0676677a4a002189ebf0b19f0dbaa1e9a4bbcef70e3e2fe636d46f4ef6e5265c515797b9a77a9c241ef876b90954a8145cbf569f2fef8756de9e251936ad270b56646b4e1344f9200bb0ee8bb5c237969cc597249f89aa90680671433543852b63741000fe3e8b28c8542c573f661fe8f2c977ecccccec808b194c94b5468de7036de3517258996f7769ad16ce5a9190578a9465e37717d7262b4055c72986a13018855bf2bb27eb0877d2f44f151e83a8ce89724e501a0fa18c1bfa965122fc7bf231844c753f66f0718ab20e086a5966ed55b7f2080e0b89fcc70f52960c702cd31a53395ebc31edcbf5ca2ad8ec0758759a7d5cfad40e903a52ab6f44ac2ca508ce90da10270811aeee9648d41fc7ec72603214a3bf963c1e690a9cd30fde5e9119ee831e2f39ea56bf3922149e051a878baa5794d12e6a52a21db88eaa87ac4c2979cf5f123a2cffff8891b45ac093ad58bb37aa58f1a4e4afd86271badfe021b05c3c8736ea4a6" + } + ], + "signed": { + "_type": "link", + "byproducts": {}, + "command": [], + "environment": {}, + "materials": {}, + "name": "developer", + "products": { + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/credentials/hostkey/env": { + "sha256": "205c6e161cd52c8a5e28ac1a14a70ece07886438418ef1ed7ff431a3c59c55c2" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/credentials/hostkey/path": { + "sha256": "ea4278fd99a3cc839efd8d8675c2b754a6e556e0cd79e2dc10df03e9be071a56" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.backup-preferences/frequency": { + "sha256": "fa6a92cf80cf218ed717b3cc3a405ffda3fdf6a983d72fed1bdd113622fea03d" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.duffle-bag/icon": { + "sha256": "317d5a9514203bd1e19b80d39c846106513c7d20bd63271e8dbdb4821bff63b1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.duffle-bag/iconType": { + "sha256": "2775d1b05dce8419e4bab67f17fb5ed87eb0ca5b30232a04de1d574b99558200" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/default": { + "sha256": "48449a14a4ff7d79bb7a1b6f3d488eba397c36ef25634c111b49baf362511afc" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/maximum": { + "sha256": "205e7b780de08f42eda9fbf1715507758afd1f2eb499ffc6d0a352f904ee72f1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/minimum": { + "sha256": "4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/type": { + "sha256": "bb894e256c101d183cfd51432eebb3feb183cf155da5994b19a45406a3e24aac" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/maximum": { + "sha256": "f2f89ede8e7d4b3d2243dea1ca96b8ece56f793811d9708b4a0181bf81a50011" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/minimum": { + "sha256": "e39eef82f61b21e2e7f762fcc4307358f165757f2e77ec855d6992f7e0191932" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/type": { + "sha256": "bb894e256c101d183cfd51432eebb3feb183cf155da5994b19a45406a3e24aac" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/string/type": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/contentEncoding": { + "sha256": "cb65d001ead1184d17391b55d1e96be555a573d9254cac717104f5d9d97e817c" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/contentMediaType": { + "sha256": "fc395c0b2477371951c95b71625d3919c73980dbb24aeca496578fc86a904add" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/type": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/writeOnly": { + "sha256": "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/description": { + "sha256": "12ccf5980e26a71d58ac3b877b24f82fdaede3e01446038585b5b201d4b83c55" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/contentDigest": { + "sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/description": { + "sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/image": { + "sha256": "be56793296fdb27458fd80666e5dcd1af52dd298760097ed7e73944e70e05118" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/contentDigest": { + "sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/image": { + "sha256": "d33274172ff3405c8cbf2ebc6cbe2f3d5904a0d53d5521d0aa6a390124e51703" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/imageType": { + "sha256": "f320b810ea61ce6405c478a1a67befdcc117a307e62f17deb2417be2f98b1864" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/email": { + "sha256": "ea6b0d7bd10c06cbda2212bed77c5b2f9c0ef7b218afaf8e013f4466ba9f2ad1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/name": { + "sha256": "6682c39fd22bf39169f435916402584970df9a4d6ed72fc7ab7db46dca57d3e4" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/url": { + "sha256": "5775c078c67ebad469f37e1d888f3084804a19ce7511c28c74c54e8232a51bdb" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/name": { + "sha256": "7b91cf1e312a84544a3d5f82ce965daf5620579a4a5e7d37b90829238a2f1055" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/clientCert/definition": { + "sha256": "157c4a9d3e97adcdd2028934f7c21db802f1c90d2193ba902fb9cc17fd713402" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/clientCert/path": { + "sha256": "2c66367f304e04df32081f665b5e106d4835b8544b7999fbe5bc73cd7d16b94c" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/applyTo": { + "sha256": "2594d48ff5c9c3577770805617147fe8b06d206b22baa806c3fd21f352acd183" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/definition": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/description": { + "sha256": "da192c9f51c6dc131efe1418a1a408bbef863fd264cc488db48f947bb955efb4" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/path": { + "sha256": "fcc9b2b4e2eb66597d77def766e3ade74c37ff8f830bd0808303345a5ec80761" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/port/definition": { + "sha256": "1915cd692d3b19d814007446d9ab8c0a2cff60dc516035caba9cd00434802e94" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/port/path": { + "sha256": "5b6a3c0e9e60e2829fd2dce7c7f00d6db98ed9e84f43dbd407e9ca67de3e2413" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/definition": { + "sha256": "b70797c6a59d071c0171317fc593cfdda53d35cf1cd7d9fffaca351c84468b05" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/description": { + "sha256": "06b809960a94debf9253cbe7ac86bc220454a50ce25d27ad65dd319eb111dbe3" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/destination/env": { + "sha256": "7ad5e1a1cccb631d1248434e7a4a4e0bd2b7a74369c3c3cf6724a6ff65423331" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/schemaVersion": { + "sha256": "f6d482dd2cad1932e8f6ed9f3a5514a5e20cd68d02237463125baf78013bd182" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/version": { + "sha256": "d05b37e57bc92debe8b4e38039876ab538a95a66caa835796dd5fbd439f0ba33" + } + } + } +} \ No newline at end of file diff --git a/testdata/intoto/minimal/links/machine.dd035ca2.link b/testdata/intoto/minimal/links/machine.dd035ca2.link new file mode 100644 index 00000000..15845c5d --- /dev/null +++ b/testdata/intoto/minimal/links/machine.dd035ca2.link @@ -0,0 +1,271 @@ +{ + "signatures": [ + { + "keyid": "dd035ca2388fffa593a9f0cb76f3ece27fe45560da0a5f93f5f404da2faac745", + "sig": "20657c441605117736e843ab4ea51a0d32e07404fea0300c1259a3a6756ebe21c17dcc8aa442ad525c46a520c4e0568e0e920fcf0f2a943248451e7d216d2f62c3668f461e814951ecab7e68fcdec050744bdd4fbc20fd5b3e211e8f535ae58e344375b0a44290c640ba83ca6bfe404acf12c3945650a551411076f18c567d190900452e3191f4a8bfe7203237db9b349b82ad0dc007770a61dbf20a657d62d4549da015f060ab6c875e980720b0dc26d49d17f488e1b5b946f2cf008d0c9328161821368c5935ced367add4fbcea2a22a8ec6495153ee186bffbb45ffeec6e6ef14de2af1686e4c8b759af883abbe0651bdbd43cd08d37903af98a702fc1a2ef85c5dd5f51572f84cd120ff6d6b91b740bd8888e9365ebf6c3e883f9fa3cb5635ec1ee6f1ac34896b79a41bbc96b4a689b43b22fc81ca6ed9e8386251d696dd1dfc50d52494034b74016e6517c5a3e5e3f435b5d878f31f383e75f8253ad69e87f51fd37e5f039e88a9a22456c48a0d92dbc28e02dabf581b0a6146efd93601" + } + ], + "signed": { + "_type": "link", + "byproducts": { + "return-value": 0, + "stderr": "", + "stdout": "" + }, + "command": [ + "./do-machine-stuff" + ], + "environment": {}, + "materials": { + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/credentials/hostkey/env": { + "sha256": "205c6e161cd52c8a5e28ac1a14a70ece07886438418ef1ed7ff431a3c59c55c2" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/credentials/hostkey/path": { + "sha256": "ea4278fd99a3cc839efd8d8675c2b754a6e556e0cd79e2dc10df03e9be071a56" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.backup-preferences/frequency": { + "sha256": "fa6a92cf80cf218ed717b3cc3a405ffda3fdf6a983d72fed1bdd113622fea03d" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.duffle-bag/icon": { + "sha256": "317d5a9514203bd1e19b80d39c846106513c7d20bd63271e8dbdb4821bff63b1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.duffle-bag/iconType": { + "sha256": "2775d1b05dce8419e4bab67f17fb5ed87eb0ca5b30232a04de1d574b99558200" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/default": { + "sha256": "48449a14a4ff7d79bb7a1b6f3d488eba397c36ef25634c111b49baf362511afc" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/maximum": { + "sha256": "205e7b780de08f42eda9fbf1715507758afd1f2eb499ffc6d0a352f904ee72f1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/minimum": { + "sha256": "4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/type": { + "sha256": "bb894e256c101d183cfd51432eebb3feb183cf155da5994b19a45406a3e24aac" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/maximum": { + "sha256": "f2f89ede8e7d4b3d2243dea1ca96b8ece56f793811d9708b4a0181bf81a50011" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/minimum": { + "sha256": "e39eef82f61b21e2e7f762fcc4307358f165757f2e77ec855d6992f7e0191932" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/type": { + "sha256": "bb894e256c101d183cfd51432eebb3feb183cf155da5994b19a45406a3e24aac" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/string/type": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/contentEncoding": { + "sha256": "cb65d001ead1184d17391b55d1e96be555a573d9254cac717104f5d9d97e817c" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/contentMediaType": { + "sha256": "fc395c0b2477371951c95b71625d3919c73980dbb24aeca496578fc86a904add" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/type": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/writeOnly": { + "sha256": "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/description": { + "sha256": "12ccf5980e26a71d58ac3b877b24f82fdaede3e01446038585b5b201d4b83c55" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/contentDigest": { + "sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/description": { + "sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/image": { + "sha256": "be56793296fdb27458fd80666e5dcd1af52dd298760097ed7e73944e70e05118" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/contentDigest": { + "sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/image": { + "sha256": "d33274172ff3405c8cbf2ebc6cbe2f3d5904a0d53d5521d0aa6a390124e51703" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/imageType": { + "sha256": "f320b810ea61ce6405c478a1a67befdcc117a307e62f17deb2417be2f98b1864" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/email": { + "sha256": "ea6b0d7bd10c06cbda2212bed77c5b2f9c0ef7b218afaf8e013f4466ba9f2ad1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/name": { + "sha256": "6682c39fd22bf39169f435916402584970df9a4d6ed72fc7ab7db46dca57d3e4" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/url": { + "sha256": "5775c078c67ebad469f37e1d888f3084804a19ce7511c28c74c54e8232a51bdb" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/name": { + "sha256": "7b91cf1e312a84544a3d5f82ce965daf5620579a4a5e7d37b90829238a2f1055" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/clientCert/definition": { + "sha256": "157c4a9d3e97adcdd2028934f7c21db802f1c90d2193ba902fb9cc17fd713402" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/clientCert/path": { + "sha256": "2c66367f304e04df32081f665b5e106d4835b8544b7999fbe5bc73cd7d16b94c" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/applyTo": { + "sha256": "2594d48ff5c9c3577770805617147fe8b06d206b22baa806c3fd21f352acd183" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/definition": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/description": { + "sha256": "da192c9f51c6dc131efe1418a1a408bbef863fd264cc488db48f947bb955efb4" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/path": { + "sha256": "fcc9b2b4e2eb66597d77def766e3ade74c37ff8f830bd0808303345a5ec80761" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/port/definition": { + "sha256": "1915cd692d3b19d814007446d9ab8c0a2cff60dc516035caba9cd00434802e94" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/port/path": { + "sha256": "5b6a3c0e9e60e2829fd2dce7c7f00d6db98ed9e84f43dbd407e9ca67de3e2413" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/definition": { + "sha256": "b70797c6a59d071c0171317fc593cfdda53d35cf1cd7d9fffaca351c84468b05" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/description": { + "sha256": "06b809960a94debf9253cbe7ac86bc220454a50ce25d27ad65dd319eb111dbe3" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/destination/env": { + "sha256": "7ad5e1a1cccb631d1248434e7a4a4e0bd2b7a74369c3c3cf6724a6ff65423331" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/schemaVersion": { + "sha256": "f6d482dd2cad1932e8f6ed9f3a5514a5e20cd68d02237463125baf78013bd182" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/version": { + "sha256": "d05b37e57bc92debe8b4e38039876ab538a95a66caa835796dd5fbd439f0ba33" + } + }, + "name": "machine", + "products": { + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/credentials/hostkey/env": { + "sha256": "205c6e161cd52c8a5e28ac1a14a70ece07886438418ef1ed7ff431a3c59c55c2" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/credentials/hostkey/path": { + "sha256": "ea4278fd99a3cc839efd8d8675c2b754a6e556e0cd79e2dc10df03e9be071a56" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.backup-preferences/frequency": { + "sha256": "fa6a92cf80cf218ed717b3cc3a405ffda3fdf6a983d72fed1bdd113622fea03d" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.duffle-bag/icon": { + "sha256": "317d5a9514203bd1e19b80d39c846106513c7d20bd63271e8dbdb4821bff63b1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/custom/com.example.duffle-bag/iconType": { + "sha256": "2775d1b05dce8419e4bab67f17fb5ed87eb0ca5b30232a04de1d574b99558200" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/default": { + "sha256": "48449a14a4ff7d79bb7a1b6f3d488eba397c36ef25634c111b49baf362511afc" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/maximum": { + "sha256": "205e7b780de08f42eda9fbf1715507758afd1f2eb499ffc6d0a352f904ee72f1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/minimum": { + "sha256": "4a44dc15364204a80fe80e9039455cc1608281820fe2b24f1e5233ade6af1dd5" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/http_port/type": { + "sha256": "bb894e256c101d183cfd51432eebb3feb183cf155da5994b19a45406a3e24aac" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/maximum": { + "sha256": "f2f89ede8e7d4b3d2243dea1ca96b8ece56f793811d9708b4a0181bf81a50011" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/minimum": { + "sha256": "e39eef82f61b21e2e7f762fcc4307358f165757f2e77ec855d6992f7e0191932" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/port/type": { + "sha256": "bb894e256c101d183cfd51432eebb3feb183cf155da5994b19a45406a3e24aac" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/string/type": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/contentEncoding": { + "sha256": "cb65d001ead1184d17391b55d1e96be555a573d9254cac717104f5d9d97e817c" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/contentMediaType": { + "sha256": "fc395c0b2477371951c95b71625d3919c73980dbb24aeca496578fc86a904add" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/type": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/definitions/x509Certificate/writeOnly": { + "sha256": "b5bea41b6c623f7c09f1bf24dcae58ebab3c0cdd90ad966bc43a45b44867e12b" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/description": { + "sha256": "12ccf5980e26a71d58ac3b877b24f82fdaede3e01446038585b5b201d4b83c55" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/contentDigest": { + "sha256": "a9b0c315f1bc108882e4488d1d9320264259585a2af6e9ebdfae4a3191262b51" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/description": { + "sha256": "a3ff9793ffc0d9ae43064176db5add9cd33c579001cdf90f792b7ca9a0e004a7" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/images/my-microservice/image": { + "sha256": "be56793296fdb27458fd80666e5dcd1af52dd298760097ed7e73944e70e05118" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/contentDigest": { + "sha256": "8aca5133332d02975e86c282acc4d55b1afdab3b25f8fd8b3ec5cf2ff8362f99" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/image": { + "sha256": "d33274172ff3405c8cbf2ebc6cbe2f3d5904a0d53d5521d0aa6a390124e51703" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/invocationImages/[0]/imageType": { + "sha256": "f320b810ea61ce6405c478a1a67befdcc117a307e62f17deb2417be2f98b1864" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/email": { + "sha256": "ea6b0d7bd10c06cbda2212bed77c5b2f9c0ef7b218afaf8e013f4466ba9f2ad1" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/name": { + "sha256": "6682c39fd22bf39169f435916402584970df9a4d6ed72fc7ab7db46dca57d3e4" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/maintainers/[0]/url": { + "sha256": "5775c078c67ebad469f37e1d888f3084804a19ce7511c28c74c54e8232a51bdb" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/name": { + "sha256": "7b91cf1e312a84544a3d5f82ce965daf5620579a4a5e7d37b90829238a2f1055" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/clientCert/definition": { + "sha256": "157c4a9d3e97adcdd2028934f7c21db802f1c90d2193ba902fb9cc17fd713402" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/clientCert/path": { + "sha256": "2c66367f304e04df32081f665b5e106d4835b8544b7999fbe5bc73cd7d16b94c" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/applyTo": { + "sha256": "2594d48ff5c9c3577770805617147fe8b06d206b22baa806c3fd21f352acd183" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/definition": { + "sha256": "e9e5c1c9e4f6277339d1bcde0733a59bd42f8731f449da6dc13010a916930d48" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/description": { + "sha256": "da192c9f51c6dc131efe1418a1a408bbef863fd264cc488db48f947bb955efb4" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/hostName/path": { + "sha256": "fcc9b2b4e2eb66597d77def766e3ade74c37ff8f830bd0808303345a5ec80761" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/port/definition": { + "sha256": "1915cd692d3b19d814007446d9ab8c0a2cff60dc516035caba9cd00434802e94" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/outputs/port/path": { + "sha256": "5b6a3c0e9e60e2829fd2dce7c7f00d6db98ed9e84f43dbd407e9ca67de3e2413" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/definition": { + "sha256": "b70797c6a59d071c0171317fc593cfdda53d35cf1cd7d9fffaca351c84468b05" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/description": { + "sha256": "06b809960a94debf9253cbe7ac86bc220454a50ce25d27ad65dd319eb111dbe3" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/parameters/backend_port/destination/env": { + "sha256": "7ad5e1a1cccb631d1248434e7a4a4e0bd2b7a74369c3c3cf6724a6ff65423331" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/schemaVersion": { + "sha256": "f6d482dd2cad1932e8f6ed9f3a5514a5e20cd68d02237463125baf78013bd182" + }, + "cnab+json:/home/saky/Work/secure-systems-lab/cnab-ite-4/bundle.json$/version": { + "sha256": "d05b37e57bc92debe8b4e38039876ab538a95a66caa835796dd5fbd439f0ba33" + } + } + } +} diff --git a/testdata/intoto/minimal/root.layout b/testdata/intoto/minimal/root.layout new file mode 100644 index 00000000..3268392f --- /dev/null +++ b/testdata/intoto/minimal/root.layout @@ -0,0 +1,120 @@ +{ + "signatures": [ + { + "keyid": "737c25cc5ed977df2979fe029909d2d36b96adb4a65b9687fb8d150eaa29a4d8", + "sig": "bc4a54ac4e7b52d6dfd36e8e0ca1b78e4f4e7d0c2b388ddd6cc738f599fc6d32b52fdbf2e2109e17debfa1a6d37969f217fb9e6f9622f980d33ca67b722ab7ef804497e8f9f070e1f4d338fb34adeb009f966f3aa42ba95d94ec8852c3b7c0399469552a99e5ddbc97368f587600468aa321887a92d7b45eba06a5a4bb932918987cbfe2ee41f88eeb614d35fbc84111c82d58faa2574a2f7b0861ab2652ce23f2a013b06e487fdf29d17ce50d1e6daace0d36657c1b292a6c3065efe6071fd24267137859e49456d69dc6cd344fd4f44a98e6a796c2ac49dbde38458d7f04ddfde1a6c64df634aece3620768828433d3f2f0b381e2956226036cdb68d94c6bdd044ca4732bb136addc037ceb43b7a2d8fa2c536a326ae8304067daa3e59e979ac0f1a079b14c66de5afb6f8d50a241c366d4fccd07dc792713e5b3e2a6f3870971c8aace1b2137341168693135c75e3d341eaa39d33cee4b83336c732fd3c305654b9c9f794d5839464455a3e9cc3a6ca4dc2ca0064d668ef392184f5933ed1" + } + ], + "signed": { + "_type": "layout", + "expires": "2021-05-12T11:15:05Z", + "inspect": [], + "keys": { + "2d2e5437de978b123ed8a50692cdb38c198ced0f1f356398abe9dd5206e890e2": { + "keyid": "2d2e5437de978b123ed8a50692cdb38c198ced0f1f356398abe9dd5206e890e2", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "private": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA4X062OOJPtd//g8acQ07\n+3xnCMCsQkMkOhJlaCWkxCFqSI8bUQrzRg1jfpCRCqzhEscTy/Vw/xWNvhgGOzcc\nYyCpnwDcr3CK3G58lVz2mnSyAW9PCOGvwgLfKMC7Z99q0tLRa3YYqzrajgYsL9D2\nPh+4DrlbAADfQIok7MkkjBqvKsFptr6N+KsB3pkQyGZUYAMdUUiQU8BV2oWNfJQo\n0PHW5fi5hfBCUGzDQB9U22fhD3I6sgKVfA+948mo+Y9QRp53WvmjR47xb5KjNJR8\niIq8htwXIe7JCJxcyEh7hjKE5E6Qm9OhN2e99uta9XiIX1hIqSdh+BcRuBb1SbJD\nX3OBqqZHtUJ9hiNLz+PmlMwLS+02sqIQud4Vhjfy83KnfOoZ0PRU9sUSQDDe/wnK\nC7PWwCfyBto7wf9EWOrRjlG/DwIPiRsxrZ2XhHJu3x4jjXjrkT6MIPWZESJvonZM\n5XIekFjaYt/mnPybuwMZCulAwQZ7ucJqf9zJUFhRYgZRAgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "dd035ca2388fffa593a9f0cb76f3ece27fe45560da0a5f93f5f404da2faac745": { + "keyid": "dd035ca2388fffa593a9f0cb76f3ece27fe45560da0a5f93f5f404da2faac745", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "private": "", + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAqxqOAKWUWeiEBNtH1Nx2\n/8IKsSpbxy9NoTT31uTVK57oX0EomrBuCY4Ec6kcBWDPcqp6Z+2Z9baVzRB08SzO\nIJ3tGsTTdmJaFXFXjrDix/AioNmpCFh0ditOYoxUFu+skYV7PoHQ3BH7A5m2YxdH\n+KiLh2ccCvNnL/Wdio/6hwyVp4lZMFgQdhi7ba5EzuzwLt6dkB+9Fle2PMgeF+od\n/Ly7oXXaUi5lbPNLzf4Dkhr02qeKLFap35hBqXjqcx68vOfjuYFWwFaHmkCPjDpf\nTaLbPnDtXVWM8HzHdb4lVrZCpwpj859/QuDGb+uJyto3BsSHMli2v5e9QKcxtOzn\n6c5YtQkfL7u/n/vM3WuMsq78mFLoBNzHWrEsKp1ZKtBQDXfKDaW2io8BiWlREseh\nbk9ekBEvh8BmjBPS7A62z389kjUKZYhfaRSsaLGkUv0CnRCnuEQxCHpIUztHGiRx\nNpWz3dgp3t6+f/ZNC+ro8+FoHDGzEHX42oxD25E2H16BAgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + } + }, + "readme": "", + "steps": [ + { + "_type": "step", + "expected_command": [], + "expected_materials": [ + [ + "DISALLOW", + "*" + ] + ], + "expected_products": [ + [ + "CREATE", + "cnab+json:*/bundle.json$*" + ], + [ + "DISALLOW", + "*" + ] + ], + "name": "developer", + "pubkeys": [ + "2d2e5437de978b123ed8a50692cdb38c198ced0f1f356398abe9dd5206e890e2" + ], + "threshold": 1 + }, + { + "_type": "step", + "expected_command": [ + "./do-machine-stuff" + ], + "expected_materials": [ + [ + "MATCH", + "cnab+json:*/bundle.json$*", + "WITH", + "PRODUCTS", + "FROM", + "developer" + ], + [ + "DISALLOW", + "*" + ] + ], + "expected_products": [ + [ + "MODIFY", + "cnab+json:*/bundle.json$/images/*/contentDigest" + ], + [ + "MODIFY", + "cnab+json:*/bundle.json$/images/*/description" + ], + [ + "MODIFY", + "cnab+json:*/bundle.json$/invocationImages/*/contentDigest" + ], + [ + "MATCH", + "cnab+json:*/bundle.json$*", + "WITH", + "MATERIALS", + "FROM", + "machine" + ], + [ + "DISALLOW", + "*" + ] + ], + "name": "machine", + "pubkeys": [ + "dd035ca2388fffa593a9f0cb76f3ece27fe45560da0a5f93f5f404da2faac745" + ], + "threshold": 1 + } + ] + } +} diff --git a/testdata/intoto/minimal/root.layout.pub b/testdata/intoto/minimal/root.layout.pub new file mode 100644 index 00000000..34d7cf65 --- /dev/null +++ b/testdata/intoto/minimal/root.layout.pub @@ -0,0 +1,11 @@ +-----BEGIN PUBLIC KEY----- +MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA1uHXuCIQKFHzPv8nM/QJ +qROdJz9Fx+wmPMaTfXxHXVt93CLdsn1JYPuLQEdhUA4s1AgOnfNYr4mEYNlCJ/lV +j4Ilt6QBloqKMqWzxi1KAEEnX/o6WQhMPZdvR3lZADwh/57fJMRyFpKQT4adv4kx +FAFVn0nUSrZj8PtSZw84Jt0ghSh1heEv9Cjza8Tf1a6XiGhsrhvU/ADWFN6ZmLdW +mscnouwtro03ic9DkyrhZYj3LnbOEvQ7zkt6tzrdgkzh925BvU8whxItrNrThX6n +4WaIJ2BUy2ZAxSrNXIWs2mW4mXmKuUs0q2477+Bh0Wa8RDmIKqW28ITxCarLrdfX +DDkm7WpDNZLfWBmQwyZaDUCpZwuQ/vsEDyNFfAk1f57drp91ACoZO68lB0f01Qu0 +LFOXOonXBmcdgC2spNTQPP7GZz861aa4nFK35JpWaT3N/9D861qjJ9XVYCEe0hK6 +rR9yKZfjBfosDH02KwCcNLvHElDip6U6yPMZKogs5w8/AgMBAAE= +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/testdata/intoto/package.2f89b927.link b/testdata/intoto/package.2f89b927.link deleted file mode 100644 index e7bde586..00000000 --- a/testdata/intoto/package.2f89b927.link +++ /dev/null @@ -1,34 +0,0 @@ -{ - "signatures": [ - { - "keyid": "2f89b9272acfc8f4a0a0f094d789fdb0ba798b0fe41f2f5f417c12f0085ff498", - "sig": "66365d379d66a2e76d39a1f048847826393127572ba43bead96419499b02561a08e1cb06cf91f2addd87c30a01f776a8ccc599574bc9a2bd519558351f56cffa61ac4f994d0d491204ff54707937e15f9abfa97c5bda1ec1ae2a2afea63f808613f4fb343b85a5a455b668b95fa3a11cb9b34219d4d6af2dd4e80a9af01023954a8813b510a6ff6041c3af52056d021fabbc975211b0d8ee7a429a6c22efde583d8ac0719fd657b398a3e02cc711897acbe8cadf32d54f47012aa44621728ede42c3bc95c662f9c1211df4e18da8e0f6b2de358700cea5db1e76fc61ef5a90bcebcc883eed2272e5ca1c8cbb09b868613b839266cd3ae346ce88439bdb5bb4c69dcb7398f4373f2b051adb3d44d11ef1b70c7189aa5c0e6906bf7be1228dc553390024c9c796316067fda7d63cf60bfac86ef2e13bbd8e4c3575683673f7cdf4639c3a5dc225fc0c040dbd9962a6ff51913b240544939ce2d32a5e84792c0acfa94ee07e88e474bf4937558d107c6ecdef5b5b3a7f3a44a657662bbc1046df3a" - } - ], - "signed": { - "_type": "link", - "byproducts": { - "return-value": 0, - "stderr": "a foo.py\n", - "stdout": "" - }, - "command": [ - "tar", - "zcvf", - "foo.tar.gz", - "foo.py" - ], - "environment": {}, - "materials": { - "foo.py": { - "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549" - } - }, - "name": "package", - "products": { - "foo.tar.gz": { - "sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c1e5aabb7c98514f355" - } - } - } -} \ No newline at end of file diff --git a/testdata/intoto/root.layout b/testdata/intoto/root.layout deleted file mode 100644 index 6812818d..00000000 --- a/testdata/intoto/root.layout +++ /dev/null @@ -1,136 +0,0 @@ -{ - "signatures": [ - { - "keyid": "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b588f3e9cc48b35", - "sig": "02813858670c66647c17802d84f06453589f41850013a544609e9d33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d525551d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb227127178d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe595804f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b533958f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b92cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41dae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65aa626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17" - } - ], - "signed": { - "_type": "layout", - "expires": "2020-11-18T16:06:36Z", - "inspect": [ - { - "_type": "inspection", - "expected_materials": [ - [ - "MATCH", - "foo.tar.gz", - "WITH", - "PRODUCTS", - "FROM", - "package" - ], - [ - "DISALLOW", - "foo.tar.gz" - ] - ], - "expected_products": [ - [ - "MATCH", - "foo.py", - "WITH", - "PRODUCTS", - "FROM", - "write-code" - ], - [ - "DISALLOW", - "foo.py" - ] - ], - "name": "untar", - "run": [ - "tar", - "xfz", - "foo.tar.gz" - ] - } - ], - "keys": { - "2f89b9272acfc8f4a0a0f094d789fdb0ba798b0fe41f2f5f417c12f0085ff498": { - "keyid": "2f89b9272acfc8f4a0a0f094d789fdb0ba798b0fe41f2f5f417c12f0085ff498", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "private": "", - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQS8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTyONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLRqzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSbJ/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLCfQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARRwU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1gKqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5": { - "keyid": "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5", - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "private": "", - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0Zfzonp3/FScaIP+KKuz\nB+OZNFpjbVGWjm3leqnFqHYLqrLcCw5KhlXpycJqoSvZBpO+PFCksUx8U/ryklHG\nVoDiB84pRkvZtBoVaA4b4IHDIhz1K5NqkJgieya4fwReTxmCW0a9gH7AnDicHBCX\nlzMxqEdt6OKMV5g4yjKaxf8lW72O1gSI46GSIToo+Z7UUgs3ofaM5UFIcczgCpUa\n5kEKocB6cSZ9U8PKRLSs0xO0ROjrcOTsfxMs8eV4bsRCWY5mAq1WM9EHDSV9WO8g\nqrRmanC4enNqa8jU4O3zhgJVegP9A01r9AwNt6AqgPSikwhXN/P4v1FMYV+R6N3b\nS1lsVWRAnwBq5RFz5zVvcY88JEkHbrcBqP/A4909NXae1VMXmnoJb4EzGAkyUySB\na+fHXAVJgzwyv3I48d/OIjH8NWcVmM/DQL7FtcJk3tp0YUjY5wNpcbQTnLzURtlU\nsd+MtGuvdlDxUUvtUYCIVKRdS8UzYnTPjI2xzeoSHZ2ZAgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - } - }, - "readme": "", - "steps": [ - { - "_type": "step", - "expected_command": [], - "expected_materials": [], - "expected_products": [ - [ - "ALLOW", - "foo.py" - ] - ], - "name": "write-code", - "pubkeys": [ - "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5" - ], - "threshold": 1 - }, - { - "_type": "step", - "expected_command": [ - "tar", - "zcvf", - "foo.tar.gz", - "foo.py" - ], - "expected_materials": [ - [ - "MATCH", - "foo.py", - "WITH", - "PRODUCTS", - "FROM", - "write-code" - ], - [ - "DISALLOW", - "*" - ] - ], - "expected_products": [ - [ - "ALLOW", - "foo.tar.gz" - ], - [ - "ALLOW", - "foo.py" - ] - ], - "name": "package", - "pubkeys": [ - "2f89b9272acfc8f4a0a0f094d789fdb0ba798b0fe41f2f5f417c12f0085ff498" - ], - "threshold": 1 - } - ] - } -} \ No newline at end of file diff --git a/testdata/intoto/root.layout.pub b/testdata/intoto/root.layout.pub deleted file mode 100644 index 0e200eac..00000000 --- a/testdata/intoto/root.layout.pub +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxPX3kFs/z645x4UOC3KF -Y3V80YQtKrp6YS3qU+Jlvx/XzK53lb4sCDRU9jqBBx3We45TmFUibroMd8tQXCUS -e8gYCBUBqBmmz0dEHJYbW0tYF7IoapMIxhRYn76YqNdl1JoRTcmzIaOJ7QrHxQrS -GpivvTm6kQ9WLeApG1GLYJ3C3Wl4bnsI1bKSv55Zi45/JawHzTzYUAIXX9qCd3Io -HzDucz9IAj9Ookw0va/q9FjoPGrRB80IReVxLVnbo6pYJfu/O37jvEobHFa8ckHd -YxUIg8wvkIOy1O3M74lBDm6CVI0ZO25xPlDB/4nHAE1PbA3aF3lw8JGuxLDsetxm -fzgAleVt4vXLQiCrZaLf+0cM97JcT7wdHcbIvRLsij9LNP+2tWZgeZ/hIAOEdaDq -cYANPDIAxfTvbe9I0sXrCtrLer1SS7GqUmdFCdkdun8erXdNF0ls9Rp4cbYhjdf3 -yMxdI/24LUOOQ71cHW3ITIDImm6I8KmrXFM2NewTARKfAgMBAAE= ------END PUBLIC KEY----- diff --git a/testdata/intoto/write-code.776a00e2.link b/testdata/intoto/write-code.776a00e2.link deleted file mode 100644 index 1baf159c..00000000 --- a/testdata/intoto/write-code.776a00e2.link +++ /dev/null @@ -1,21 +0,0 @@ -{ - "signatures": [ - { - "keyid": "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5", - "sig": "ba2899895d769db034b898e27104a3f8d6cfca4f482c55fc68283cf34feede07966f9d6a32ea283215d373d8b3f2d5b7c7b02546f2cb55751eb347069cd4225da7d5829491aef18405380e21a74b04859c4db41e33133b2aae323c84e95d081a544d58940396f94d49fb718637025a3b7d0b9d4fb3d0ae2a604cb4f45c4cb001e20c411a9832851916b3a2e21d2e29a4d33300a848cd968b588bce7483f6f751ee95c2eb6c18c4e2978be6bdd9eb63b9436e434b38c7f37a7c9f444744a250470262e9ea408e65b96608a6b7748ead175d5b3894a20f258046c769e94e50da4145052dc9bb736196edcb86d79857437d4994a7ec9f022fae3c16645605ae03e4f3408f29818dcaec0ff3e513a5fab6906877ea5e4c92bfa0967913ce70ddeb598e73cb8799ce80d1bf2b88e53d1264f0a36d3549be86b2dff39592a59d4982176d04f5f2d7170a13f5f37ee471493be1eb9a30e002e77e9046b29aa1c1363ca46e4a2ae2f96dd780d0132469815e3fe1ab6db11b570e9411d0968482ac02d2cc" - } - ], - "signed": { - "_type": "link", - "byproducts": {}, - "command": [], - "environment": {}, - "materials": {}, - "name": "write-code", - "products": { - "foo.py": { - "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549" - } - } - } -} \ No newline at end of file