//go:build linux package provisioner import ( "bytes" "fmt" "io" "log/slog" "os" "os/exec" "testing" "github.com/go-json-experiment/json" ) func TestCLIPrivateOutput(t *testing.T) { if os.Getenv("OFICINA_CLI_CHILD") == "1" { args := []string{"provision", "init", "--state", os.Getenv("OFICINA_CLI_STATE"), "--floor-dir", os.Getenv("OFICINA_CLI_FLOOR"), "--password-fd", "3"} if os.Getenv("OFICINA_CLI_INVALID") == "1" { args = append(args, "--unknown", "canary-8f3a@example.invalid") } if e := Run(args, os.Stdout); e != nil { slog.Error("provisioner", "err", e) os.Exit(1) } return } state, floor := persistentDirectory(t), persistentDirectory(t) run := func(invalid bool) ([]byte, []byte, error) { reader, writer, e := os.Pipe() if e != nil { t.Fatal(e) } cmd := exec.Command(os.Args[0], "-test.run=^TestCLIPrivateOutput$") cmd.ExtraFiles = []*os.File{reader} cmd.Env = append(os.Environ(), "OFICINA_CLI_CHILD=1", "OFICINA_CLI_STATE="+state, "OFICINA_CLI_FLOOR="+floor) if invalid { cmd.Env = append(cmd.Env, "OFICINA_CLI_INVALID=1") } var out, errout bytes.Buffer cmd.Stdout = &out cmd.Stderr = &errout if e = cmd.Start(); e != nil { t.Fatal(e) } reader.Close() io.WriteString(writer, "synthetic-private-password") writer.Close() e = cmd.Wait() return out.Bytes(), errout.Bytes(), e } out, errout, e := run(false) if e != nil { t.Fatalf("child failed: %v %s", e, errout) } // The Go test runner adds PASS after the helper returns. Keep the actual Run // result separate while still observing the complete process streams. line, _, ok := bytes.Cut(out, []byte("\n")) if !ok { t.Fatal("missing structured output") } var got RegistryInfo if json.Unmarshal(line, &got, json.RejectUnknownMembers(true)) != nil || got.Sequence != 0 || len(got.PublicKey) != 87 || len(got.Registry) != 43 || len(got.Device) != 43 { t.Fatal("unexpected public result") } if len(errout) != 0 || bytes.Contains(out, []byte("synthetic-private-password")) { t.Fatal("private CLI output") } out, errout, e = run(true) if e == nil || len(out) != 0 || bytes.Contains(errout, []byte("canary-8f3a@example.invalid")) || bytes.Contains(errout, []byte("synthetic-private-password")) || !bytes.Contains(errout, []byte(ErrRefused.Error())) { t.Fatal(fmt.Sprint("invalid input privacy: ", e)) } }