func TestRotation(t *testing.T) { signer := signed.NewEd25519() repo := tuf.NewRepo(signer) remote := store.NewMemoryStore(nil) cache := store.NewMemoryStore(nil) // Generate initial root key and role and add to key DB rootKey, err := signer.Create("root", data.ED25519Key) assert.NoError(t, err, "Error creating root key") rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil) assert.NoError(t, err, "Error creating root role") originalRoot, err := data.NewRoot( map[string]data.PublicKey{rootKey.ID(): rootKey}, map[string]*data.RootRole{"root": &rootRole.RootRole}, false, ) repo.Root = originalRoot // Generate new key and role. replacementKey, err := signer.Create("root", data.ED25519Key) assert.NoError(t, err, "Error creating replacement root key") replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil) assert.NoError(t, err, "Error creating replacement root role") // Generate a new root with the replacement key and role testRoot, err := data.NewRoot( map[string]data.PublicKey{replacementKey.ID(): replacementKey}, map[string]*data.RootRole{ data.CanonicalRootRole: &replacementRole.RootRole, data.CanonicalSnapshotRole: &replacementRole.RootRole, data.CanonicalTargetsRole: &replacementRole.RootRole, data.CanonicalTimestampRole: &replacementRole.RootRole, }, false, ) assert.NoError(t, err, "Failed to create new root") // Sign testRoot with both old and new keys signedRoot, err := testRoot.ToSigned() err = signed.Sign(signer, signedRoot, rootKey, replacementKey) assert.NoError(t, err, "Failed to sign root") var origKeySig bool var replKeySig bool for _, sig := range signedRoot.Signatures { if sig.KeyID == rootKey.ID() { origKeySig = true } else if sig.KeyID == replacementKey.ID() { replKeySig = true } } assert.True(t, origKeySig, "Original root key signature not present") assert.True(t, replKeySig, "Replacement root key signature not present") client := NewClient(repo, remote, cache) err = client.verifyRoot("root", signedRoot, 0) assert.NoError(t, err, "Failed to verify key rotated root") }
func TestDownloadSnapshotHappy(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) signedOrig, err = repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) orig, err = json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("timestamp", orig) assert.NoError(t, err) err = client.downloadSnapshot() assert.NoError(t, err) }
func TestRotationNewSigMissing(t *testing.T) { logrus.SetLevel(logrus.DebugLevel) kdb := keys.NewDB() signer := signed.NewEd25519() repo := tuf.NewRepo(kdb, signer) remote := store.NewMemoryStore(nil, nil) cache := store.NewMemoryStore(nil, nil) // Generate initial root key and role and add to key DB rootKey, err := signer.Create("root", data.ED25519Key) assert.NoError(t, err, "Error creating root key") rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) assert.NoError(t, err, "Error creating root role") kdb.AddKey(rootKey) err = kdb.AddRole(rootRole) assert.NoError(t, err, "Error adding root role to db") // Generate new key and role. These will appear in the root.json // but will not be added to the keyDB. replacementKey, err := signer.Create("root", data.ED25519Key) assert.NoError(t, err, "Error creating replacement root key") replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil, nil) assert.NoError(t, err, "Error creating replacement root role") assert.NotEqual(t, rootKey.ID(), replacementKey.ID(), "Key IDs are the same") // Generate a new root with the replacement key and role testRoot, err := data.NewRoot( map[string]data.PublicKey{replacementKey.ID(): replacementKey}, map[string]*data.RootRole{"root": &replacementRole.RootRole}, false, ) assert.NoError(t, err, "Failed to create new root") _, ok := testRoot.Signed.Keys[rootKey.ID()] assert.False(t, ok, "Old root key appeared in test root") // Sign testRoot with both old and new keys signedRoot, err := testRoot.ToSigned() err = signed.Sign(signer, signedRoot, rootKey) assert.NoError(t, err, "Failed to sign root") var origKeySig bool var replKeySig bool for _, sig := range signedRoot.Signatures { if sig.KeyID == rootKey.ID() { origKeySig = true } else if sig.KeyID == replacementKey.ID() { replKeySig = true } } assert.True(t, origKeySig, "Original root key signature not present") assert.False(t, replKeySig, "Replacement root key signature was present and shouldn't be") client := NewClient(repo, remote, kdb, cache) err = client.verifyRoot("root", signedRoot, 0) assert.Error(t, err, "Should have errored on verify as replacement signature was missing.") }
// If there is no local cache and the remote timestamp is empty, downloading the timestamp // fails with a store.ErrMetaNotFound func TestDownloadTimestampNoLocalTimestampRemoteTimestampEmpty(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(map[string][]byte{data.CanonicalTimestampRole: {}}) client := NewClient(repo, remoteStorage, localStorage) err = client.downloadTimestamp() assert.Error(t, err) assert.IsType(t, &json.SyntaxError{}, err) }
// If there is no local cache and also no remote timestamp, downloading the timestamp // fails with a store.ErrMetaNotFound func TestDownloadTimestampNoTimestamps(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) err = client.downloadTimestamp() assert.Error(t, err) notFoundErr, ok := err.(store.ErrMetaNotFound) assert.True(t, ok) assert.Equal(t, data.CanonicalTimestampRole, notFoundErr.Resource) }
func TestDownloadTargetChecksumMismatch(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := testutils.NewCorruptingMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // create and "upload" sample targets signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) origSha256 := sha256.Sum256(orig) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // create local snapshot with targets file snap := data.SignedSnapshot{ Signed: data.Snapshot{ Meta: data.Files{ "targets": data.FileMeta{ Length: int64(len(orig)), Hashes: data.Hashes{ "sha256": origSha256[:], }, }, }, }, } repo.Snapshot = &snap err = client.downloadTargets("targets") assert.IsType(t, ErrChecksumMismatch{}, err) }
func TestChecksumMatch(t *testing.T) { repo := tuf.NewRepo(nil, nil) localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, nil, localStorage) sampleTargets := data.NewTargets() orig, err := json.Marshal(sampleTargets) origSha256 := sha256.Sum256(orig) assert.NoError(t, err) remoteStorage.SetMeta("targets", orig) _, _, err = client.downloadSigned("targets", int64(len(orig)), origSha256[:]) assert.NoError(t, err) }
func TestDownloadTimestampHappy(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample timestamp signedOrig, err := repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("timestamp", orig) assert.NoError(t, err) err = client.downloadTimestamp() assert.NoError(t, err) }
// If there is is a local cache and no remote timestamp, we fall back on the cached timestamp func TestDownloadTimestampLocalTimestampNoRemoteTimestamp(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) // add a timestamp to the local cache tsSigned, err := repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) ts, err := json.Marshal(tsSigned) assert.NoError(t, err) localStorage := store.NewMemoryStore(map[string][]byte{data.CanonicalTimestampRole: ts}) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) err = client.downloadTimestamp() assert.NoError(t, err) }
// If there is no local cache and the remote timestamp is invalid, downloading the timestamp // fails with a store.ErrMetaNotFound func TestDownloadTimestampNoLocalTimestampRemoteTimestampInvalid(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) // add a timestamp to the remote cache tsSigned, err := repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) tsSigned.Signatures[0].Signature = []byte("12345") // invalidate the signature ts, err := json.Marshal(tsSigned) assert.NoError(t, err) remoteStorage := store.NewMemoryStore(map[string][]byte{data.CanonicalTimestampRole: ts}) client := NewClient(repo, remoteStorage, localStorage) err = client.downloadTimestamp() assert.Error(t, err) assert.IsType(t, signed.ErrRoleThreshold{}, err) }
func TestDownloadSnapshotNoChecksum(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) delete(repo.Timestamp.Signed.Meta["snapshot"].Hashes, "sha256") err = client.downloadSnapshot() assert.IsType(t, ErrMissingMeta{}, err) }
// TestDownloadTargetsNoSnapshot: it's never valid to download any targets // role (incl. delegations) when a checksum is not available. func TestDownloadTargetsNoSnapshot(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample targets signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) repo.Snapshot = nil err = client.downloadTargets("targets") assert.IsType(t, ErrMissingMeta{}, err) }
func TestDownloadTargetsHappy(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // call repo.SignSnapshot to update the targets role in the snapshot repo.SignSnapshot(data.DefaultExpires("snapshot")) err = client.downloadTargets("targets") assert.NoError(t, err) }
func TestUpdateDownloadRootHappy(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample root, snapshot, and timestamp signedOrig, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("root", orig) assert.NoError(t, err) // sign snapshot to make root meta in snapshot get updated signedOrig, err = repo.SignSnapshot(data.DefaultExpires("snapshot")) err = client.downloadRoot() assert.NoError(t, err) }
func TestBootstrapDownloadRootHappy(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample root signedOrig, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("root", orig) assert.NoError(t, err) // unset snapshot as if we're bootstrapping from nothing repo.Snapshot = nil err = client.downloadRoot() assert.NoError(t, err) }
// TestDownloadTargetsNoChecksum: it's never valid to download any targets // role (incl. delegations) when a checksum is not available. func TestDownloadTargetsNoChecksum(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // create and "upload" sample targets signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) delete(repo.Snapshot.Signed.Meta["targets"].Hashes, "sha256") err = client.downloadTargets("targets") assert.IsType(t, data.ErrMissingMeta{}, err) }
// TestDownloadTargetsLarge: Check that we can download very large targets metadata files, // which may be caused by adding a large number of targets. // This test is slow, so it will not run in short mode. func TestDownloadTargetsLarge(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) hash := sha256.Sum256([]byte{}) f := data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } // Add a ton of target files to the targets role to make this targets metadata huge // 75,000 targets results in > 5MB (~6.5MB on recent runs) for i := 0; i < 75000; i++ { _, err = repo.AddTargets(data.CanonicalTargetsRole, data.Files{strconv.Itoa(i): f}) assert.NoError(t, err) } signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // call repo.SignSnapshot to update the targets role in the snapshot repo.SignSnapshot(data.DefaultExpires("snapshot")) // Clear the cache to force an online download client.cache.RemoveAll() err = client.downloadTargets("targets") assert.NoError(t, err) }
func TestSizeMismatchShort(t *testing.T) { repo := tuf.NewRepo(nil, nil) localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, nil, localStorage) sampleTargets := data.NewTargets() orig, err := json.Marshal(sampleTargets) origSha256 := sha256.Sum256(orig) assert.NoError(t, err) l := int64(len(orig)) orig = orig[1:] remoteStorage.SetMeta("targets", orig) _, _, err = client.downloadSigned("targets", l, origSha256[:]) // size just limits the data received, the error is caught // either during checksum verification or during json deserialization assert.IsType(t, ErrChecksumMismatch{}, err) }
// TestDownloadSnapshotLarge: Check that we can download very large snapshot metadata files, // which may be caused by adding a large number of delegations. // This test is slow, so it will not run in short mode. func TestDownloadSnapshotLarge(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // Add a ton of empty delegation roles to targets to make snapshot data huge // This can also be done by adding legitimate delegations but it will be much slower // 75,000 delegation roles results in > 5MB (~7.3MB on recent runs) for i := 0; i < 75000; i++ { newRole := &data.SignedTargets{} repo.Targets[fmt.Sprintf("targets/%d", i)] = newRole } // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) signedOrig, err = repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) orig, err = json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("timestamp", orig) assert.NoError(t, err) // Clear the cache to force an online download client.cache.RemoveAll() err = client.downloadSnapshot() assert.NoError(t, err) }
// TargetMeta returns the file metadata for a file path in the role subtree, // if it exists. It also returns the role in that subtree in which the target // was found. If the path doesn't exist in that role subtree, returns // nil and an empty string. func TestTargetMeta(t *testing.T) { kdb, repo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) client := NewClient(repo, nil, kdb, localStorage) delegations := []string{ "targets/level1", "targets/level1/a", "targets/level1/a/i", } k, err := cs.Create("", data.ED25519Key) assert.NoError(t, err) hash := sha256.Sum256([]byte{}) f := data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } for i, r := range delegations { // create role role, err := data.NewRole(r, 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) // add role to repo repo.UpdateDelegations(role, []data.PublicKey{k}) repo.InitTargets(r) // add a target to the role _, err = repo.AddTargets(r, data.Files{strconv.Itoa(i): f}) assert.NoError(t, err) } // returns the right level fileMeta, role := client.TargetMeta("targets", "1") assert.Equal(t, &f, fileMeta) assert.Equal(t, "targets/level1/a", role) // looks only in subtree fileMeta, role = client.TargetMeta("targets/level1/a", "0") assert.Nil(t, fileMeta) assert.Equal(t, "", role) fileMeta, role = client.TargetMeta("targets/level1/a", "2") assert.Equal(t, &f, fileMeta) assert.Equal(t, "targets/level1/a/i", role) }
func TestUpdateDownloadRootBadChecksum(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // sign snapshot to make sure we have a checksum for root _, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) // create and "upload" sample root, snapshot, and timestamp signedOrig, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("root", orig) assert.NoError(t, err) // don't sign snapshot again to ensure checksum is out of date (bad) err = client.downloadRoot() assert.IsType(t, ErrChecksumMismatch{}, err) }
func TestDownloadSnapshotBadChecksum(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // sign timestamp to ensure it has a checksum for snapshot _, err := repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) // by not signing timestamp again we ensure it has the wrong checksum err = client.downloadSnapshot() assert.IsType(t, ErrChecksumMismatch{}, err) }
func TestDownloadTargetChecksumMismatch(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample targets signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) origSha256 := sha256.Sum256(orig) orig[0] = '}' // corrupt data, should be a { err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // create local snapshot with targets file // It's necessary to do it this way rather than calling repo.SignSnapshot // so that we have the wrong sha256 in the snapshot. snap := data.SignedSnapshot{ Signed: data.Snapshot{ Meta: data.Files{ "targets": data.FileMeta{ Length: int64(len(orig)), Hashes: data.Hashes{ "sha256": origSha256[:], }, }, }, }, } repo.Snapshot = &snap err = client.downloadTargets("targets") assert.IsType(t, ErrChecksumMismatch{}, err) }
// NewMetadataSwizzler returns a new swizzler when given a gun, // mapping of roles to initial metadata bytes, and a cryptoservice func NewMetadataSwizzler(gun string, initialMetadata map[string][]byte, cryptoService signed.CryptoService) *MetadataSwizzler { var roles []string for roleName := range initialMetadata { roles = append(roles, roleName) } return &MetadataSwizzler{ Gun: gun, MetadataCache: store.NewMemoryStore(initialMetadata), CryptoService: cryptoService, Roles: roles, } }
func TestUpdateDownloadRootChecksumNotFound(t *testing.T) { remoteStore := store.NewMemoryStore(nil) repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStore, localStorage) // sign snapshot to make sure we have current checksum for root _, err = repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) // sign and "upload" sample root signedOrig, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStore.SetMeta("root", orig) assert.NoError(t, err) // don't sign snapshot again to ensure checksum is out of date (bad) err = client.downloadRoot() assert.IsType(t, store.ErrMetaNotFound{}, err) }
// Update can succeed even if we cannot write any metadata to the repo (assuming // no data in the repo) func TestUpdateSucceedsEvenIfCannotWriteNewRepo(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } serverMeta, _, err := testutils.NewRepoMetadata("docker.com/notary", metadataDelegations...) require.NoError(t, err) ts := readOnlyServer(t, store.NewMemoryStore(serverMeta), http.StatusNotFound, "docker.com/notary") defer ts.Close() for role := range serverMeta { repo := newBlankRepo(t, ts.URL) repo.fileStore = &unwritableStore{MetadataStore: repo.fileStore, roleToNotWrite: role} _, err := repo.Update(false) if role == data.CanonicalRootRole { require.Error(t, err) // because checkRoot loads root from cache to check hashes continue } else { require.NoError(t, err) } for r, expected := range serverMeta { actual, err := repo.fileStore.GetMeta(r, -1) if r == role { require.Error(t, err) require.IsType(t, store.ErrMetaNotFound{}, err, "expected no data because unable to write for %s", role) } else { require.NoError(t, err, "problem getting repo metadata for %s", r) require.True(t, bytes.Equal(expected, actual), "%s: expected to update since only %s was unwritable", r, role) } } os.RemoveAll(repo.baseDir) } }
func TestUpdateDownloadRootBadChecksum(t *testing.T) { remoteStore := testutils.NewCorruptingMemoryStore(nil) kdb, repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStore, kdb, localStorage) // sign and "upload" sample root signedOrig, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStore.SetMeta("root", orig) assert.NoError(t, err) // sign snapshot to make sure we have current checksum for root _, err = repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) err = client.downloadRoot() assert.IsType(t, ErrChecksumMismatch{}, err) }
// If a repo has corrupt metadata (in that the hash doesn't match the snapshot) or // missing metadata, an update will replace all of it func TestUpdateReplacesCorruptOrMissingMetadata(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } serverMeta, cs, err := testutils.NewRepoMetadata("docker.com/notary", metadataDelegations...) require.NoError(t, err) ts := readOnlyServer(t, store.NewMemoryStore(serverMeta), http.StatusNotFound, "docker.com/notary") defer ts.Close() repo := newBlankRepo(t, ts.URL) defer os.RemoveAll(repo.baseDir) _, err = repo.Update(false) // ensure we have all metadata to start with require.NoError(t, err) // we want to swizzle the local cache, not the server, so create a new one repoSwizzler := testutils.NewMetadataSwizzler("docker.com/notary", serverMeta, cs) repoSwizzler.MetadataCache = repo.fileStore for _, role := range repoSwizzler.Roles { for _, expt := range waysToMessUpLocalMetadata { text, messItUp := expt.desc, expt.swizzle for _, forWrite := range []bool{true, false} { require.NoError(t, messItUp(repoSwizzler, role), "could not fuzz %s (%s)", role, text) _, err := repo.Update(forWrite) require.NoError(t, err) for r, expected := range serverMeta { actual, err := repo.fileStore.GetMeta(r, -1) require.NoError(t, err, "problem getting repo metadata for %s", role) require.True(t, bytes.Equal(expected, actual), "%s for %s: expected to recover after update", text, role) } } } } }
func TestCheckRootExpired(t *testing.T) { repo := tuf.NewRepo(nil, nil) storage := store.NewMemoryStore(nil, nil) client := NewClient(repo, storage, nil, storage) root := &data.SignedRoot{} root.Signed.Expires = time.Now().AddDate(-1, 0, 0) signedRoot, err := root.ToSigned() assert.NoError(t, err) rootJSON, err := json.Marshal(signedRoot) assert.NoError(t, err) rootHash := sha256.Sum256(rootJSON) testSnap := &data.SignedSnapshot{ Signed: data.Snapshot{ Meta: map[string]data.FileMeta{ "root": { Length: int64(len(rootJSON)), Hashes: map[string][]byte{ "sha256": rootHash[:], }, }, }, }, } repo.SetRoot(root) repo.SetSnapshot(testSnap) storage.SetMeta("root", rootJSON) err = client.checkRoot() assert.Error(t, err) assert.IsType(t, tuf.ErrLocalRootExpired{}, err) }
func TestDownloadTargetsDeepHappy(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) delegations := []string{ // left subtree "targets/level1", "targets/level1/a", "targets/level1/a/i", "targets/level1/a/ii", "targets/level1/a/iii", // right subtree "targets/level2", "targets/level2/b", "targets/level2/b/i", "targets/level2/b/i/0", "targets/level2/b/i/1", } for _, r := range delegations { // create role k, err := cs.Create(r, data.ED25519Key) assert.NoError(t, err) // add role to repo err = repo.UpdateDelegationKeys(r, []data.PublicKey{k}, []string{}, 1) assert.NoError(t, err) err = repo.UpdateDelegationPaths(r, []string{""}, []string{}, false) assert.NoError(t, err) repo.InitTargets(r) } // can only sign after adding all delegations for _, r := range delegations { // serialize and store role signedOrig, err := repo.SignTargets(r, data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta(r, orig) assert.NoError(t, err) } // serialize and store targets after adding all delegations signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // call repo.SignSnapshot to update the targets role in the snapshot repo.SignSnapshot(data.DefaultExpires("snapshot")) delete(repo.Targets, "targets") for _, r := range delegations { delete(repo.Targets, r) _, ok := repo.Targets[r] assert.False(t, ok) } err = client.downloadTargets("targets") assert.NoError(t, err) _, ok := repo.Targets["targets"] assert.True(t, ok) for _, r := range delegations { _, ok = repo.Targets[r] assert.True(t, ok) } }