github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/integration/feature_flag_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "os/exec" 9 "path" 10 "reflect" 11 "regexp" 12 "runtime" 13 "testing" 14 ) 15 16 var ( 17 testApiKey1 string = os.Getenv("CNIL_GITHUB_TEST_API_KEY1") 18 testApiKey2 string = os.Getenv("CNIL_GITHUB_TEST_API_KEY2") 19 revokedKey string = os.Getenv("CNIL_GITHUB_REVOKED_KEY") 20 testHost string = os.Getenv("CNIL_GITHUB_TEST_HOST") 21 testPort string = os.Getenv("CNIL_GITHUB_TEST_PORT") 22 signerID1 string = os.Getenv("CNIL_SIGNERID1") 23 // signerID2 string = os.Getenv("CNIL_SIGNERID2") 24 revokedSigner string = os.Getenv("REVOKED_SIGNERID") 25 revokedHash string = os.Getenv("REVOKED_HASH") 26 untrustedHash string = os.Getenv("UNTRUSTED_HASH") 27 //TODO: Create a list of images and make this part of the test configuration rather than a secret 28 imageToNotarize string = os.Getenv("IMAGE_TO_NOTARIZE") 29 30 attributeRE *regexp.Regexp = regexp.MustCompile(".*test_attr_value1.*") 31 loginSuccessRe *regexp.Regexp = regexp.MustCompile("Login successful") 32 statusTrustedRE *regexp.Regexp = regexp.MustCompile("Status:.*TRUSTED") 33 statusUntrustedRE *regexp.Regexp = regexp.MustCompile("Status:.*UNTRUSTED") 34 statusRevokedRE *regexp.Regexp = regexp.MustCompile("Status:.*REVOKED") 35 notarizationsFoundRE *regexp.Regexp = regexp.MustCompile("notarizations found") 36 noSignerIdRE *regexp.Regexp = regexp.MustCompile("no signer ID provided") 37 apiKeyRevokedRE *regexp.Regexp = regexp.MustCompile("Apikey revoked") 38 recursiveNotarizationRE *regexp.Regexp = regexp.MustCompile(`notarized.*\d+.*items`) 39 badApikeyRE *regexp.Regexp = regexp.MustCompile("api key not valid") 40 logoutSuccessfulRE *regexp.Regexp = regexp.MustCompile("Logout successful") 41 logoutNotLoggedInRE *regexp.Regexp = regexp.MustCompile("No logged-in user") 42 needToLoginRE *regexp.Regexp = regexp.MustCompile("You need to be logged in") 43 cmd_str string = getCmdFqp() 44 ) 45 46 func findBinaryName() string { 47 os := runtime.GOOS 48 binaryName := "vcn" 49 switch os { 50 case "windows": 51 return binaryName + ".exe" 52 default: 53 return binaryName 54 } 55 } 56 57 func getCmdFqp() string { 58 binary := findBinaryName() 59 current_dir, err := os.Getwd() 60 if err != nil { 61 log.Printf("Error getting current directory, aborting tests") 62 os.Exit(1) 63 } 64 working_dir := path.Dir(current_dir) 65 return path.Join(working_dir, binary) 66 } 67 68 /** Tests unauthenticated interaction with blockchain backend, currently limited until google/goexpect is added to this test suite since interactive login is required **/ 69 func TestBlockchainContext(t *testing.T) { 70 tests := []struct { 71 name string 72 args []string 73 x_output *regexp.Regexp 74 }{ 75 {"Authenticate hash - Not logged in", []string{"a", "--hash", "75238fba430613c4339f06f1951b375afed0d051e9869a65d639c64b54671532"}, statusTrustedRE}, 76 } 77 os.Setenv("VCN_SKIP_SIGNATURE_VERIFY", "true") 78 for _, tt := range tests { 79 t.Run(tt.name, func(t *testing.T) { 80 cmd := exec.Command(cmd_str, tt.args...) 81 output, err := cmd.CombinedOutput() 82 if err != nil { 83 t.Fatal(err) 84 } 85 actual := string(output) 86 87 if !tt.x_output.MatchString(actual) { 88 x_string := fmt.Sprintf("Expected %s but got %s", tt.x_output, actual) 89 log.Fatal(x_string) 90 } 91 }) 92 } 93 } 94 95 type C struct{} 96 97 func (c C) Fixture_set_env_api_key() { 98 _, f := os.LookupEnv("VCN_LC_API_KEY") 99 if f { 100 os.Setenv("VCN_LC_API_KEY", testApiKey2) 101 } else { 102 os.Setenv("VCN_LC_API_KEY", testApiKey1) 103 } 104 log.Printf("API Key set to %s", os.Getenv("VCN_LC_API_KEY")) 105 106 } 107 108 func (c C) FixturePullImage() { 109 cmd := exec.Command("docker", "pull", imageToNotarize) 110 out, err := cmd.CombinedOutput() 111 cmd.Run() 112 if err != nil { 113 log.Printf("Error pulling image %s", imageToNotarize) 114 } 115 log.Println(string(out)) 116 } 117 118 type VcnTest struct { 119 // Name of the test 120 name string 121 // CLI Args 122 args []string 123 // Array of regular expressions to vaidate stdout/stderr 124 x_output []*regexp.Regexp 125 // Fixture (create func(c C) Function_name, uses reflection) 126 fixture string 127 } 128 129 func executeTests(testArray []VcnTest, t *testing.T) { 130 for _, tt := range testArray { 131 t.Run(tt.name, func(t *testing.T) { 132 if tt.fixture != "" { 133 c := C{} 134 f := reflect.ValueOf(c).MethodByName(tt.fixture) 135 f.Call(nil) 136 } 137 cmd := exec.Command(cmd_str, tt.args...) 138 out, err := cmd.CombinedOutput() 139 cmd.Run() 140 if err != nil { 141 log.Println("Logging stdErr, tests may still pass") 142 log.Println(fmt.Sprint(err) + ": " + string(out)) 143 } 144 actual := string(out) 145 for _, regex := range tt.x_output { 146 if !regex.MatchString(actual) { 147 t.Log(fmt.Sprintf("Test %s failed", tt.name)) 148 x_string := fmt.Sprintf("Expected %s but got %s", tt.x_output, actual) 149 log.Fatal(x_string) 150 } 151 } 152 153 }) 154 } 155 156 } 157 158 /** Tests authenticated interaction with CNIL backend**/ 159 func TestCNcloudContext(t *testing.T) { 160 var tests = []VcnTest{ 161 {"Login to private test instance", []string{"login", "--lc-host", testHost, "--lc-port", testPort, "--lc-api-key", testApiKey1}, []*regexp.Regexp{loginSuccessRe}, "Fixture_set_env_api_key"}, 162 {"Notarize a simple file", []string{"n", "feature_flag_test.go"}, []*regexp.Regexp{statusTrustedRE}, ""}, 163 {"Authenticate a previously notarized file", []string{"a", "feature_flag_test.go"}, []*regexp.Regexp{statusTrustedRE}, ""}, 164 {"Untrust a previously notarized file", []string{"untrust", "feature_flag_test.go"}, []*regexp.Regexp{statusUntrustedRE}, ""}, 165 {"Authenticate a previously untrusted file", []string{"a", "feature_flag_test.go"}, []*regexp.Regexp{statusUntrustedRE}, ""}, 166 {"Inspect a previously untrusted file using a date range", []string{"i", "feature_flag_test.go", "--start", "2021/08/25-00:00:00", "--end", "2021/08/25-23:59:00", "--first", "10"}, []*regexp.Regexp{notarizationsFoundRE}, ""}, 167 {"Inspect a previously untrusted file (No Args)", []string{"inspect", "feature_flag_test.go"}, []*regexp.Regexp{noSignerIdRE}, ""}, 168 {"Inspect a previously untrusted file --first flag", []string{"inspect", "feature_flag_test.go", "--first", "1"}, []*regexp.Regexp{notarizationsFoundRE}, ""}, 169 {"Inspect a previously untrusted file --last flag", []string{"inspect", "feature_flag_test.go", "--last", "1"}, []*regexp.Regexp{notarizationsFoundRE}, ""}, 170 {"Inspect a previously untrusted file hash flag", []string{"inspect", "--hash", untrustedHash, "--signerID", signerID1}, []*regexp.Regexp{notarizationsFoundRE}, ""}, 171 {"Notarize a file with specific attributes", []string{"n", "--attr", "test_attr1=test_attr_value1", "feature_flag_test.go"}, []*regexp.Regexp{attributeRE}, ""}, 172 {"Authenticate with previous signerId", []string{"a", "feature_flag_test.go", "--signerID", signerID1}, []*regexp.Regexp{statusTrustedRE}, "Fixture_set_env_api_key"}, 173 {"Authenticate with a revoked signerId", []string{"a", "--hash", revokedHash, "--signerID", revokedSigner}, []*regexp.Regexp{apiKeyRevokedRE, statusRevokedRE}, ""}, 174 {"Notarize recursively", []string{"n", "-r", "*.go"}, []*regexp.Regexp{recursiveNotarizationRE}, ""}, 175 {"Notarize docker image", []string{"n", fmt.Sprintf("docker://%s", imageToNotarize)}, []*regexp.Regexp{statusTrustedRE}, "FixturePullImage"}, 176 {"Notarize git repo ", []string{"n", "git://../"}, []*regexp.Regexp{statusTrustedRE}, ""}, 177 {"Notarize git repo BOM", []string{"n", "--bom", "git://../"}, []*regexp.Regexp{statusTrustedRE}, ""}, 178 {"Attempt to notarize using revoked API Key", []string{"n", "git://../", "--lc-api-key", revokedKey}, []*regexp.Regexp{badApikeyRE}, ""}, 179 {"Attempt to notarize using an invalid API Key", []string{"n", "git://../", "--lc-api-key", "lc._"}, []*regexp.Regexp{badApikeyRE}, ""}, 180 {"Logout", []string{"logout"}, []*regexp.Regexp{logoutSuccessfulRE}, ""}, 181 {"Logout without logging in", []string{"logout"}, []*regexp.Regexp{logoutNotLoggedInRE}, ""}, 182 {"Attempt to notarize after logging out", []string{"n", "git://../", "--lc-api-key", "lc._"}, []*regexp.Regexp{needToLoginRE}, ""}, 183 } 184 os.Setenv("VCN_SKIP_SIGNATURE_VERIFY", "true") 185 executeTests(tests, t) 186 } 187 188 func TestBomUnsupported(t *testing.T) { 189 // Negative tests still can't use the above illustrated method 190 pckManErrorRE := *regexp.MustCompile(`.*cannot identify package manager.*`) 191 c := C{} 192 c.FixturePullImage() 193 cmd := exec.Command(cmd_str, "bom", fmt.Sprintf("docker://%s", imageToNotarize)) 194 out, err := cmd.CombinedOutput() 195 cmd.Run() 196 log.Println(err) 197 if err != nil { 198 // We want to be here 199 if !pckManErrorRE.MatchString(string(out)) { 200 t.Fatal("Package manager error not found") 201 } 202 } else { 203 t.Fatal("Unsupported docker image generated no errors") 204 } 205 } 206 207 func TestBomSupportedDockerImage(t *testing.T) { 208 exec.Command("docker", "pull", "codenotary/vcn:bom-nodejs").Run() 209 var tests = []VcnTest{ 210 {"Run vcn bom on a supported docker image", []string{"bom", "docker://codenotary/vcn:bom-nodejs"}, []*regexp.Regexp{regexp.MustCompile(`.*ca-certificates.*`), regexp.MustCompile(`.*openssl.*`)}, ""}, 211 } 212 executeTests(tests, t) 213 214 } 215 216 func TestBomSpdxFile(t *testing.T) { 217 var vcnBomFiles = []string{"vcn-bom.spdx", "git-bom.spdx", "docker-bom.spdx"} 218 var tests = []VcnTest{ 219 {"Run vcn bom --spdx-file some_file on VCN Binary", []string{"bom", cmd_str, "--bom-spdx", vcnBomFiles[0]}, []*regexp.Regexp{regexp.MustCompile(`.*github.com/prometheus/common*`), regexp.MustCompile(`.*github.com/package-url/packageurl-go*`), regexp.MustCompile(`.*github.com/matttproud/golang_protobuf_extensions*`)}, ""}, 220 {"Run vcn bom --spdx-file this-repository", []string{"bom", "git://../", "--bom-spdx", vcnBomFiles[1]}, []*regexp.Regexp{regexp.MustCompile(`.*github.com/prometheus/common*`), regexp.MustCompile(`.*github.com/package-url/packageurl-go*`), regexp.MustCompile(`.*github.com/matttproud/golang_protobuf_extensions*`)}, ""}, 221 } 222 executeTests(tests, t) 223 spdxContent, err := ioutil.ReadFile(vcnBomFiles[0]) 224 spdxString := string(spdxContent) 225 if err != nil { 226 t.Fatal("failed to read spdx file contents") 227 } 228 for _, regex := range tests[0].x_output { 229 if !regex.MatchString(spdxString) { 230 t.Fatal(fmt.Sprintf("Dependency %s missing from bom-spdx output for vcn", regex)) 231 } 232 } 233 } 234 235 func TestBomWhatIncludes(t *testing.T) { 236 vcnDependency := "gocom://github.com/spf13/viper@v1.8.1" 237 var tests = []VcnTest{ 238 // Login required for this 239 {"Login to private test instance", []string{"login", "--lc-host", testHost, "--lc-port", testPort, "--lc-api-key", testApiKey1}, []*regexp.Regexp{loginSuccessRe}, ""}, 240 {"Run vcn a git://../ --bom-what-includes some_dependency", []string{"a", "--bom-what-includes", vcnDependency}, []*regexp.Regexp{regexp.MustCompile(`.*git@github.com:codenotary/vcn.git*`)}, ""}, 241 } 242 executeTests(tests, t) 243 }