fix(P01): register orca cert command tree + cert_repo tests (REQ-053)
The `orca cert` command (ca-init, gen, show, renew, fingerprint) was fully implemented in internal/cli/cert.go but never registered on rootCmd — unreachable from the CLI. Added init() registration (AD-022). Added cert_test.go (regression) + cert_smoke_test.go (e2e). Added cert_repo_test.go (11 tests) + migration 0007 (UNIQUE serial_hex, I-107). ---ci--- project: orca phase: 1 milestone: v0.7 status: verify requirements: covered: [REQ-053] partial: [] ---/ci---
This commit is contained in:
@@ -253,3 +253,7 @@ func parseFirstCertDER(pemBytes []byte) []byte {
|
||||
}
|
||||
return block.Bytes
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(NewCommand(slog.Default()))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func runCertArgs(t *testing.T, args []string) (string, error) {
|
||||
t.Helper()
|
||||
var buf bytes.Buffer
|
||||
rootCmd.SetOut(&buf)
|
||||
rootCmd.SetErr(&buf)
|
||||
rootCmd.SetArgs(args)
|
||||
defer func() {
|
||||
rootCmd.SetArgs(nil)
|
||||
rootCmd.SetOut(os.Stdout)
|
||||
rootCmd.SetErr(os.Stderr)
|
||||
}()
|
||||
err := rootCmd.Execute()
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func TestCertSmoke(t *testing.T) {
|
||||
t.Setenv("ORCA_HOME", t.TempDir())
|
||||
|
||||
t.Run("ca-init", func(t *testing.T) {
|
||||
out, err := runCertArgs(t, []string{"cert", "ca-init", "--cn", "test-ca"})
|
||||
if err != nil {
|
||||
t.Fatalf("ca-init: %v\n%s", err, out)
|
||||
}
|
||||
if !strings.Contains(out, "CA initialized") {
|
||||
t.Errorf("ca-init output unexpected: %s", out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("gen", func(t *testing.T) {
|
||||
out, err := runCertArgs(t, []string{"cert", "gen", "--cn", "test-server", "--san", "localhost", "--san", "127.0.0.1"})
|
||||
if err != nil {
|
||||
t.Fatalf("gen: %v\n%s", err, out)
|
||||
}
|
||||
if !strings.Contains(out, "Server cert generated") {
|
||||
t.Errorf("gen output unexpected: %s", out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("show", func(t *testing.T) {
|
||||
out, err := runCertArgs(t, []string{"cert", "show"})
|
||||
if err != nil {
|
||||
t.Fatalf("show: %v\n%s", err, out)
|
||||
}
|
||||
if strings.Contains(out, "PRIVATE KEY") {
|
||||
t.Errorf("show leaked private key material (REQ-035):\n%s", out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("fingerprint_ca", func(t *testing.T) {
|
||||
out, err := runCertArgs(t, []string{"cert", "fingerprint", "--which", "ca"})
|
||||
if err != nil {
|
||||
t.Fatalf("fingerprint ca: %v\n%s", err, out)
|
||||
}
|
||||
fp := strings.TrimSpace(out)
|
||||
if len(fp) != 64 || !isHex(fp) {
|
||||
t.Errorf("ca fingerprint = %q, want 64 hex chars", fp)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("fingerprint_server", func(t *testing.T) {
|
||||
out, err := runCertArgs(t, []string{"cert", "fingerprint", "--which", "server"})
|
||||
if err != nil {
|
||||
t.Fatalf("fingerprint server: %v\n%s", err, out)
|
||||
}
|
||||
fp := strings.TrimSpace(out)
|
||||
if len(fp) != 64 || !isHex(fp) {
|
||||
t.Errorf("server fingerprint = %q, want 64 hex chars", fp)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("renew", func(t *testing.T) {
|
||||
out, err := runCertArgs(t, []string{"cert", "renew"})
|
||||
if err != nil {
|
||||
t.Fatalf("renew: %v\n%s", err, out)
|
||||
}
|
||||
if !strings.Contains(out, "rotated") {
|
||||
t.Errorf("renew output unexpected: %s", out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("file_modes", func(t *testing.T) {
|
||||
dir := os.Getenv("ORCA_HOME")
|
||||
checks := []struct {
|
||||
path string
|
||||
want os.FileMode
|
||||
}{
|
||||
{"ca.crt", 0o644},
|
||||
{"ca.key", 0o600},
|
||||
{"server.crt", 0o644},
|
||||
{"server.key", 0o600},
|
||||
}
|
||||
for _, c := range checks {
|
||||
info, err := os.Stat(filepath.Join(dir, c.path))
|
||||
if err != nil {
|
||||
t.Fatalf("stat %s: %v", c.path, err)
|
||||
}
|
||||
if got := info.Mode().Perm(); got != c.want {
|
||||
t.Errorf("mode %s = %04o, want %04o (REQ-033)", c.path, got, c.want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func isHex(s string) bool {
|
||||
for _, r := range s {
|
||||
if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F')) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCertCommandRegistered(t *testing.T) {
|
||||
found := false
|
||||
for _, cmd := range rootCmd.Commands() {
|
||||
if strings.Fields(cmd.Use)[0] == "cert" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatal("cert command not registered on rootCmd")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertSubcommands(t *testing.T) {
|
||||
expected := []string{"ca-init", "gen", "show", "renew", "fingerprint"}
|
||||
registered := make(map[string]bool)
|
||||
for _, cmd := range rootCmd.Commands() {
|
||||
if strings.Fields(cmd.Use)[0] != "cert" {
|
||||
continue
|
||||
}
|
||||
for _, sub := range cmd.Commands() {
|
||||
registered[strings.Fields(sub.Use)[0]] = true
|
||||
}
|
||||
}
|
||||
for _, name := range expected {
|
||||
if !registered[name] {
|
||||
t.Errorf("expected cert subcommand %q not registered", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,8 +80,8 @@ func TestInit_FullBootstrap(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("migration version: %v", err)
|
||||
}
|
||||
if version != "0006_node_kind_os.sql" {
|
||||
t.Errorf("migration version = %q, want 0006_node_kind_os.sql", version)
|
||||
if version != "0007_certs_serial_unique.sql" {
|
||||
t.Errorf("migration version = %q, want 0007_certs_serial_unique.sql", version)
|
||||
}
|
||||
|
||||
// Verify localhost node registered with kind=localhost.
|
||||
|
||||
Reference in New Issue
Block a user