package main import ( "crypto/sha256" "database/sql" "encoding/hex" "encoding/json" "fmt" "os" "os/exec" "path/filepath" "strings" "testing" "forge-mesh/internal/db" "forge-mesh/internal/forge" ) func TestForgeBuildCrossCompileAndSign(t *testing.T) { dir := t.TempDir() cfgPath := writeForgeConfig(t, dir) bin := buildForgeBinary(t) out, err := exec.Command(bin, "build", "--config", cfgPath, "--version", "test-1.0", "--public", ).CombinedOutput() if err != nil { t.Fatalf("forge build: %v\n%s", err, out) } output := string(out) if !strings.Contains(output, "linux/amd64") || !strings.Contains(output, "linux/arm64") { t.Fatalf("expected amd64 and arm64 builds in output:\n%s", output) } if !strings.Contains(output, "checksum=") { t.Fatalf("expected checksum in build output:\n%s", output) } if !strings.Contains(output, "public key:") { t.Fatalf("expected public key in build output:\n%s", output) } artifactsDir := filepath.Join(dir, "artifacts") for _, arch := range []string{"amd64", "arm64"} { path := filepath.Join(artifactsDir, "forge-mesh-agent-linux-"+arch) assertSignedArtifact(t, path, cfgPath) } } func TestForgeBuildPublicFlag(t *testing.T) { dir := t.TempDir() cfgPath := writeForgeConfig(t, dir) bin := buildForgeBinary(t) if out, err := exec.Command(bin, "build", "--config", cfgPath, "--public=false").CombinedOutput(); err != nil { t.Fatalf("forge build private: %v\n%s", err, out) } conn := openDB(t, filepath.Join(dir, "forge-mesh.db")) defer conn.Close() var publicCount int if err := conn.QueryRow(`SELECT COUNT(*) FROM builds WHERE public = 1`).Scan(&publicCount); err != nil { t.Fatal(err) } if publicCount != 0 { t.Fatalf("expected no public builds with --public=false, got %d", publicCount) } if out, err := exec.Command(bin, "build", "--config", cfgPath, "--public").CombinedOutput(); err != nil { t.Fatalf("forge build public: %v\n%s", err, out) } if err := conn.QueryRow(`SELECT COUNT(*) FROM builds WHERE public = 1`).Scan(&publicCount); err != nil { t.Fatal(err) } if publicCount < 2 { t.Fatalf("expected public builds after --public, got %d", publicCount) } } func TestForgePubkey(t *testing.T) { dir := t.TempDir() cfgPath := writeForgeConfig(t, dir) bin := buildForgeBinary(t) out, err := exec.Command(bin, "pubkey", "--config", cfgPath).CombinedOutput() if err != nil { t.Fatalf("forge pubkey: %v\n%s", err, out) } hexKey := strings.TrimSpace(string(out)) if len(hexKey) != 64 { t.Fatalf("expected 64-char ed25519 pubkey hex, got %q", hexKey) } cfg := readForgeConfigFile(t, cfgPath) kp, err := forge.LoadOrCreateKey(cfg.Forge.SigningKeyPath) if err != nil { t.Fatal(err) } if kp.PublicKeyHex() != hexKey { t.Fatalf("pubkey mismatch: CLI %s key file %s", hexKey, kp.PublicKeyHex()) } } func TestForgeUsageExitsNonZero(t *testing.T) { bin := buildForgeBinary(t) cmd := exec.Command(bin) err := cmd.Run() if err == nil { t.Fatal("expected non-zero exit without subcommand") } } func assertSignedArtifact(t *testing.T, path, cfgPath string) { t.Helper() info, err := os.Stat(path) if err != nil { t.Fatalf("artifact %s: %v", path, err) } if info.Size() == 0 { t.Fatalf("empty artifact %s", path) } data, err := os.ReadFile(path) if err != nil { t.Fatal(err) } sum := sha256.Sum256(data) checksum := hex.EncodeToString(sum[:]) cfg := readForgeConfigFile(t, cfgPath) kp, err := forge.LoadOrCreateKey(cfg.Forge.SigningKeyPath) if err != nil { t.Fatal(err) } sig := kp.Sign(data) if !forge.Verify(kp.Public, data, sig) { t.Fatalf("artifact %s failed ed25519 verification", path) } conn := openDB(t, cfg.DatabasePath) defer conn.Close() var dbChecksum, dbSig string err = conn.QueryRow(` SELECT checksum, signature FROM builds WHERE path = ? ORDER BY created_at DESC LIMIT 1 `, path).Scan(&dbChecksum, &dbSig) if err != nil { t.Fatalf("build row for %s: %v", path, err) } if dbChecksum != checksum { t.Fatalf("checksum mismatch for %s: db %s file %s", path, dbChecksum, checksum) } if !forge.Verify(kp.Public, data, dbSig) { t.Fatalf("db signature invalid for %s", path) } } func buildForgeBinary(t *testing.T) string { t.Helper() out := filepath.Join(t.TempDir(), "forge-mesh-forge") cmd := exec.Command("go", "build", "-o", out, "./cmd/forge") cmd.Dir = repoRoot(t) if outBytes, err := cmd.CombinedOutput(); err != nil { t.Fatalf("build forge: %v\n%s", err, outBytes) } return out } func writeForgeConfig(t *testing.T, dir string) string { t.Helper() cfgPath := filepath.Join(dir, "config.json") content := fmt.Sprintf(`{ "listen_addr": ":0", "data_dir": %q, "database_path": %q, "auth": { "fleet_secret": "forge-test-secret" }, "forge": { "signing_key_path": %q, "artifacts_dir": %q } }`, dir, filepath.Join(dir, "forge-mesh.db"), filepath.Join(dir, "signing.key"), filepath.Join(dir, "artifacts")) if err := os.WriteFile(cfgPath, []byte(content), 0o644); err != nil { t.Fatal(err) } return cfgPath } type forgeConfigSnippet struct { DatabasePath string `json:"database_path"` Forge struct { SigningKeyPath string `json:"signing_key_path"` } `json:"forge"` } func readForgeConfigFile(t *testing.T, path string) forgeConfigSnippet { t.Helper() data, err := os.ReadFile(path) if err != nil { t.Fatal(err) } var cfg forgeConfigSnippet if err := json.Unmarshal(data, &cfg); err != nil { t.Fatal(err) } return cfg } func openDB(t *testing.T, path string) *sql.DB { t.Helper() conn, err := db.Open(path) if err != nil { t.Fatal(err) } return conn } func repoRoot(t *testing.T) string { t.Helper() wd, err := os.Getwd() if err != nil { t.Fatal(err) } for { if _, err := os.Stat(filepath.Join(wd, "go.mod")); err == nil { return wd } parent := filepath.Dir(wd) if parent == wd { t.Fatal("go.mod not found") } wd = parent } }