110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func findRepoFile(name string) (string, error) {
|
|
candidates := []string{
|
|
name,
|
|
filepath.Join("..", "..", name),
|
|
filepath.Join("..", name),
|
|
}
|
|
for _, p := range candidates {
|
|
if _, err := os.Stat(p); err == nil {
|
|
return p, nil
|
|
}
|
|
}
|
|
return "", fmt.Errorf("file %q not found", name)
|
|
}
|
|
|
|
func readRepoFile(t *testing.T, name string) string {
|
|
t.Helper()
|
|
path, err := findRepoFile(name)
|
|
if err != nil {
|
|
t.Fatalf("find file %s: %v", name, err)
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatalf("read file %s: %v", path, err)
|
|
}
|
|
return string(data)
|
|
}
|
|
|
|
func TestComposeDNSAndAdvertiseIP(t *testing.T) {
|
|
content := readRepoFile(t, "docker-compose.yml")
|
|
|
|
// 1. Must publish 8005:8005, 8007:8007, 5223:5223.
|
|
requiredPorts := []string{"8005:8005", "8007:8007", "5223:5223"}
|
|
for _, port := range requiredPorts {
|
|
if !strings.Contains(content, port) {
|
|
t.Errorf("docker-compose.yml missing port mapping %q", port)
|
|
}
|
|
}
|
|
|
|
// 2. Must not use host networking.
|
|
if strings.Contains(content, "network_mode: host") || strings.Contains(content, "network_mode: \"host\"") {
|
|
t.Error("docker-compose.yml must not use network_mode: host")
|
|
}
|
|
|
|
// 3. Comment block must mention lbo.ecouser.net and ADVERTISE_IP.
|
|
if !strings.Contains(content, "lbo.ecouser.net") {
|
|
t.Error("docker-compose.yml comment must contain lbo.ecouser.net")
|
|
}
|
|
if !strings.Contains(content, "ADVERTISE_IP") {
|
|
t.Error("docker-compose.yml comment must contain ADVERTISE_IP")
|
|
}
|
|
|
|
// 4. Must not contain an MQTT_PASSWORD value.
|
|
lines := strings.Split(content, "\n")
|
|
for _, line := range lines {
|
|
trimmed := strings.TrimSpace(line)
|
|
if strings.HasPrefix(trimmed, "#") {
|
|
continue
|
|
}
|
|
if strings.Contains(trimmed, "MQTT_PASSWORD") {
|
|
parts := strings.SplitN(trimmed, ":", 2)
|
|
if len(parts) == 2 && strings.TrimSpace(parts[1]) != "" {
|
|
t.Errorf("docker-compose.yml must not contain an MQTT_PASSWORD value, found: %q", trimmed)
|
|
}
|
|
}
|
|
}
|
|
|
|
t.Log("Specification §15 item B1 verified and closed")
|
|
}
|
|
|
|
func TestDockerfileNonRootStatic(t *testing.T) {
|
|
content := readRepoFile(t, "Dockerfile")
|
|
|
|
if !strings.Contains(content, "golang:1.27.1") {
|
|
t.Error("Dockerfile must specify golang:1.27.1")
|
|
}
|
|
if !strings.Contains(content, "CGO_ENABLED=0") {
|
|
t.Error("Dockerfile must set CGO_ENABLED=0")
|
|
}
|
|
if !strings.Contains(content, "gcr.io/distroless/static-debian12:nonroot") {
|
|
t.Error("Dockerfile must use gcr.io/distroless/static-debian12:nonroot")
|
|
}
|
|
if !strings.Contains(content, "@sha256:") {
|
|
t.Error("Dockerfile must pin images by sha256 digest")
|
|
}
|
|
}
|
|
|
|
func TestDockerignoreExcludesPcap(t *testing.T) {
|
|
content := readRepoFile(t, ".dockerignore")
|
|
|
|
if !strings.Contains(content, "*.pcap") {
|
|
t.Error(".dockerignore must match *.pcap")
|
|
}
|
|
if !strings.Contains(content, "docs/") {
|
|
t.Error(".dockerignore must exclude docs/")
|
|
}
|
|
if !strings.Contains(content, ".env") {
|
|
t.Error(".dockerignore must exclude .env")
|
|
}
|
|
}
|