Initial commit: Incredigo — local-first RAM-only credential custody
v1: discover → migrate → expiry tracking → sealed export/import. - vault: memguard mlock/DONTDUMP arena, handle indirection, zeroize-on-drop - discover: registry + 8 read-only scanners (aws, env, netrc, ssh, docker, kube, git) and a file/dir harvester (--path) - sink: gopass streaming insert; length-prefixed bundle framing; Sealer interface with three impls — age (default, authenticated), hmac (authenticated, openssl-only encrypt-then-MAC), openssl (CBC fallback, unauthenticated; OpenSSL 3.x enc refuses AEAD) - policy: local expiry engine, 60d/8w threshold parser - audit: redacted append-only JSONL, injectable clock - export/import: passphrase from no-echo prompt or $INCREDIGO_PASSPHRASE into locked memory; secrets stream gopass<->Sealer as bytes, never Go strings - tests: scanner leak-checks, vault zeroize, bundle round-trip via fake gopass; go test ./... green, -race clean Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package sink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"incredigo/internal/discover"
|
||||
)
|
||||
|
||||
// writeFakeGopass writes a stub `gopass` binary that stores entries as files under
|
||||
// $FAKE_GOPASS_STORE, supporting the ls/show/insert subcommands the bundle code
|
||||
// uses. This exercises the real framing + subprocess plumbing without touching the
|
||||
// user's actual gopass store.
|
||||
func writeFakeGopass(t *testing.T) string {
|
||||
t.Helper()
|
||||
bin := filepath.Join(t.TempDir(), "gopass")
|
||||
script := `#!/usr/bin/env bash
|
||||
store="$FAKE_GOPASS_STORE"
|
||||
case "$1" in
|
||||
ls) (cd "$store" 2>/dev/null && find . -type f | sed 's#^\./##' | sort) ;;
|
||||
show) cat "$store/$3" ;;
|
||||
insert)
|
||||
shift; path=""
|
||||
for a in "$@"; do case "$a" in --multiline=false|-f) ;; *) path="$a";; esac; done
|
||||
mkdir -p "$store/$(dirname "$path")"; cat > "$store/$path" ;;
|
||||
esac
|
||||
`
|
||||
if err := os.WriteFile(bin, []byte(script), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return bin
|
||||
}
|
||||
|
||||
func seed(t *testing.T, store string, entries map[string]string) {
|
||||
t.Helper()
|
||||
for path, secret := range entries {
|
||||
full := filepath.Join(store, path)
|
||||
if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(full, []byte(secret), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBundleRoundTrip(t *testing.T) {
|
||||
bin := writeFakeGopass(t)
|
||||
gp := &Gopass{Bin: bin}
|
||||
ctx := context.Background()
|
||||
|
||||
src := t.TempDir()
|
||||
seed(t, src, map[string]string{
|
||||
"imported/aws/default": "AKIA/secret+with=specials",
|
||||
"imported/env/api": "unicode-末-\U0001f511",
|
||||
"other/skip": "should-not-export",
|
||||
})
|
||||
|
||||
// Export the imported/ subtree to a framed (unsealed) buffer.
|
||||
t.Setenv("FAKE_GOPASS_STORE", src)
|
||||
var buf bytes.Buffer
|
||||
n, err := gp.ExportTo(ctx, &buf, "imported/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if n != 2 {
|
||||
t.Fatalf("exported %d entries, want 2 (other/ excluded by prefix)", n)
|
||||
}
|
||||
|
||||
// Import into a fresh store and assert byte-exact restoration.
|
||||
dst := t.TempDir()
|
||||
t.Setenv("FAKE_GOPASS_STORE", dst)
|
||||
m, err := gp.ImportFrom(ctx, &buf, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if m != 2 {
|
||||
t.Fatalf("imported %d entries, want 2", m)
|
||||
}
|
||||
|
||||
want := map[string]string{
|
||||
"imported/aws/default": "AKIA/secret+with=specials",
|
||||
"imported/env/api": "unicode-末-\U0001f511",
|
||||
}
|
||||
for path, exp := range want {
|
||||
got, err := os.ReadFile(filepath.Join(dst, path))
|
||||
if err != nil {
|
||||
t.Fatalf("restored %s: %v", path, err)
|
||||
}
|
||||
if string(got) != exp {
|
||||
t.Errorf("%s: got %q want %q", path, got, exp)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(dst, "other", "skip")); !os.IsNotExist(err) {
|
||||
t.Error("other/skip leaked across the prefix filter")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorePathNoDoubleSegment(t *testing.T) {
|
||||
gp := &Gopass{Prefix: "imported/"}
|
||||
c := discover.Credential{Source: "file", Identity: "keys/deploy"}
|
||||
if got := gp.StorePath(c); got != "imported/file/keys/deploy" {
|
||||
t.Errorf("StorePath = %q, want imported/file/keys/deploy", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user