Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ VERSION_OVERRIDE=v0.8.15 IMAGE_NAMESPACE=local/pasturestack make package

Pull requests and `main` run one non-publishing gate: tests, vet/format checks, govulncheck, a reproducible binary build, one runtime image build, and Trivy scans plus CycloneDX SBOMs for the source, binary, and image. All reported vulnerabilities and secrets fail the gate. Publishing remains a separate, explicitly authorized operation.

The opt-in, root-only host NAT and host-port VM tests reuse the runtime's
read-only Docker firewall detection before changing any rules. This also
recognizes older Docker APIs without `FirewallBackend.Driver` and avoids
probing unloaded legacy tables on nft-only hosts. Run them only on a
disposable VM with a rollback point; ordinary CI does not execute them.

## Compatibility and security

Some legacy API paths, Docker labels, filesystem paths, and dependency namespaces are protocol or data contracts. They are isolated and documented in [COMPATIBILITY.md](COMPATIBILITY.md), rather than exposed as PastureStack branding.
Expand Down
18 changes: 9 additions & 9 deletions hostnat/iptables_vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/PastureStack/network-plugin-manager/internal/firewall"
"github.com/moby/moby/client"
)

// Opt-in root test for an isolated VM. It refuses to run when the production
Expand All @@ -34,19 +35,18 @@ func testIptablesBatchOnVM(t *testing.T, mode firewall.Mode) {
t.Fatal(err)
}
}
if out, err := exec.Command("docker", "info", "--format", "{{.FirewallBackend.Driver}}").CombinedOutput(); err != nil || strings.TrimSpace(string(out)) != "iptables" {
t.Fatalf("requires Docker iptables backend: %v: %s", err, out)
dc, err := client.New(client.FromEnv)
if err != nil {
t.Fatal(err)
}
defer dc.Close()
detected, err := firewall.Detect(dc, mode)
if err != nil || detected.Mode != mode || detected.Command != command || detected.Restore != restore {
t.Fatalf("refusing mismatched Docker firewall backend %s: detected=%+v err=%v", mode, detected, err)
}
if out, err := exec.Command(command, "-t", "nat", "-S", "DOCKER").CombinedOutput(); err != nil {
t.Fatalf("requires Docker-owned NAT chain in %s: %v: %s", mode, err, out)
}
other := "iptables-nft"
if mode == firewall.IptablesNFT {
other = "iptables-legacy"
}
if out, err := exec.Command(other, "-t", "nat", "-S", "DOCKER").CombinedOutput(); err == nil {
t.Fatalf("refusing dual Docker backends; %s also owns NAT: %s", other, out)
}
iptables := func(args ...string) ([]byte, error) {
return exec.Command(command, args...).CombinedOutput()
}
Expand Down
17 changes: 3 additions & 14 deletions hostports/iptables_vm_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package hostports

import (
"context"
"os"
"os/exec"
"strings"
Expand Down Expand Up @@ -47,23 +46,13 @@ func testIptablesOnDisposableVM(t *testing.T, mode firewall.Mode) {
t.Fatal(err)
}
defer dc.Close()
info, err := dc.Info(context.Background(), client.InfoOptions{})
if err != nil {
t.Fatal(err)
}
if info.Info.FirewallBackend == nil || info.Info.FirewallBackend.Driver != "iptables" {
t.Fatalf("refusing xtables test outside Docker iptables mode: %#v", info.Info.FirewallBackend)
detected, err := firewall.Detect(dc, mode)
if err != nil || detected.Mode != mode || detected.Command != command || detected.Restore != restore {
t.Fatalf("refusing mismatched Docker firewall backend %s: detected=%+v err=%v", mode, detected, err)
}
if out, err := exec.Command(command, "-t", "nat", "-S", "DOCKER").CombinedOutput(); err != nil {
t.Fatalf("requires Docker-owned NAT chain in %s: %v: %s", mode, err, out)
}
other := "iptables-nft"
if mode == firewall.IptablesNFT {
other = "iptables-legacy"
}
if out, err := exec.Command(other, "-t", "nat", "-S", "DOCKER").CombinedOutput(); err == nil {
t.Fatalf("refusing dual Docker backends; %s also owns NAT: %s", other, out)
}
for _, table := range []string{"nat", "filter"} {
out, err := xtVMCommand(command, "-t", table, "-S")
if err != nil {
Expand Down