mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-16 11:39:53 +00:00
83 lines
2.7 KiB
Go
83 lines
2.7 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package main
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/MeshCore-Beacon/beacon-server/internal/backup"
|
|
)
|
|
|
|
func TestVerifyCommandIsReadOnlyAndOffline(t *testing.T) {
|
|
dir := t.TempDir()
|
|
t.Setenv("PATH", dir) // no pg_dump, psql or shell helper is available
|
|
t.Setenv("PGDATABASE", "")
|
|
archive := filepath.Join(dir, "private.tar.gz")
|
|
m := backup.Manifest{FormatVersion: 1, CreatedAt: time.Now().UTC(), DatabaseFormat: "postgresql-plain-sql", ToolVersion: "PRIVATE_CANARY"}
|
|
data := map[string][]byte{"database.sql": []byte("SELECT 'PRIVATE_CANARY';"), "config.yaml": {}}
|
|
for _, name := range []string{"database.sql", "config.yaml"} {
|
|
hash := sha256.Sum256(data[name])
|
|
m.Files = append(m.Files, backup.File{Name: name, Size: int64(len(data[name])), SHA256: hex.EncodeToString(hash[:])})
|
|
}
|
|
data["manifest.json"], _ = json.Marshal(m)
|
|
var raw bytes.Buffer
|
|
gz := gzip.NewWriter(&raw)
|
|
tw := tar.NewWriter(gz)
|
|
for _, name := range []string{"manifest.json", "database.sql", "config.yaml"} {
|
|
if err := tw.WriteHeader(&tar.Header{Name: name, Size: int64(len(data[name])), Mode: 0600}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := tw.Write(data[name]); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := tw.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := gz.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(archive, raw.Bytes(), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, tc := range []struct {
|
|
args []string
|
|
code int
|
|
}{
|
|
{[]string{"-verify", archive}, 0},
|
|
{[]string{"-verify", archive, "-max-bytes", "1"}, 1},
|
|
{[]string{"-verify", archive, "-timeout", "0"}, 2},
|
|
{[]string{"-verify", archive, "-output", filepath.Join(dir, "must-not-exist")}, 2},
|
|
{[]string{"-verify", archive, "-config", "missing.yaml"}, 2},
|
|
{[]string{"-verify", "", "-output", filepath.Join(dir, "must-not-exist")}, 2},
|
|
{[]string{"-verify", dir}, 1},
|
|
{[]string{"-verify", filepath.Join(dir, "PRIVATE_CANARY-missing")}, 1},
|
|
{[]string{"-verify", archive, "unexpected"}, 2},
|
|
} {
|
|
var stdout, stderr bytes.Buffer
|
|
if got := run(context.Background(), tc.args, &stdout, &stderr); got != tc.code || strings.Contains(stdout.String()+stderr.String(), "PRIVATE_CANARY") {
|
|
t.Fatalf("exit %d, want %d; diagnostic %s", got, tc.code, stderr.String())
|
|
}
|
|
}
|
|
files, err := os.ReadDir(dir)
|
|
if err != nil || len(files) != 1 || files[0].Name() != "private.tar.gz" {
|
|
t.Fatal("verification extracted files or created output")
|
|
}
|
|
unchanged, err := os.ReadFile(archive)
|
|
if err != nil || !bytes.Equal(unchanged, raw.Bytes()) {
|
|
t.Fatal("input archive changed")
|
|
}
|
|
}
|