func Test0Dot3Migration(t *testing.T) { // make a temporary directory and copy the fixture into it, since updating // and publishing will modify the files tmpDir, err := ioutil.TempDir("", "notary-backwards-compat-test") defer os.RemoveAll(tmpDir) require.NoError(t, err) require.NoError(t, recursiveCopy("../fixtures/compatibility/notary0.3", tmpDir)) gun := "docker.com/notary0.3/samplerepo" passwd := "randompass" ts := fullTestServer(t) defer ts.Close() _, err = NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) // check that root_keys and tuf_keys are gone and that all corect keys are present and have the correct headers files, _ := ioutil.ReadDir(filepath.Join(tmpDir, notary.PrivDir)) require.Equal(t, files[0].Name(), "041b64dab281324ef2b62fd2d04f4758269e120ff063b7bc78709272821a0a02.key") targKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "041b64dab281324ef2b62fd2d04f4758269e120ff063b7bc78709272821a0a02.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer targKey.Close() targBytes, _ := ioutil.ReadAll(targKey) targString := string(targBytes) require.Contains(t, targString, "gun: docker.com/notary0.3/tst") require.Contains(t, targString, "role: targets") require.Equal(t, files[1].Name(), "85559599cf3cf681ff193f432a7ca6d128182bd1cfa8ede2c70761deac8bc2dc.key") snapKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "85559599cf3cf681ff193f432a7ca6d128182bd1cfa8ede2c70761deac8bc2dc.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer snapKey.Close() snapBytes, _ := ioutil.ReadAll(snapKey) snapString := string(snapBytes) require.Contains(t, snapString, "gun: docker.com/notary0.3/tst") require.Contains(t, snapString, "role: snapshot") require.Equal(t, files[2].Name(), "f4eaf871a74aa3b3a0ff95cef2455a1e4d461639f5625418e76756fc5c948690.key") rootKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "f4eaf871a74aa3b3a0ff95cef2455a1e4d461639f5625418e76756fc5c948690.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer rootKey.Close() rootBytes, _ := ioutil.ReadAll(rootKey) rootString := string(rootBytes) require.Contains(t, rootString, "role: root") require.NotContains(t, rootString, "gun") require.Equal(t, files[3].Name(), "fa842f66cac2dc898677a8660789dcff0e3b0b93b73f8952491f6493199936d3.key") delKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "fa842f66cac2dc898677a8660789dcff0e3b0b93b73f8952491f6493199936d3.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer delKey.Close() delBytes, _ := ioutil.ReadAll(delKey) delString := string(delBytes) require.Contains(t, delString, "role: targets/releases") require.NotContains(t, delString, "gun") require.Len(t, files, 4) }
// insufficient arguments produce an error before any parsing of configs happens func TestInsufficientArgumentsReturnsErrorAndPrintsUsage(t *testing.T) { tempdir, err := ioutil.TempDir("", "empty-dir") require.NoError(t, err) defer os.RemoveAll(tempdir) for _, args := range exampleValidCommands { b := new(bytes.Buffer) cmd := NewNotaryCommand() cmd.SetOutput(b) arglist := strings.Fields(args) if args == "key list" || args == "key generate rsa" { // in these case, "key" or "key generate" are valid commands, so add an arg to them instead arglist = append(arglist, "extraArg") } else { arglist = arglist[:len(arglist)-1] } invalid := strings.Join(arglist, " ") cmd.SetArgs(append( []string{"-c", filepath.Join(tempdir, "idonotexist.json"), "-d", tempdir}, arglist...)) err = cmd.Execute() require.NotContains(t, err.Error(), "error opening config file", "running `notary %s`", invalid) // it's a usage error, so the usage is printed require.Contains(t, b.String(), "Usage:", "expected usage when running `notary %s`", invalid) } }
func TestStatusUnstageAndReset(t *testing.T) { setUp(t) tempBaseDir := tempDirWithConfig(t, "{}") defer os.RemoveAll(tempBaseDir) tc := &tufCommander{ configGetter: func() (*viper.Viper, error) { v := viper.New() v.SetDefault("trust_dir", tempBaseDir) return v, nil }, } // run a reset with an empty changelist and make sure it succeeds tc.resetAll = true err := tc.tufReset(&cobra.Command{}, []string{"gun"}) require.NoError(t, err) // add some targets tc.sha256 = "88b76b34ab83a9e4d5abe3697950fb73f940aab1aa5b534f80cf9de9708942be" err = tc.tufAddByHash(&cobra.Command{}, []string{"gun", "test1", "100"}) require.NoError(t, err) tc.sha256 = "4a7c203ce63b036a1999ea74eebd307c338368eb2b32218b722de6c5fdc7f016" err = tc.tufAddByHash(&cobra.Command{}, []string{"gun", "test2", "100"}) require.NoError(t, err) tc.sha256 = "64bd0565907a6a55fc66fd828a71dbadd976fa875d0a3869f53d02eb8710ecb4" err = tc.tufAddByHash(&cobra.Command{}, []string{"gun", "test3", "100"}) require.NoError(t, err) tc.sha256 = "9d9e890af64dd0f44b8a1538ff5fa0511cc31bf1ab89f3a3522a9a581a70fad8" err = tc.tufAddByHash(&cobra.Command{}, []string{"gun", "test4", "100"}) require.NoError(t, err) out, err := runCommand(t, tempBaseDir, "status", "gun") require.NoError(t, err) require.Contains(t, out, "test1") require.Contains(t, out, "test2") require.Contains(t, out, "test3") require.Contains(t, out, "test4") _, err = runCommand(t, tempBaseDir, "reset", "gun", "-n", "-1,1,3,10") require.NoError(t, err) out, err = runCommand(t, tempBaseDir, "status", "gun") require.NoError(t, err) require.Contains(t, out, "test1") require.NotContains(t, out, "test2") require.Contains(t, out, "test3") require.NotContains(t, out, "test4") _, err = runCommand(t, tempBaseDir, "reset", "gun", "--all") require.NoError(t, err) out, err = runCommand(t, tempBaseDir, "status", "gun") require.NoError(t, err) require.NotContains(t, out, "test1") require.NotContains(t, out, "test2") require.NotContains(t, out, "test3") require.NotContains(t, out, "test4") }
// the config can provide all the TLS information necessary - the root ca file, // the tls client files - they are all relative to the directory of the config // file, and not the cwd, or absolute paths func TestConfigFileTLSCanBeRelativeToConfigOrAbsolute(t *testing.T) { // Set up server that with a self signed cert var err error // add a handler for getting the root m := &recordingMetaStore{MemStorage: *storage.NewMemStorage()} s := httptest.NewUnstartedServer(setupServerHandler(m)) s.TLS, err = tlsconfig.Server(tlsconfig.Options{ CertFile: "../../fixtures/notary-server.crt", KeyFile: "../../fixtures/notary-server.key", CAFile: "../../fixtures/root-ca.crt", ClientAuth: tls.RequireAndVerifyClientCert, }) require.NoError(t, err) s.StartTLS() defer s.Close() tempDir, err := ioutil.TempDir("", "config-test") require.NoError(t, err) defer os.RemoveAll(tempDir) configFile, err := os.Create(filepath.Join(tempDir, "config.json")) require.NoError(t, err) fmt.Fprintf(configFile, `{ "remote_server": { "url": "%s", "root_ca": "root-ca.crt", "tls_client_cert": "%s", "tls_client_key": "notary-server.key" } }`, s.URL, filepath.Join(tempDir, "notary-server.crt")) configFile.Close() // copy the certs to be relative to the config directory for _, fname := range []string{"notary-server.crt", "notary-server.key", "root-ca.crt"} { content, err := ioutil.ReadFile(filepath.Join("../../fixtures", fname)) require.NoError(t, err) require.NoError(t, ioutil.WriteFile(filepath.Join(tempDir, fname), content, 0766)) } // set a config file, so it doesn't check ~/.notary/config.json by default, // and execute a random command so that the flags are parsed cmd := NewNotaryCommand() cmd.SetArgs([]string{"-c", configFile.Name(), "-d", tempDir, "list", "repo"}) cmd.SetOutput(new(bytes.Buffer)) // eat the output err = cmd.Execute() require.Error(t, err, "there was no repository, so list should have failed") require.NotContains(t, err.Error(), "TLS", "there was no TLS error though!") // validate that we actually managed to connect and attempted to download the root though require.Len(t, m.gotten, 1) require.Equal(t, m.gotten[0], "repo.root") }
func TestAllNotNearExpiry(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) notnearexpdate := time.Now().AddDate(0, 10, 0) repo.Root.Signed.SignedCommon.Expires = notnearexpdate repo.Snapshot.Signed.SignedCommon.Expires = notnearexpdate repo.Targets["targets"].Signed.Expires = notnearexpdate _, err1 := repo.InitTargets("targets/noexp") require.NoError(t, err1) repo.Targets["targets/noexp"].Signed.Expires = notnearexpdate //Reset levels to display warnings through logrus orgLevel := log.GetLevel() log.SetLevel(log.WarnLevel) defer log.SetLevel(orgLevel) a := bytes.NewBuffer(nil) log.SetOutput(a) warnRolesNearExpiry(repo) require.NotContains(t, a.String(), "targets metadata is nearing expiry, you should re-sign the role metadata", "targets should not show near expiry") require.NotContains(t, a.String(), "targets/noexp metadata is nearing expiry, you should re-sign the role metadata", "targets/noexp should not show near expiry") require.NotContains(t, a.String(), "root is nearing expiry, you should re-sign the role metadata", "Root should not show near expiry") require.NotContains(t, a.String(), "snapshot is nearing expiry, you should re-sign the role metadata", "Snapshot should not show near expiry") require.NotContains(t, a.String(), "timestamp", "there should be no logrus warnings pertaining to timestamp") }
// Whatever TLS config is in the config file can be overridden by the command line // TLS flags, which are relative to the CWD (not the config) or absolute func TestConfigFileOverridenByCmdLineFlags(t *testing.T) { // Set up server that with a self signed cert var err error // add a handler for getting the root m := &recordingMetaStore{MemStorage: *storage.NewMemStorage()} s := httptest.NewUnstartedServer(setupServerHandler(m)) s.TLS, err = tlsconfig.Server(tlsconfig.Options{ CertFile: "../../fixtures/notary-server.crt", KeyFile: "../../fixtures/notary-server.key", CAFile: "../../fixtures/root-ca.crt", ClientAuth: tls.RequireAndVerifyClientCert, }) require.NoError(t, err) s.StartTLS() defer s.Close() tempDir := tempDirWithConfig(t, fmt.Sprintf(`{ "remote_server": { "url": "%s", "root_ca": "nope", "tls_client_cert": "nope", "tls_client_key": "nope" } }`, s.URL)) defer os.RemoveAll(tempDir) configFile := filepath.Join(tempDir, "config.json") // set a config file, so it doesn't check ~/.notary/config.json by default, // and execute a random command so that the flags are parsed cwd, err := os.Getwd() require.NoError(t, err) cmd := NewNotaryCommand() cmd.SetArgs([]string{ "-c", configFile, "-d", tempDir, "list", "repo", "--tlscacert", "../../fixtures/root-ca.crt", "--tlscert", filepath.Clean(filepath.Join(cwd, "../../fixtures/notary-server.crt")), "--tlskey", "../../fixtures/notary-server.key"}) cmd.SetOutput(new(bytes.Buffer)) // eat the output err = cmd.Execute() require.Error(t, err, "there was no repository, so list should have failed") require.NotContains(t, err.Error(), "TLS", "there was no TLS error though!") // validate that we actually managed to connect and attempted to download the root though require.Len(t, m.gotten, 1) require.Equal(t, m.gotten[0], "repo.root") }
func Test0Dot1Migration(t *testing.T) { // make a temporary directory and copy the fixture into it, since updating // and publishing will modify the files tmpDir, err := ioutil.TempDir("", "notary-backwards-compat-test") defer os.RemoveAll(tmpDir) require.NoError(t, err) require.NoError(t, recursiveCopy("../fixtures/compatibility/notary0.1", tmpDir)) gun := "docker.com/notary0.1/samplerepo" passwd := "randompass" ts := fullTestServer(t) defer ts.Close() _, err = NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{}) require.NoError(t, err, "error creating repo: %s", err) // check that root_keys and tuf_keys are gone and that all corect keys are present and have the correct headers files, _ := ioutil.ReadDir(filepath.Join(tmpDir, notary.PrivDir)) require.Equal(t, files[0].Name(), "7fc757801b9bab4ec9e35bfe7a6b61668ff6f4c81b5632af19e6c728ab799599.key") targKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "7fc757801b9bab4ec9e35bfe7a6b61668ff6f4c81b5632af19e6c728ab799599.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer targKey.Close() targBytes, _ := ioutil.ReadAll(targKey) targString := string(targBytes) require.Contains(t, targString, "gun: docker.com/notary0.1/samplerepo") require.Contains(t, targString, "role: targets") require.Equal(t, files[1].Name(), "a55ccf652b0be4b6c4d356cbb02d9ea432bb84a2571665be3df7c7396af8e8b8.key") snapKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "a55ccf652b0be4b6c4d356cbb02d9ea432bb84a2571665be3df7c7396af8e8b8.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer snapKey.Close() snapBytes, _ := ioutil.ReadAll(snapKey) snapString := string(snapBytes) require.Contains(t, snapString, "gun: docker.com/notary0.1/samplerepo") require.Contains(t, snapString, "role: snapshot") require.Equal(t, files[2].Name(), "d0c623c8e70c70d42a8a8125c44a8598588b3f6e31d5c21a83cbc338dfde8a68.key") rootKey, err := os.OpenFile(filepath.Join(tmpDir, notary.PrivDir, "d0c623c8e70c70d42a8a8125c44a8598588b3f6e31d5c21a83cbc338dfde8a68.key"), os.O_RDONLY, notary.PrivExecPerms) require.NoError(t, err) defer rootKey.Close() rootBytes, _ := ioutil.ReadAll(rootKey) rootString := string(rootBytes) require.Contains(t, rootString, "role: root") require.NotContains(t, rootString, "gun") require.Len(t, files, 3) }
func TestBuilderBridgeSAM(t *testing.T) { DownloadCoresAndToolsAndLibraries(t) ctx := &types.Context{ HardwareFolders: []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"}, ToolsFolders: []string{"downloaded_tools"}, BuiltInLibrariesFolders: []string{"downloaded_libraries"}, OtherLibrariesFolders: []string{"libraries"}, SketchLocation: filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino"), FQBN: "arduino:sam:arduino_due_x_dbg", ArduinoAPIVersion: "10600", } buildPath := SetupBuildPath(t, ctx) defer os.RemoveAll(buildPath) ctx.WarningsLevel = "all" command := builder.Builder{} err := command.Run(ctx) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "syscalls_sam3.c.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "USB", "PluggableUSB.cpp.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "avr", "dtostrf.c.d")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "Bridge.ino.cpp.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, "Bridge.ino.elf")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, "Bridge.ino.bin")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "Bridge", "Mailbox.cpp.o")) NoError(t, err) cmd := exec.Command(filepath.Join("downloaded_tools", "arm-none-eabi-gcc", "4.8.3-2014q1", "bin", "arm-none-eabi-objdump"), "-f", filepath.Join(buildPath, constants.FOLDER_CORE, "core.a")) bytes, err := cmd.CombinedOutput() NoError(t, err) require.NotContains(t, string(bytes), "variant.cpp.o") }
func TestBuilderBridgeSAM(t *testing.T) { DownloadCoresAndToolsAndLibraries(t) context := make(map[string]interface{}) buildPath := SetupBuildPath(t, context) defer os.RemoveAll(buildPath) context[constants.CTX_HARDWARE_FOLDERS] = []string{filepath.Join("..", "hardware"), "hardware", "downloaded_hardware"} context[constants.CTX_TOOLS_FOLDERS] = []string{"downloaded_tools"} context[constants.CTX_FQBN] = "arduino:sam:arduino_due_x_dbg" context[constants.CTX_SKETCH_LOCATION] = filepath.Join("downloaded_libraries", "Bridge", "examples", "Bridge", "Bridge.ino") context[constants.CTX_BUILT_IN_LIBRARIES_FOLDERS] = []string{"downloaded_libraries"} context[constants.CTX_OTHER_LIBRARIES_FOLDERS] = []string{"libraries"} context[constants.CTX_BUILD_PROPERTIES_RUNTIME_IDE_VERSION] = "10600" context[constants.CTX_WARNINGS_LEVEL] = "all" command := builder.Builder{} err := command.Run(context) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "syscalls_sam3.c.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "USB", "PluggableUSB.cpp.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_CORE, "avr", "dtostrf.c.d")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_PREPROC, constants.FILE_CTAGS_TARGET_FOR_GCC_MINUS_E)) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_SKETCH, "Bridge.ino.cpp.o")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, "Bridge.ino.elf")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, "Bridge.ino.bin")) NoError(t, err) _, err = os.Stat(filepath.Join(buildPath, constants.FOLDER_LIBRARIES, "Bridge", "Mailbox.cpp.o")) NoError(t, err) cmd := exec.Command(filepath.Join("downloaded_tools", "arm-none-eabi-gcc", "4.8.3-2014q1", "bin", "arm-none-eabi-objdump"), "-f", filepath.Join(buildPath, constants.FOLDER_CORE, "core.a")) bytes, err := cmd.CombinedOutput() NoError(t, err) require.NotContains(t, string(bytes), "variant.cpp.o") }
// config parsing bugs are propagated in all commands func TestConfigParsingErrorsPropagatedByCommands(t *testing.T) { tempdir, err := ioutil.TempDir("", "empty-dir") require.NoError(t, err) defer os.RemoveAll(tempdir) for _, args := range exampleValidCommands { b := new(bytes.Buffer) cmd := NewNotaryCommand() cmd.SetOutput(b) cmd.SetArgs(append( []string{"-c", filepath.Join(tempdir, "idonotexist.json"), "-d", tempdir}, strings.Fields(args)...)) err = cmd.Execute() require.Error(t, err, "expected error when running `notary %s`", args) require.Contains(t, err.Error(), "error opening config file", "running `notary %s`", args) require.NotContains(t, b.String(), "Usage:") } }
// NewRaftDEKManager creates a key if one doesn't exist func TestNewRaftDEKManager(t *testing.T) { tempDir, err := ioutil.TempDir("", "manager-new-dek-manager-") require.NoError(t, err) defer os.RemoveAll(tempDir) paths := ca.NewConfigPaths(tempDir) cert, key, err := cautils.CreateRootCertAndKey("cn") require.NoError(t, err) krw := ca.NewKeyReadWriter(paths.Node, nil, nil) require.NoError(t, krw.Write(cert, key, nil)) keyBytes, err := ioutil.ReadFile(paths.Node.Key) require.NoError(t, err) require.NotContains(t, string(keyBytes), pemHeaderRaftDEK) // headers are not written dekManager, err := NewRaftDEKManager(krw) // this should create a new DEK and write it to the file require.NoError(t, err) keyBytes, err = ioutil.ReadFile(paths.Node.Key) require.NoError(t, err) require.Contains(t, string(keyBytes), pemHeaderRaftDEK) // header is written now keys := dekManager.GetKeys() require.NotNil(t, keys.CurrentDEK) require.Nil(t, keys.PendingDEK) require.False(t, dekManager.NeedsRotation()) // If one exists, nothing is updated dekManager, err = NewRaftDEKManager(krw) // this should create a new DEK and write it to the file require.NoError(t, err) keyBytes2, err := ioutil.ReadFile(paths.Node.Key) require.NoError(t, err) require.Equal(t, keyBytes, keyBytes2) require.Equal(t, keys, dekManager.GetKeys()) require.False(t, dekManager.NeedsRotation()) }
func mustNotContain(t *testing.T, page, what string) { require.NotContains(t, page, what) }
func TestDelegationRolesParent(t *testing.T) { delgA := data.DelegationRole{ BaseRole: data.BaseRole{ Keys: nil, Name: "targets/a", Threshold: 1, }, Paths: []string{"path", "anotherpath"}, } delgB := data.DelegationRole{ BaseRole: data.BaseRole{ Keys: nil, Name: "targets/a/b", Threshold: 1, }, Paths: []string{"path/b", "anotherpath/b", "b/invalidpath"}, } // Assert direct parent relationship require.True(t, delgA.IsParentOf(delgB)) require.False(t, delgB.IsParentOf(delgA)) require.False(t, delgA.IsParentOf(delgA)) delgC := data.DelegationRole{ BaseRole: data.BaseRole{ Keys: nil, Name: "targets/a/b/c", Threshold: 1, }, Paths: []string{"path/b", "anotherpath/b/c", "c/invalidpath"}, } // Assert direct parent relationship require.True(t, delgB.IsParentOf(delgC)) require.False(t, delgB.IsParentOf(delgB)) require.False(t, delgA.IsParentOf(delgC)) require.False(t, delgC.IsParentOf(delgB)) require.False(t, delgC.IsParentOf(delgA)) require.False(t, delgC.IsParentOf(delgC)) // Check that parents correctly restrict paths restrictedDelgB, err := delgA.Restrict(delgB) require.NoError(t, err) require.Contains(t, restrictedDelgB.Paths, "path/b") require.Contains(t, restrictedDelgB.Paths, "anotherpath/b") require.NotContains(t, restrictedDelgB.Paths, "b/invalidpath") _, err = delgB.Restrict(delgA) require.Error(t, err) _, err = delgA.Restrict(delgC) require.Error(t, err) _, err = delgC.Restrict(delgB) require.Error(t, err) _, err = delgC.Restrict(delgA) require.Error(t, err) // Make delgA have no paths and check that it changes delgB and delgC accordingly when chained delgA.Paths = []string{} restrictedDelgB, err = delgA.Restrict(delgB) require.NoError(t, err) require.Empty(t, restrictedDelgB.Paths) restrictedDelgC, err := restrictedDelgB.Restrict(delgC) require.NoError(t, err) require.Empty(t, restrictedDelgC.Paths) }
// Initialize repo and test publishing targets with delegation roles func TestClientDelegationsPublishing(t *testing.T) { setUp(t) tempDir := tempDirWithConfig(t, "{}") defer os.RemoveAll(tempDir) server := setupServer() defer server.Close() // Setup certificate for delegation role tempFile, err := ioutil.TempFile("", "pemfile") require.NoError(t, err) privKey, err := trustmanager.GenerateRSAKey(rand.Reader, 2048) require.NoError(t, err) privKeyBytesNoRole, err := trustmanager.KeyToPEM(privKey, "") require.NoError(t, err) privKeyBytesWithRole, err := trustmanager.KeyToPEM(privKey, "user") require.NoError(t, err) startTime := time.Now() endTime := startTime.AddDate(10, 0, 0) cert, err := cryptoservice.GenerateCertificate(privKey, "gun", startTime, endTime) require.NoError(t, err) _, err = tempFile.Write(trustmanager.CertToPEM(cert)) require.NoError(t, err) tempFile.Close() defer os.Remove(tempFile.Name()) rawPubBytes, _ := ioutil.ReadFile(tempFile.Name()) parsedPubKey, _ := trustmanager.ParsePEMPublicKey(rawPubBytes) canonicalKeyID, err := utils.CanonicalKeyID(parsedPubKey) require.NoError(t, err) // Set up targets for publishing tempTargetFile, err := ioutil.TempFile("", "targetfile") require.NoError(t, err) tempTargetFile.Close() defer os.Remove(tempTargetFile.Name()) var target = "sdgkadga" var output string // init repo _, err = runCommand(t, tempDir, "-s", server.URL, "init", "gun") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - none yet output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "No delegations present in this repository.") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // validate that we have all keys, including snapshot assertNumKeys(t, tempDir, 1, 2, true) // rotate the snapshot key to server output, err = runCommand(t, tempDir, "-s", server.URL, "key", "rotate", "gun", "snapshot", "-r") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // validate that we lost the snapshot signing key _, signingKeyIDs := assertNumKeys(t, tempDir, 1, 1, true) targetKeyID := signingKeyIDs[0] // add new valid delegation with single new cert output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/releases", tempFile.Name(), "--paths", "\"\"") require.NoError(t, err) require.Contains(t, output, "Addition of delegation role") require.Contains(t, output, canonicalKeyID) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see our one delegation output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.NotContains(t, output, "No delegations present in this repository.") // remove the targets key to demonstrate that delegates don't need this key keyDir := filepath.Join(tempDir, "private", "tuf_keys") require.NoError(t, os.Remove(filepath.Join(keyDir, "gun", targetKeyID+".key"))) // Note that we need to use the canonical key ID, followed by the base of the role here err = ioutil.WriteFile(filepath.Join(keyDir, canonicalKeyID+"_releases.key"), privKeyBytesNoRole, 0700) require.NoError(t, err) // add a target using the delegation -- will only add to targets/releases _, err = runCommand(t, tempDir, "add", "gun", target, tempTargetFile.Name(), "--roles", "targets/releases") require.NoError(t, err) // list targets for targets/releases - we should see no targets until we publish output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "No targets") output, err = runCommand(t, tempDir, "-s", server.URL, "status", "gun") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list targets for targets/releases - we should see our target! output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "targets/releases") // remove the target for this role only _, err = runCommand(t, tempDir, "remove", "gun", target, "--roles", "targets/releases") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list targets for targets/releases - we should see no targets output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "No targets present") // Try adding a target with a different key style - private/tuf_keys/canonicalKeyID.key with "user" set as the "role" PEM header // First remove the old key and add the new style require.NoError(t, os.Remove(filepath.Join(keyDir, canonicalKeyID+"_releases.key"))) err = ioutil.WriteFile(filepath.Join(keyDir, canonicalKeyID+".key"), privKeyBytesWithRole, 0700) require.NoError(t, err) // add a target using the delegation -- will only add to targets/releases _, err = runCommand(t, tempDir, "add", "gun", target, tempTargetFile.Name(), "--roles", "targets/releases") require.NoError(t, err) // list targets for targets/releases - we should see no targets until we publish output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "No targets") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list targets for targets/releases - we should see our target! output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "targets/releases") // remove the target for this role only _, err = runCommand(t, tempDir, "remove", "gun", target, "--roles", "targets/releases") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // Now remove this key, and make a new file to import the delegation's key from require.NoError(t, os.Remove(filepath.Join(keyDir, canonicalKeyID+".key"))) tempPrivFile, err := ioutil.TempFile("/tmp", "privfile") require.NoError(t, err) defer os.Remove(tempPrivFile.Name()) // Write the private key to a file so we can import it _, err = tempPrivFile.Write(privKeyBytesNoRole) require.NoError(t, err) tempPrivFile.Close() // Import the private key, associating it with our delegation role _, err = runCommand(t, tempDir, "key", "import", tempPrivFile.Name(), "--role", "targets/releases") require.NoError(t, err) // add a target using the delegation -- will only add to targets/releases _, err = runCommand(t, tempDir, "add", "gun", target, tempTargetFile.Name(), "--roles", "targets/releases") require.NoError(t, err) // list targets for targets/releases - we should see no targets until we publish output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "No targets") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list targets for targets/releases - we should see our target! output, err = runCommand(t, tempDir, "-s", server.URL, "list", "gun", "--roles", "targets/releases") require.NoError(t, err) require.Contains(t, output, "targets/releases") }
// Initialize repo and test delegations commands by adding, listing, and removing delegations func TestClientDelegationsInteraction(t *testing.T) { setUp(t) tempDir := tempDirWithConfig(t, "{}") defer os.RemoveAll(tempDir) server := setupServer() defer server.Close() // Setup certificate tempFile, err := ioutil.TempFile("", "pemfile") require.NoError(t, err) privKey, err := trustmanager.GenerateECDSAKey(rand.Reader) startTime := time.Now() endTime := startTime.AddDate(10, 0, 0) cert, err := cryptoservice.GenerateCertificate(privKey, "gun", startTime, endTime) require.NoError(t, err) _, err = tempFile.Write(trustmanager.CertToPEM(cert)) require.NoError(t, err) tempFile.Close() defer os.Remove(tempFile.Name()) rawPubBytes, _ := ioutil.ReadFile(tempFile.Name()) parsedPubKey, _ := trustmanager.ParsePEMPublicKey(rawPubBytes) keyID, err := utils.CanonicalKeyID(parsedPubKey) require.NoError(t, err) var output string // -- tests -- // init repo _, err = runCommand(t, tempDir, "-s", server.URL, "init", "gun") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - none yet output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "No delegations present in this repository.") // add new valid delegation with single new cert, and no path output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", tempFile.Name()) require.NoError(t, err) require.Contains(t, output, "Addition of delegation role") require.Contains(t, output, keyID) require.NotContains(t, output, "path") // check status - see delegation output, err = runCommand(t, tempDir, "status", "gun") require.NoError(t, err) require.Contains(t, output, "Unpublished changes for gun") // list delegations - none yet because still unpublished output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "No delegations present in this repository.") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // check status - no changelist output, err = runCommand(t, tempDir, "status", "gun") require.NoError(t, err) require.Contains(t, output, "No unpublished changes for gun") // list delegations - we should see our added delegation, with no paths output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "targets/delegation") require.Contains(t, output, keyID) require.NotContains(t, output, "\"\"") // add all paths to this delegation output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--all-paths") require.NoError(t, err) require.Contains(t, output, "Addition of delegation role") require.Contains(t, output, "\"\"") require.Contains(t, output, "<all paths>") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see our added delegation, with no paths output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "targets/delegation") require.Contains(t, output, "\"\"") require.Contains(t, output, "<all paths>") // Setup another certificate tempFile2, err := ioutil.TempFile("", "pemfile2") require.NoError(t, err) privKey, err = trustmanager.GenerateECDSAKey(rand.Reader) startTime = time.Now() endTime = startTime.AddDate(10, 0, 0) cert, err = cryptoservice.GenerateCertificate(privKey, "gun", startTime, endTime) require.NoError(t, err) _, err = tempFile2.Write(trustmanager.CertToPEM(cert)) require.NoError(t, err) require.NoError(t, err) tempFile2.Close() defer os.Remove(tempFile2.Name()) rawPubBytes2, _ := ioutil.ReadFile(tempFile2.Name()) parsedPubKey2, _ := trustmanager.ParsePEMPublicKey(rawPubBytes2) keyID2, err := utils.CanonicalKeyID(parsedPubKey2) require.NoError(t, err) // add to the delegation by specifying the same role, this time add a scoped path output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", tempFile2.Name(), "--paths", "path") require.NoError(t, err) require.Contains(t, output, "Addition of delegation role") require.Contains(t, output, keyID2) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see two keys output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "path") require.Contains(t, output, keyID) require.Contains(t, output, keyID2) // remove the delegation's first key output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", keyID) require.NoError(t, err) require.Contains(t, output, "Removal of delegation role") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see the delegation but with only the second key output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.NotContains(t, output, keyID) require.Contains(t, output, keyID2) // remove the delegation's second key output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", keyID2) require.NoError(t, err) require.Contains(t, output, "Removal of delegation role") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see no delegations output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "No delegations present in this repository.") // add delegation with multiple certs and multiple paths output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", tempFile.Name(), tempFile2.Name(), "--paths", "path1,path2") require.NoError(t, err) require.Contains(t, output, "Addition of delegation role") require.Contains(t, output, keyID) require.Contains(t, output, keyID2) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see two keys output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "path1") require.Contains(t, output, "path2") require.Contains(t, output, keyID) require.Contains(t, output, keyID2) // add delegation with multiple certs and multiple paths output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "path3") require.NoError(t, err) require.Contains(t, output, "Addition of delegation role") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see two keys output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "path1") require.Contains(t, output, "path2") require.Contains(t, output, "path3") require.Contains(t, output, keyID) require.Contains(t, output, keyID2) // just remove two paths from this delegation output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--paths", "path2,path3") require.NoError(t, err) require.Contains(t, output, "Removal of delegation role") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see the same two keys, and only path1 output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "path1") require.NotContains(t, output, "path2") require.NotContains(t, output, "path3") require.Contains(t, output, keyID) require.Contains(t, output, keyID2) // remove the remaining path, should not remove the delegation entirely output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--paths", "path1") require.NoError(t, err) require.Contains(t, output, "Removal of delegation role") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see the same two keys, and no paths output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.NotContains(t, output, "path1") require.NotContains(t, output, "path2") require.NotContains(t, output, "path3") require.Contains(t, output, keyID) require.Contains(t, output, keyID2) // Add a bunch of individual paths so we can test a delegation remove --all-paths output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "abcdef,123456") require.NoError(t, err) // Add more individual paths so we can test a delegation remove --all-paths output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "banana/split,apple/crumble/pie,orange.peel,kiwi") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see all of our paths output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "abcdef") require.Contains(t, output, "123456") require.Contains(t, output, "banana/split") require.Contains(t, output, "apple/crumble/pie") require.Contains(t, output, "orange.peel") require.Contains(t, output, "kiwi") // Try adding "", and check that adding it with other paths clears out the others output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "\"\",grapefruit,pomegranate") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see all of our old paths, and "" output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "abcdef") require.Contains(t, output, "123456") require.Contains(t, output, "banana/split") require.Contains(t, output, "apple/crumble/pie") require.Contains(t, output, "orange.peel") require.Contains(t, output, "kiwi") require.Contains(t, output, "\"\"") require.NotContains(t, output, "grapefruit") require.NotContains(t, output, "pomegranate") // Try removing just "" output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--paths", "\"\"") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see all of our old paths without "" output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "abcdef") require.Contains(t, output, "123456") require.Contains(t, output, "banana/split") require.Contains(t, output, "apple/crumble/pie") require.Contains(t, output, "orange.peel") require.Contains(t, output, "kiwi") require.NotContains(t, output, "\"\"") // Remove --all-paths to clear out all paths from this delegation output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--all-paths") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see all of our paths output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.NotContains(t, output, "abcdef") require.NotContains(t, output, "123456") require.NotContains(t, output, "banana/split") require.NotContains(t, output, "apple/crumble/pie") require.NotContains(t, output, "orange.peel") require.NotContains(t, output, "kiwi") // Check that we ignore other --paths if we pass in --all-paths on an add output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--all-paths", "--paths", "grapefruit,pomegranate") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should only see "", and not the other paths specified output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "\"\"") require.NotContains(t, output, "grapefruit") require.NotContains(t, output, "pomegranate") // Add those extra paths we ignored to set up the next test output, err = runCommand(t, tempDir, "delegation", "add", "gun", "targets/delegation", "--paths", "grapefruit,pomegranate") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // Check that we ignore other --paths if we pass in --all-paths on a remove output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "--all-paths", "--paths", "pomegranate") require.NoError(t, err) // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see no paths output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.NotContains(t, output, "\"\"") require.NotContains(t, output, "grapefruit") require.NotContains(t, output, "pomegranate") // remove by force to delete the delegation entirely output, err = runCommand(t, tempDir, "delegation", "remove", "gun", "targets/delegation", "-y") require.NoError(t, err) require.Contains(t, output, "Forced removal (including all keys and paths) of delegation role") // publish repo _, err = runCommand(t, tempDir, "-s", server.URL, "publish", "gun") require.NoError(t, err) // list delegations - we should see no delegations output, err = runCommand(t, tempDir, "-s", server.URL, "delegation", "list", "gun") require.NoError(t, err) require.Contains(t, output, "No delegations present in this repository.") }