diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fe0aa40..e007430 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,5 +28,7 @@ jobs: run: nix run nixpkgs.nix-build-uncached -c nix-build-uncached default.nix - name: Add keys group (needed for go tests) run: sudo groupadd keys - - name: Run go tests - run: nix-shell --run "sudo unshare --mount --fork go test ./pkgs/sops-install-secrets" + - name: Run sops-install-secrets tests + run: nix-shell --pure --run "$(command -v sudo) unshare --mount --fork go test ./pkgs/sops-install-secrets" + - name: Run sops-pgp-hook tests + run: nix-shell --pure --run "NIX_PATH=nixpkgs=$(nix-instantiate --find-file nixpkgs) go test ./pkgs/sops-pgp-hook" diff --git a/default.nix b/default.nix index 2b67a87..9b97904 100644 --- a/default.nix +++ b/default.nix @@ -6,6 +6,7 @@ in rec { inherit vendorSha256; }; sops-pgp-hook = pkgs.callPackage ./pkgs/sops-pgp-hook {}; + ssh-to-pgp = pkgs.callPackage ./pkgs/ssh-to-pgp { inherit vendorSha256; }; diff --git a/pkgs/sops-pgp-hook/default.nix b/pkgs/sops-pgp-hook/default.nix index 9384123..56241d4 100644 --- a/pkgs/sops-pgp-hook/default.nix +++ b/pkgs/sops-pgp-hook/default.nix @@ -1,8 +1,8 @@ -{ makeSetupHook, gnupg, sops }: +{ stdenv, makeSetupHook, gnupg, sops, go, nix }: -makeSetupHook { +(makeSetupHook { substitutions = { gpg = "${gnupg}/bin/gpg"; }; deps = [ sops gnupg ]; -} ./sops-pgp-hook.bash +} ./sops-pgp-hook.bash) diff --git a/pkgs/sops-pgp-hook/hook_test.go b/pkgs/sops-pgp-hook/hook_test.go new file mode 100644 index 0000000..6d4f8f2 --- /dev/null +++ b/pkgs/sops-pgp-hook/hook_test.go @@ -0,0 +1,54 @@ +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// ok fails the test if an err is not nil. +func ok(tb testing.TB, err error) { + if err != nil { + _, file, line, _ := runtime.Caller(1) + fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error()) + tb.FailNow() + } +} + +func TestShellHook(t *testing.T) { + _, filename, _, _ := runtime.Caller(0) + assets := path.Join(path.Dir(filename), "test-assets") + tempdir, err := ioutil.TempDir("", "testdir") + ok(t, err) + defer os.RemoveAll(tempdir) + + cmd := exec.Command("nix-shell", "shell.nix", "--run", "echo SOPS_PGP_FP=$SOPS_PGP_FP") + cmd.Env = append(os.Environ(), fmt.Sprintf("GNUPGHOME=%s", tempdir)) + var stdoutBuf, stderrBuf bytes.Buffer + cmd.Stdout = &stdoutBuf + cmd.Stderr = &stderrBuf + cmd.Dir = assets + err = cmd.Run() + stdout := string(stdoutBuf.Bytes()) + stderr := string(stderrBuf.Bytes()) + fmt.Printf("$ %s\nstdout: \n%s\nstderr: \n%s\n", strings.Join(cmd.Args, " "), stdout, stderr) + ok(t, err) + + expectedStdout := "SOPS_PGP_FP=C6DA56E69A7C756564A8AFEB4A6B05B714D13EFD,4EC40F8E04A945339F7F7C0032C5225271038E3F,7FB89715AADA920D65D25E63F9BA9DEBD03F57C0" + if strings.Index(stdout, expectedStdout) == -1 { + t.Fatalf("'%v' not in '%v'", expectedStdout, stdout) + } + + expectedStderr := "./non-existing-key.gpg does not exists" + if strings.Index(stderr, expectedStderr) == -1 { + t.Fatalf("'%v' not in '%v'", expectedStderr, stdout) + } + +} diff --git a/pkgs/sops-pgp-hook/sops-pgp-hook.bash b/pkgs/sops-pgp-hook/sops-pgp-hook.bash index dbbd539..5bb0097 100644 --- a/pkgs/sops-pgp-hook/sops-pgp-hook.bash +++ b/pkgs/sops-pgp-hook/sops-pgp-hook.bash @@ -3,18 +3,24 @@ _sopsAddKey() { local fpr fpr=$(@gpg@ --with-fingerprint --with-colons --show-key "$key" \ | awk -F: '$1 == "fpr" { print $10;}') - export SOPS_PGP_FP=''${SOPS_PGP_FP}''${SOPS_PGP_FP:+','}$fpr + if [[ $fpr != "" ]]; then + export SOPS_PGP_FP=''${SOPS_PGP_FP}''${SOPS_PGP_FP:+','}$fpr + fi } sopsPGPHook() { local key dir for key in $sopsPGPKeys; do - _sopsAddKey "$key" + if [[ -f "$key" ]]; then + _sopsAddKey "$key" + else + echo "$key does not exists" >&2 + fi done for dir in $sopsPGPKeyDirs; do while IFS= read -r -d '' key; do _sopsAddKey "$key" - done < <(find "$dir" -type f -name '*.gpg' -o -name '*.asc' -print0) + done < <(find -L "$dir" -type f \( -name '*.gpg' -o -name '*.asc' \) -print0) done } diff --git a/pkgs/sops-pgp-hook/test-assets/existing-key.gpg b/pkgs/sops-pgp-hook/test-assets/existing-key.gpg new file mode 100644 index 0000000..eba3738 Binary files /dev/null and b/pkgs/sops-pgp-hook/test-assets/existing-key.gpg differ diff --git a/pkgs/sops-pgp-hook/test-assets/keys/key.asc b/pkgs/sops-pgp-hook/test-assets/keys/key.asc new file mode 120000 index 0000000..34bc240 --- /dev/null +++ b/pkgs/sops-pgp-hook/test-assets/keys/key.asc @@ -0,0 +1 @@ +../../../sops-install-secrets/test-assets/key.asc \ No newline at end of file diff --git a/pkgs/sops-pgp-hook/test-assets/keys/key.gpg b/pkgs/sops-pgp-hook/test-assets/keys/key.gpg new file mode 100644 index 0000000..c168d74 Binary files /dev/null and b/pkgs/sops-pgp-hook/test-assets/keys/key.gpg differ diff --git a/pkgs/sops-pgp-hook/test-assets/shell.nix b/pkgs/sops-pgp-hook/test-assets/shell.nix new file mode 100644 index 0000000..628a019 --- /dev/null +++ b/pkgs/sops-pgp-hook/test-assets/shell.nix @@ -0,0 +1,14 @@ +# shell.nix +with import {}; +mkShell { + sopsPGPKeyDirs = [ + "./keys" + ]; + sopsPGPKeys = [ + "./existing-key.gpg" + "./non-existing-key.gpg" + ]; + nativeBuildInputs = [ + (pkgs.callPackage ../../.. {}).sops-pgp-hook + ]; +} diff --git a/shell.nix b/shell.nix index 7b695f2..7f1bda6 100644 --- a/shell.nix +++ b/shell.nix @@ -6,6 +6,7 @@ pkgs.mkShell { delve gnupg utillinux + nix ]; # delve does not compile with hardening enabled hardeningDisable = [ "all" ];