github.com/StackExchange/blackbox/v2@v2.0.1-0.20220331193400-d84e904973ab/integrationTest/integration_test.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/StackExchange/blackbox/v2/pkg/bblog"
    12  	_ "github.com/StackExchange/blackbox/v2/pkg/bblog"
    13  	_ "github.com/StackExchange/blackbox/v2/pkg/vcs/_all"
    14  )
    15  
    16  var vcsToTest = flag.String("testvcs", "GIT", "VCS to test")
    17  var longTests = flag.Bool("long", false, "Run long version of tests")
    18  
    19  //var crypterToTest = flag.String("crypter", "GnuPG", "crypter to test")
    20  
    21  func init() {
    22  	testing.Init()
    23  	flag.Parse()
    24  
    25  	op, err := os.Getwd()
    26  	if err != nil {
    27  		panic(err)
    28  	}
    29  	originPath = op
    30  }
    31  
    32  func compile(t *testing.T) {
    33  	if PathToBlackBox() != "" {
    34  		// It's been compiled already.
    35  		return
    36  	}
    37  	// Make sure we have the latest binary
    38  	fmt.Println("========== Compiling")
    39  	cmd := exec.Command("go", "build", "-o", "../bbintegration", "../cmd/blackbox")
    40  	cmd.Stdout = os.Stdout
    41  	cmd.Stderr = os.Stderr
    42  	err := cmd.Run()
    43  	if err != nil {
    44  		t.Fatalf("setup_compile: %v", err)
    45  	}
    46  	cwd, err := os.Getwd()
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	SetPathToBlackBox(filepath.Join(cwd, "../bbintegration"))
    51  }
    52  
    53  func setup(t *testing.T) {
    54  	logDebug := bblog.GetDebug(*verbose)
    55  
    56  	logDebug.Printf("flag.testvcs is %v", *vcsToTest)
    57  	vh := getVcs(t, *vcsToTest)
    58  	logDebug.Printf("Using BLACKBOX_VCS=%v", vh.Name())
    59  	os.Setenv("BLACKBOX_VCS", vh.Name())
    60  
    61  }
    62  
    63  func TestInit(t *testing.T) {
    64  	if !*longTests {
    65  		return
    66  	}
    67  	compile(t)
    68  	makeHomeDir(t, "init")
    69  
    70  	// Only zero or one args are permitted.
    71  	invalidArgs(t, "init", "one", "two")
    72  	invalidArgs(t, "init", "one", "two", "three")
    73  
    74  	runBB(t, "init", "yes")
    75  	assertFileEmpty(t, ".blackbox/blackbox-admins.txt")
    76  	assertFileEmpty(t, ".blackbox/blackbox-files.txt")
    77  	assertFilePerms(t, ".blackbox/blackbox-admins.txt", 0o640)
    78  	assertFilePerms(t, ".blackbox/blackbox-files.txt", 0o640)
    79  }
    80  
    81  func TestList(t *testing.T) {
    82  	if !*longTests {
    83  		return
    84  	}
    85  	compile(t)
    86  	makeHomeDir(t, "init")
    87  
    88  	runBB(t, "init", "yes")
    89  	createDummyFilesAdmin(t)
    90  	checkOutput("000-admin-list.txt", t, "admin", "list")
    91  	checkOutput("000-file-list.txt", t, "file", "list")
    92  
    93  	invalidArgs(t, "file", "list", "extra")
    94  	invalidArgs(t, "admin", "list", "extra")
    95  }
    96  
    97  func TestStatus(t *testing.T) {
    98  	if !*longTests {
    99  		return
   100  	}
   101  	compile(t)
   102  	makeHomeDir(t, "init")
   103  
   104  	runBB(t, "init", "yes")
   105  	createFilesStatus(t)
   106  	checkOutput("000-status.txt", t, "status")
   107  }
   108  
   109  func TestShred(t *testing.T) {
   110  	if !*longTests {
   111  		return
   112  	}
   113  	compile(t)
   114  	makeHomeDir(t, "shred")
   115  	runBB(t, "init", "yes")
   116  
   117  	makeFile(t, "shredme.txt", "File with SHREDME in it.\n")
   118  	assertFileExists(t, "shredme.txt")
   119  	runBB(t, "shred", "shredme.txt")
   120  	assertFileMissing(t, "shredme.txt")
   121  }
   122  
   123  func TestStatus_notreg(t *testing.T) {
   124  	if !*longTests {
   125  		return
   126  	}
   127  	compile(t)
   128  	makeHomeDir(t, "init")
   129  
   130  	runBB(t, "init", "yes")
   131  	createFilesStatus(t)
   132  	checkOutput("status-noreg.txt", t, "status", "status-ENCRYPTED.txt", "blah.txt")
   133  }
   134  
   135  // TestHard tests the functions using a fake homedir and repo.
   136  func TestHard(t *testing.T) {
   137  	if !*longTests {
   138  		return
   139  	}
   140  	// These are basic tests that work on a fake repo.
   141  	// The repo has mostly real data, except any .gpg file
   142  	// is just garbage.
   143  	compile(t)
   144  	setup(t)
   145  
   146  	for _, cx := range []struct{ subname, prefix string }{
   147  		//{subname: ".", prefix: "."},
   148  		{subname: "mysub", prefix: ".."},
   149  	} {
   150  		subname := cx.subname
   151  		prefix := cx.prefix
   152  		_ = prefix
   153  
   154  		phase("========== SUBDIR = " + subname + " ==========")
   155  
   156  		makeHomeDir(t, "BasicAlice")
   157  
   158  		plaintextFoo := "I am the foo.txt file!\n"
   159  		plainAltered := "I am the altered file!\n"
   160  
   161  		runBB(t, "testing_init") // Runs "git init" or equiv
   162  		assertFileExists(t, ".git")
   163  		runBB(t, "init", "yes") // Creates .blackbox or equiv
   164  
   165  		if subname != "." {
   166  			err := os.Mkdir(subname, 0770)
   167  			if err != nil {
   168  				t.Fatal(fmt.Errorf("hard-mk-home %q: %v", subname, err))
   169  			}
   170  		}
   171  		olddir, err := os.Getwd()
   172  		if err != nil {
   173  			t.Fatal(err)
   174  		}
   175  
   176  		os.Chdir(subname)
   177  		os.Chdir(olddir)
   178  
   179  		phase("Alice creates a GPG key")
   180  		gpgdir := makeAdmin(t, "alice", "Alice Example", "alice@example.com")
   181  		become(t, "alice")
   182  
   183  		phase("Alice enrolls as an admin")
   184  		//os.Chdir(subname)
   185  		runBB(t, "admin", "add", "alice@example.com", gpgdir)
   186  		//os.Chdir(olddir)
   187  
   188  		// encrypt
   189  		phase("Alice registers foo.txt")
   190  		makeFile(t, "foo.txt", plaintextFoo)
   191  		//os.Chdir(subname)
   192  		//runBB(t, "file", "add", "--shred", filepath.Join(prefix, "foo.txt"))
   193  		runBB(t, "file", "add", "--shred", "foo.txt")
   194  		//os.Chdir(olddir)
   195  		// "file add" encrypts the file.
   196  		// We shred the plaintext so that we are sure that when Decrypt runs,
   197  		// we can verify the contents wasn't just sitting there all the time.
   198  		assertFileMissing(t, "foo.txt")
   199  		assertFileExists(t, "foo.txt.gpg")
   200  
   201  		phase("Alice decrypts foo.txt")
   202  		// decrypt
   203  		//os.Chdir(subname)
   204  		runBB(t, "decrypt", "foo.txt")
   205  		//runBB(t, "decrypt", filepath.Join(prefix, "foo.txt"))
   206  		//os.Chdir(olddir)
   207  		assertFileExists(t, "foo.txt")
   208  		assertFileExists(t, "foo.txt.gpg")
   209  		assertFileContents(t, "foo.txt", plaintextFoo)
   210  
   211  		// encrypts (without shredding)
   212  		phase("Alice encrypts foo.txt (again)")
   213  		runBB(t, "encrypt", "foo.txt")
   214  		assertFileExists(t, "foo.txt")
   215  		assertFileExists(t, "foo.txt.gpg")
   216  		assertFileContents(t, "foo.txt", plaintextFoo)
   217  
   218  		// reencrypt
   219  		phase("Alice reencrypts")
   220  		checkOutput("basic-status.txt", t, "status")
   221  		runBB(t, "reencrypt", "--overwrite", "foo.txt")
   222  
   223  		// Test variations of cat
   224  
   225  		// foo.txt=plain    result=plain
   226  		phase("Alice cats plain:plain")
   227  		makeFile(t, "foo.txt", plaintextFoo)
   228  		assertFileExists(t, "foo.txt")
   229  		runBB(t, "encrypt", "foo.txt")
   230  		assertFileExists(t, "foo.txt")
   231  		assertFileExists(t, "foo.txt.gpg")
   232  		checkOutput("alice-cat-plain.txt", t, "cat", "foo.txt")
   233  		assertFileExists(t, "foo.txt")
   234  		assertFileExists(t, "foo.txt.gpg")
   235  
   236  		// foo.txt=altered    result=plain
   237  		phase("Alice cats altered:plain")
   238  		makeFile(t, "foo.txt", plainAltered)
   239  		assertFileExists(t, "foo.txt")
   240  		assertFileExists(t, "foo.txt.gpg")
   241  		checkOutput("alice-cat-plain.txt", t, "cat", "foo.txt")
   242  		assertFileExists(t, "foo.txt")
   243  		assertFileExists(t, "foo.txt.gpg")
   244  
   245  		// foo.txt=missing  result=plain
   246  		phase("Alice cats missing:plain")
   247  		removeFile(t, "foo.txt")
   248  		assertFileMissing(t, "foo.txt")
   249  		assertFileMissing(t, "foo.txt")
   250  		assertFileExists(t, "foo.txt.gpg")
   251  		checkOutput("alice-cat-plain.txt", t, "cat", "foo.txt")
   252  		assertFileMissing(t, "foo.txt")
   253  		assertFileExists(t, "foo.txt.gpg")
   254  
   255  		// Chapter 2: Bob
   256  		// Alice adds Bob.
   257  		// Bob encrypts a file.
   258  		// Bob makes sure he can decrypt alice's file.
   259  		// Bob removes Alice.
   260  		// Alice verifies she CAN'T decrypt files.
   261  		// Bob adds Alice back.
   262  		// Alice verifies she CAN decrypt files.
   263  		// Bob adds an encrypted file by mistake, "bb add" and fixes it.
   264  		// Bob corrupts the blackbox-admins.txt file, verifies that commands fail.
   265  
   266  	}
   267  
   268  }
   269  
   270  // TestEvilFilenames verifies commands work with "difficult" file names
   271  func TestEvilFilenames(t *testing.T) {
   272  	if !*longTests {
   273  		return
   274  	}
   275  	compile(t)
   276  	setup(t)
   277  	makeHomeDir(t, "Mallory")
   278  
   279  	runBB(t, "testing_init") // Runs "git init" or equiv
   280  	assertFileExists(t, ".git")
   281  	runBB(t, "init", "yes") // Creates .blackbox or equiv
   282  
   283  	phase("Malory creates a GPG key")
   284  	gpgdir := makeAdmin(t, "mallory", "Mallory Evil", "mallory@example.com")
   285  	become(t, "mallory")
   286  
   287  	phase("Mallory enrolls as an admin")
   288  	runBB(t, "admin", "add", "mallory@example.com", gpgdir)
   289  
   290  	_ = os.MkdirAll("my/path/to", 0o770)
   291  	_ = os.Mkdir("other", 0o770)
   292  
   293  	for i, name := range []string{
   294  		"!important!.txt",
   295  		"#andpounds.txt",
   296  		"stars*bars?.txt",
   297  		"space space.txt",
   298  		"tab\ttab.txt",
   299  		"ret\rret.txt",
   300  		"smile😁eyes",
   301  		"¡que!",
   302  		"thé",
   303  		"pound£",
   304  		"*.go",
   305  		"rm -f erase ; echo done",
   306  		`smile☺`,
   307  		`dub𝓦`,
   308  		"my/path/to/relsecrets.txt",
   309  		//"my/../my/path/../path/to/myother.txt",  // Not permitted yet
   310  		//"other/../my//path/../path/to/otherother.txt", // Not permitted yet
   311  		//"new\nnew.txt",  // \n not permitted
   312  		//"two\n",  // \n not permitted (yet)
   313  		//"four\U0010FFFF",  // Illegal byte sequence. git won't accept.
   314  	} {
   315  		phase(fmt.Sprintf("Mallory tries %02d: %q", i, name))
   316  		contents := "the name of this file is the talking heads... i mean, " + name
   317  		makeFile(t, name, contents)
   318  		assertFileExists(t, name)
   319  		assertFileMissing(t, name+".gpg")
   320  		assertFileContents(t, name, contents)
   321  
   322  		runBB(t, "file", "add", name)
   323  		assertFileMissing(t, name)
   324  		assertFileExists(t, name+".gpg")
   325  
   326  		runBB(t, "decrypt", name)
   327  		assertFileExists(t, name)
   328  		assertFileExists(t, name+".gpg")
   329  		assertFileContents(t, name, contents)
   330  
   331  		runBB(t, "encrypt", name)
   332  		assertFileExists(t, name)
   333  		assertFileExists(t, name+".gpg")
   334  		assertFileContents(t, name, contents)
   335  
   336  		runBB(t, "shred", name)
   337  		assertFileMissing(t, name)
   338  		assertFileExists(t, name+".gpg")
   339  	}
   340  }
   341  
   342  // More tests to implement.
   343  // 1. Verify that the --gid works (blackbox decrypt --gid)