ci / vet-and-test (pull_request) Successful in 40s
Why: Backend PR #185 merged while the dependency migration was open. Its account transactions, audit behavior and migration tests must remain intact when this branch adopts the new main. Evidence: SELF 343 upstream Go files match after canonical import translation except the two bounded test-reliability corrections; complete Go test and vet passed in /tmp/dependency-backend-after-185-{parity,all-go,vet}-20261014-01a1345f.json. Impact: Disposable integration fixture first; the actual Backend branch can fast-forward to this tested merge without rewriting other task history. No production account logic is changed relative to the new main. Refs: Backend PR #196; upstream Backend PR #185; Dev PR #537; R15
159 lines
4.5 KiB
Go
159 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/store"
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func accountCLI(t *testing.T, args ...string) (int, string) {
|
|
t.Helper()
|
|
out, err := os.CreateTemp(t.TempDir(), "capture-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer out.Close()
|
|
oldOut, oldErr := os.Stdout, os.Stderr
|
|
os.Stdout = out
|
|
os.Stderr = out
|
|
defer func() { os.Stdout = oldOut; os.Stderr = oldErr }()
|
|
rc := runUser(args)
|
|
out.Seek(0, 0)
|
|
raw, err := io.ReadAll(out)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return rc, string(raw)
|
|
}
|
|
func cliStore(t *testing.T) (string, *store.Store) {
|
|
t.Helper()
|
|
t.Setenv("AGENT_SYSTEM_DSN", "")
|
|
dir := t.TempDir()
|
|
s, e := store.OpenSQLite(filepath.Join(dir, "agent-system.db"))
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
t.Cleanup(func() { s.Close() })
|
|
if e := s.EnsureSystemIdentity("fixture", "sqlite"); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
return dir, s
|
|
}
|
|
func TestOutputFileAppliesToEveryCredentialCommand(t *testing.T) {
|
|
for _, sub := range []string{"create", "reset-password", "issue-login-key", "bootstrap-admin"} {
|
|
t.Run(sub, func(t *testing.T) {
|
|
dir, s := cliStore(t)
|
|
if sub != "create" && sub != "bootstrap-admin" {
|
|
if e := s.CreateAccount("ada", "Ada", "", false); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
}
|
|
out := filepath.Join(t.TempDir(), "secret")
|
|
rc, _ := accountCLI(t, sub, "--data", dir, "--owner", "ada", "--out-file", out)
|
|
if rc != 0 {
|
|
t.Fatalf("credential command failed: %d", rc)
|
|
}
|
|
info, e := os.Stat(out)
|
|
if e != nil {
|
|
t.Fatal("credential output file missing")
|
|
}
|
|
if info.Mode().Perm() != 0600 {
|
|
t.Fatal("credential output permissions are not private")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func TestExistingOutputAndConflictingFormatsRefuseBeforeMutation(t *testing.T) {
|
|
for _, kind := range []string{"existing", "conflicting"} {
|
|
t.Run(kind, func(t *testing.T) {
|
|
dir, s := cliStore(t)
|
|
out := filepath.Join(t.TempDir(), "secret")
|
|
args := []string{"create", "--data", dir, "--owner", "ada", "--out-file", out}
|
|
if kind == "existing" {
|
|
if e := os.WriteFile(out, []byte("existing"), 0600); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
} else {
|
|
args = append(args, "--out", filepath.Join(t.TempDir(), "json-secret"))
|
|
}
|
|
rc, _ := accountCLI(t, args...)
|
|
if rc == 0 {
|
|
t.Fatal("unsafe output selection succeeded")
|
|
}
|
|
if _, e := s.GetUser("ada"); e == nil {
|
|
t.Fatal("output refusal happened after account mutation")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAPIKeyCreateUsesExclusivePrivateOutput(t *testing.T) {
|
|
if dir := os.Getenv("U7_APIKEY_CHILD_DIR"); dir != "" {
|
|
rc := runAPIKey([]string{"create", "--data", dir, "--owner", "ada", "--name", "fixture", "--out-file", os.Getenv("U7_APIKEY_CHILD_OUT")})
|
|
if rc != 0 {
|
|
t.Fatal("apikey create rejected its private output destination")
|
|
}
|
|
return
|
|
}
|
|
for _, existing := range []bool{false, true} {
|
|
name := "new"
|
|
if existing {
|
|
name = "existing"
|
|
}
|
|
t.Run(name, func(t *testing.T) {
|
|
dir, st := cliStore(t)
|
|
if err := st.CreateAccount("ada", "Ada", "", false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := filepath.Join(t.TempDir(), "credential")
|
|
if existing {
|
|
if err := os.WriteFile(out, []byte("preserve"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
cmd := exec.Command(os.Args[0], "-test.run=^TestAPIKeyCreateUsesExclusivePrivateOutput$")
|
|
cmd.Env = append(os.Environ(), "U7_APIKEY_CHILD_DIR="+dir, "U7_APIKEY_CHILD_OUT="+out)
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
err := cmd.Run()
|
|
if existing {
|
|
if err == nil {
|
|
t.Fatal("existing output was overwritten or mutation succeeded")
|
|
}
|
|
raw, readErr := os.ReadFile(out)
|
|
if readErr != nil || string(raw) != "preserve" {
|
|
t.Fatal("existing output was modified")
|
|
}
|
|
keys, listErr := st.ListAPIKeys("ada")
|
|
if listErr != nil || len(keys) != 0 {
|
|
t.Fatal("mutation happened before output preflight")
|
|
}
|
|
return
|
|
}
|
|
if err != nil {
|
|
t.Fatal("new private output was rejected")
|
|
}
|
|
info, statErr := os.Stat(out)
|
|
if statErr != nil || info.Mode().Perm() != 0600 {
|
|
t.Fatal("credential output missing or not private")
|
|
}
|
|
raw, readErr := os.ReadFile(out)
|
|
if readErr != nil || len(raw) == 0 {
|
|
t.Fatal("credential output empty")
|
|
}
|
|
if bytes.Contains(stdout.Bytes(), bytes.TrimSpace(raw)) {
|
|
t.Fatal("credential was written to stdout")
|
|
}
|
|
keys, listErr := st.ListAPIKeys("ada")
|
|
if listErr != nil || len(keys) != 1 {
|
|
t.Fatal("successful issue was not committed")
|
|
}
|
|
})
|
|
}
|
|
}
|