106 lines
3.1 KiB
Go
106 lines
3.1 KiB
Go
package aptrepo
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"server-deploy/internal/installplan"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestStagingRejectsLinksAndFIFO(t *testing.T) {
|
|
dir := t.TempDir()
|
|
for _, name := range []string{"docker.asc", "Release", "Release.gpg", "Packages"} {
|
|
if err := os.WriteFile(filepath.Join(dir, name), []byte("metadata"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
link := filepath.Join(t.TempDir(), "link")
|
|
if err := os.Symlink(dir, link); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readStaging(link + "/"); err == nil {
|
|
t.Fatal("root symlink accepted")
|
|
}
|
|
if err := os.Remove(filepath.Join(dir, "Release")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(filepath.Join(dir, "Packages"), filepath.Join(dir, "Release")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readStaging(dir); err == nil {
|
|
t.Fatal("file symlink accepted")
|
|
}
|
|
if err := os.Remove(filepath.Join(dir, "Release")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := syscall.Mkfifo(filepath.Join(dir, "Release"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readStaging(dir); err == nil {
|
|
t.Fatal("FIFO accepted")
|
|
}
|
|
}
|
|
|
|
func TestGPGFailureRedactsDiagnostics(t *testing.T) {
|
|
if _, err := runGPG(t.TempDir(), "/nonexistent/signature-tool-secret"); err == nil || err.Error() != "repository signature tool failed" {
|
|
t.Fatal("unredacted or absent error", err)
|
|
}
|
|
}
|
|
|
|
func TestOutputBound(t *testing.T) {
|
|
var b cappedOutput
|
|
if _, err := b.Write(make([]byte, 65536)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := b.Write([]byte{1}); err == nil {
|
|
t.Fatal("output limit missing")
|
|
}
|
|
if b.Len() != 65536 {
|
|
t.Fatal("buffer grew beyond limit")
|
|
}
|
|
}
|
|
|
|
func TestStagedSignatureIntegration(t *testing.T) {
|
|
// Explicit opt-in public fixture, downloaded by the metadata-only probe.
|
|
dir := os.Getenv("DEPLOYCTL_REPOSITORY_FIXTURE")
|
|
if dir == "" {
|
|
t.Skip("public signed fixture not supplied; run repository probe for real signature evidence")
|
|
}
|
|
files, err := readStaging(dir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := authenticate(files, time.Now()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Result comes from the successful real CLI invocation. Recheck the exact
|
|
// fixture versions before making a semantically valid signature mutation.
|
|
var response struct {
|
|
Lock installplan.Lock `json:"lock"`
|
|
}
|
|
raw, err := os.ReadFile(filepath.Join(dir, "result.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = json.Unmarshal(raw, &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
versions := make(map[string]string)
|
|
for _, p := range response.Lock.Packages {
|
|
versions[p.Name] = p.Version
|
|
}
|
|
// Unknown Release extension remains valid metadata; only its signature
|
|
// should reject it. This catches a bypass hidden by syntax failures.
|
|
files["Release"] = append(bytes.TrimRight(files["Release"], "\n"), []byte("\nX-Verification-Probe: changed\n")...)
|
|
if _, err := Resolve(files["Release"], files["Packages"], response.Lock.Suite, response.Lock.Architecture, versions, time.Now()); err != nil {
|
|
t.Fatal("mutation masked by metadata rejection", err)
|
|
}
|
|
if err := authenticate(files, time.Now()); err == nil {
|
|
t.Fatal("tampered signature accepted")
|
|
}
|
|
}
|