4b70e31cf4
Critical fixes:
- logs --job: validate ^[A-Za-z0-9_-]+$ + shellQuote (was %q backtick RCE)
- pprof: isLoopback treats empty host as bind-all (was :6060 bypass)
- backup restore: filepath.Rel containment check (was tar-slip via a/../..)
- WebAuthn reg auth deferred to P04 (requires session infra)
High fixes:
- txn rollback/show/apply: validate ^T-[0-9a-f]{16}$ + shellQuote
- nft diff --against: validate txn ID before filepath.Join
- drain stopAlloc: validate allocID ^[A-Za-z0-9_-]+$
- cluster_compat: shellQuote peer dir name
- podman image: shellQuote (was %q backtick injection)
- nft TrustedProbes: net.ParseIP/CIDR validation + split v4/v6 sets
- sudoers: validate --proxmox-user/--proxmox-role ^[a-zA-Z_][a-zA-Z0-9_-]{0,31}$
fixed path /etc/sudoers.d/orca; shellQuote pveum/useradd; validateSudoers
checks actual file
- nft country block: validate ^[A-Z]{2}$ (was len==2 only)
New file: internal/cli/validate.go (shared validators + shellQuote)
All 38 Go test packages pass. go vet + gofmt clean.
---ci---
project: orca
phase: 2
milestone: v0.13
status: complete
requirements:
covered: [150]
---/ci---
253 lines
6.6 KiB
Go
253 lines
6.6 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.cloudinit.dev/coreci/orca/internal/emitter"
|
|
)
|
|
|
|
func TestNftCmd_Registered(t *testing.T) {
|
|
found := false
|
|
for _, c := range rootCmd.Commands() {
|
|
if c.Name() == "nft" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("nft command not registered on root")
|
|
}
|
|
}
|
|
|
|
func TestNftShowCmd(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
origPeer := nftLeadPeerOverride
|
|
defer func() {
|
|
nftTransportOverride = origTransport
|
|
nftLeadPeerOverride = origPeer
|
|
}()
|
|
nftLeadPeerOverride = "lead"
|
|
want := "table inet orca-ingress { dnat }"
|
|
nftTransportOverride = &mockNftTransport{
|
|
execOut: map[string][]byte{
|
|
"nft list table inet orca-ingress": []byte(want),
|
|
},
|
|
}
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "show"})
|
|
if err := rootCmd.Execute(); err != nil {
|
|
t.Fatalf("nft show: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), want) {
|
|
t.Errorf("nft show output missing %q:\n%s", want, buf.String())
|
|
}
|
|
}
|
|
|
|
func TestNftShowCmd_PeerFlag(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
defer func() { nftTransportOverride = origTransport }()
|
|
mt := &mockNftTransport{
|
|
execOut: map[string][]byte{"nft list table inet orca-ingress": []byte("ok")},
|
|
}
|
|
nftTransportOverride = mt
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "show", "--peer", "node-2"})
|
|
if err := rootCmd.Execute(); err != nil {
|
|
t.Fatalf("nft show: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNftDiffCmd_NoDrift(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
origPeer := nftLeadPeerOverride
|
|
defer func() {
|
|
nftTransportOverride = origTransport
|
|
nftLeadPeerOverride = origPeer
|
|
}()
|
|
nftLeadPeerOverride = "lead"
|
|
// Use the full default nft render so the diff detects no drift
|
|
rendered, rerr := emitter.NftEmitter{}.RenderNftConfig(emitter.NftClusterConfig{})
|
|
if rerr != nil {
|
|
t.Fatalf("render: %v", rerr)
|
|
}
|
|
live := string(rendered[0].Content)
|
|
nftTransportOverride = &mockNftTransport{
|
|
execOut: map[string][]byte{
|
|
"nft list table inet orca-ingress": []byte(live),
|
|
},
|
|
}
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "diff", "--against", "T-abcdef0123456789"})
|
|
if err := rootCmd.Execute(); err != nil {
|
|
t.Fatalf("nft diff: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "no drift") {
|
|
t.Errorf("expected no drift, got:\n%s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestNftDiffCmd_RequiresAgainst(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "diff"})
|
|
if err := rootCmd.Execute(); err == nil {
|
|
t.Fatal("expected error for missing --against, got nil")
|
|
}
|
|
}
|
|
|
|
func TestNftRateLimitSetCmd(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
origPeer := nftLeadPeerOverride
|
|
defer func() {
|
|
nftTransportOverride = origTransport
|
|
nftLeadPeerOverride = origPeer
|
|
}()
|
|
nftLeadPeerOverride = "lead"
|
|
mt := &mockNftTransport{
|
|
execOut: map[string][]byte{},
|
|
}
|
|
nftTransportOverride = mt
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "rate", "limit", "set", "--rate", "250"})
|
|
if err := rootCmd.Execute(); err != nil {
|
|
t.Fatalf("nft rate limit set: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "rate-limit set to 250/s burst 500") {
|
|
t.Errorf("unexpected output:\n%s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestNftRateLimitSetCmd_RequiresRate(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "rate", "limit", "set"})
|
|
if err := rootCmd.Execute(); err == nil {
|
|
t.Fatal("expected error for missing --rate, got nil")
|
|
}
|
|
}
|
|
|
|
func TestNftCountryBlockAddCmd(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
origPeer := nftLeadPeerOverride
|
|
defer func() {
|
|
nftTransportOverride = origTransport
|
|
nftLeadPeerOverride = origPeer
|
|
}()
|
|
nftLeadPeerOverride = "lead"
|
|
mt := &mockNftTransport{execOut: map[string][]byte{}}
|
|
nftTransportOverride = mt
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "country", "block", "add", "RU,CN"})
|
|
if err := rootCmd.Execute(); err != nil {
|
|
t.Fatalf("nft country block add: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "added 2 country code(s)") {
|
|
t.Errorf("unexpected output:\n%s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestNftCountryBlockAddCmd_BadCode(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "country", "block", "add", "USA"})
|
|
if err := rootCmd.Execute(); err == nil {
|
|
t.Fatal("expected error for bad country code, got nil")
|
|
}
|
|
}
|
|
|
|
func TestNftDoctorAliasCmd(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
origPeer := nftLeadPeerOverride
|
|
defer func() {
|
|
nftTransportOverride = origTransport
|
|
nftLeadPeerOverride = origPeer
|
|
}()
|
|
nftLeadPeerOverride = "lead"
|
|
nftTransportOverride = &mockNftTransport{
|
|
execOut: map[string][]byte{
|
|
"nft list table inet orca-ingress": []byte("dnat to 127.0.0.1:8443 dnat to 127.0.0.1:8080 ora_rl"),
|
|
},
|
|
}
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "doctor"})
|
|
if err := rootCmd.Execute(); err != nil {
|
|
t.Fatalf("nft doctor: %v", err)
|
|
}
|
|
if !strings.Contains(buf.String(), "nft:table") {
|
|
t.Errorf("nft doctor alias did not run doctor nft checks:\n%s", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestNftShowCmd_ExecError(t *testing.T) {
|
|
_, cleanup := initTestEnv(t)
|
|
defer cleanup()
|
|
origTransport := nftTransportOverride
|
|
origPeer := nftLeadPeerOverride
|
|
defer func() {
|
|
nftTransportOverride = origTransport
|
|
nftLeadPeerOverride = origPeer
|
|
}()
|
|
nftLeadPeerOverride = "lead"
|
|
nftTransportOverride = &mockNftTransport{
|
|
execErr: map[string]error{
|
|
"nft list table inet orca-ingress": errors.New("connection refused"),
|
|
},
|
|
}
|
|
resetRootFlags(t)
|
|
var buf bytes.Buffer
|
|
rootCmd.SetOut(&buf)
|
|
rootCmd.SetErr(&buf)
|
|
rootCmd.SetArgs([]string{"nft", "show"})
|
|
if err := rootCmd.Execute(); err == nil {
|
|
t.Fatal("expected error from exec failure, got nil")
|
|
}
|
|
}
|
|
|
|
var _ context.Context = context.Background()
|