Files
server-deploy/internal/cli/package_test.go

118 lines
4.4 KiB
Go

package cli
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
)
func packageFixture(t *testing.T) (string, string) {
return packageFixturePayload(t, []byte("services: {}\n"))
}
func packageFixturePayload(t *testing.T, payload []byte) (string, string) {
t.Helper()
dir := t.TempDir()
digest := func(data []byte) string { sum := sha256.Sum256(data); return "sha256:" + hex.EncodeToString(sum[:]) }
manifest := map[string]any{
"protocolVersion": 1, "appId": "example", "version": "1.0.0", "runtime": "compose", "entrypoint": "compose.yaml",
"platforms": []string{"linux/amd64"},
"components": []map[string]string{{"name": "server", "image": "example/server@sha256:" + strings.Repeat("a", 64)}},
"files": []map[string]string{{"path": "compose.yaml", "digest": digest(payload)}},
}
raw, err := json.Marshal(manifest)
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "manifest.json"), raw, 0600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "compose.yaml"), payload, 0600); err != nil {
t.Fatal(err)
}
return dir, digest(raw)
}
func TestCheckPackagePolicyCLI(t *testing.T) {
payload := `{"services":{"server":{"image":"example/server@sha256:` + strings.Repeat("a", 64) + `","user":"1000:1000","read_only":true,"cap_drop":["ALL"],"security_opt":["no-new-privileges:true"],"restart":"no","networks":["backend"],"volumes":[]}},"networks":{"backend":{"internal":true}},"volumes":{}}`
for _, tc := range []struct {
payload string
accepted bool
}{
{payload, true},
{strings.Replace(payload, `"read_only":true`, `"read_only":false`, 1), false},
{`services: {}`, false},
} {
dir, digest := packageFixturePayload(t, []byte(tc.payload))
input, _ := json.Marshal(map[string]string{"directory": dir, "expectedDigest": digest})
code, out, diagnostics := run([]string{"check-package"}, string(input))
if tc.accepted {
var result struct {
PolicyPassed bool `json:"policyPassed"`
Executable bool `json:"executable"`
Profile string `json:"profile"`
Digest string `json:"digest"`
}
if code != 0 || json.Unmarshal([]byte(out), &result) != nil || !result.PolicyPassed || result.Executable || result.Profile == "" || result.Digest != digest {
t.Fatalf("bad check result: %s %s", out, diagnostics)
}
if strings.Contains(out, "1000:1000") {
t.Fatal("payload leaked")
}
if err := os.WriteFile(filepath.Join(dir, "compose.yaml"), []byte(tc.payload+" "), 0600); err != nil {
t.Fatal(err)
}
if code, _, _ := run([]string{"check-package"}, string(input)); code == 0 {
t.Fatal("policy bypassed integrity check")
}
} else if code == 0 || out != "" {
t.Fatal("unsafe package accepted")
}
}
}
func TestVerifyPackageCLI(t *testing.T) {
dir, digest := packageFixture(t)
input, _ := json.Marshal(map[string]string{"directory": dir, "expectedDigest": digest})
code, out, diagnostics := run([]string{"verify-package"}, string(input))
if code != 0 || diagnostics != "" {
t.Fatalf("package verification failed: %s", diagnostics)
}
var response struct {
Verified bool `json:"verified"`
Executable bool `json:"executable"`
PublisherAuthenticated bool `json:"publisherAuthenticated"`
FileCount int `json:"fileCount"`
Digest string `json:"digest"`
}
if err := json.Unmarshal([]byte(out), &response); err != nil {
t.Fatal(err)
}
if !response.Verified || response.Executable || response.PublisherAuthenticated || response.FileCount != 1 || response.Digest != digest {
t.Fatalf("misleading verification: %s", out)
}
if strings.Contains(out, "services: {}") {
t.Fatal("file contents leaked")
}
if err := os.WriteFile(filepath.Join(dir, "compose.yaml"), []byte("secret tampering"), 0600); err != nil {
t.Fatal(err)
}
code, out, diagnostics = run([]string{"verify-package"}, string(input))
if code == 0 || out != "" || strings.Contains(diagnostics, "secret tampering") {
t.Fatal("tampering accepted or leaked")
}
}
func TestVerifyPackageInvalidRequests(t *testing.T) {
for _, input := range []string{`{}`, `{"directory":".","expectedDigest":"latest"}`, `{"directory":"secret","expectedDigest":"bad","password":"do-not-echo"}`} {
code, out, diagnostics := run([]string{"verify-package"}, input)
if code == 0 || out != "" || strings.Contains(diagnostics, "do-not-echo") {
t.Fatal("invalid package request accepted or leaked")
}
}
}