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  }