8d1cdceb5c
Sub-wave 1: internal/emitter/nft.go (nftables emitter, DNAT :443→127.0.0.1:8443, rate-limit, SYN-flood filter); Traefik static config 127.0.0.1:8443 binding (D-220); orca doctor nft; orca nft CLI (show/diff/doctor/country-block/rate-limit). Sub-wave 2: docs/threat-model.md (R-017 trust boundary, R-020 deadlock, D-234 secret exclusion, orca user blast radius, step-ca SPOF); orca doctor mTLS (chain verification + live handshake probe, C5). ---ci--- project: orca phase: 15.5 milestone: v0.11 status: execute ---/ci---
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
package emitter
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNftEmitter_RenderBasic(t *testing.T) {
|
|
files, err := (NftEmitter{}).RenderNftConfig(NftClusterConfig{})
|
|
if err != nil {
|
|
t.Fatalf("RenderNftConfig: %v", err)
|
|
}
|
|
if len(files) != 1 {
|
|
t.Fatalf("got %d files, want 1", len(files))
|
|
}
|
|
f := files[0]
|
|
if f.Path != "/etc/nftables.d/orca.nft" {
|
|
t.Errorf("Path = %q, want /etc/nftables.d/orca.nft", f.Path)
|
|
}
|
|
if f.Mode != "0644" {
|
|
t.Errorf("Mode = %q, want 0644", f.Mode)
|
|
}
|
|
c := f.Content
|
|
for _, want := range []string{
|
|
"#!/usr/sbin/nft -f",
|
|
"table inet orca-ingress",
|
|
"set orca_trusted_probes",
|
|
"type ipv4_addr",
|
|
"flags interval",
|
|
"127.0.0.1",
|
|
"::1",
|
|
"chain input",
|
|
"tcp dport 443 tcp-flags != syn,rst,ack,fin notrack drop",
|
|
"chain prerouting",
|
|
"tcp dport 443 dnat to 127.0.0.1:8443",
|
|
"tcp dport 80 dnat to 127.0.0.1:8080",
|
|
"chain forward",
|
|
"rate 100/second burst 200 packets",
|
|
"ora_rl",
|
|
} {
|
|
if !strings.Contains(c, want) {
|
|
t.Errorf("content missing %q:\n%s", want, c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNftEmitter_DefaultsApplied(t *testing.T) {
|
|
files, err := (NftEmitter{}).RenderNftConfig(NftClusterConfig{RateLimit: 0, RateBurst: 0})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
if !strings.Contains(files[0].Content, "rate 100/second burst 200 packets") {
|
|
t.Errorf("defaults not applied:\n%s", files[0].Content)
|
|
}
|
|
}
|
|
|
|
func TestNftEmitter_CustomRate(t *testing.T) {
|
|
files, err := (NftEmitter{}).RenderNftConfig(NftClusterConfig{RateLimit: 50, RateBurst: 150})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
if !strings.Contains(files[0].Content, "rate 50/second burst 150 packets") {
|
|
t.Errorf("custom rate not rendered:\n%s", files[0].Content)
|
|
}
|
|
}
|
|
|
|
func TestNftEmitter_CustomTrustedProbes(t *testing.T) {
|
|
files, err := (NftEmitter{}).RenderNftConfig(NftClusterConfig{TrustedProbes: []string{"10.0.0.5", "192.168.1.1"}})
|
|
if err != nil {
|
|
t.Fatalf("Render: %v", err)
|
|
}
|
|
c := files[0].Content
|
|
if !strings.Contains(c, "10.0.0.5, 192.168.1.1") {
|
|
t.Errorf("custom probes not rendered:\n%s", c)
|
|
}
|
|
if strings.Contains(c, "::1") {
|
|
t.Errorf("default ::1 should not be present when custom probes set:\n%s", c)
|
|
}
|
|
}
|
|
|
|
func TestNftEmitter_NegativeRateRejected(t *testing.T) {
|
|
if _, err := (NftEmitter{}).RenderNftConfig(NftClusterConfig{RateLimit: -1}); err == nil {
|
|
t.Fatal("expected error for negative rate, got nil")
|
|
}
|
|
}
|
|
|
|
func TestNftEmitter_ShebangFirst(t *testing.T) {
|
|
files, _ := (NftEmitter{}).RenderNftConfig(NftClusterConfig{})
|
|
if !strings.HasPrefix(files[0].Content, "#!/usr/sbin/nft -f\n") {
|
|
t.Errorf("shebang not first:\n%s", files[0].Content[:40])
|
|
}
|
|
}
|