Files
Privatae e4c9b69b46
ci / personal-data (push) Successful in 5s
ci / test (push) Successful in 3m4s
ci / fuzz (push) Successful in 3m45s
bastion 0.53.2
2026-10-20 04:42:14 +00:00

91 lines
3.2 KiB
Go

package main
// Fuzz the two walls a host's input meets on the backup lane: the reseal
// request it files, and the sidecar it hands over. Whatever the input, the
// request filed is well formed and the sidecar opened is the backup it names.
import (
"bytes"
"encoding/json"
"strings"
"testing"
"time"
"filippo.io/age"
"filippo.io/age/armor"
)
func FuzzBackupResealRequest(f *testing.F) {
id, _ := age.GenerateX25519Identity()
good := string(armorSealF(f, []byte(`{"v":1}`), id.Recipient()))
f.Add(good, id.Recipient().String(), fixtureStamp, "the host")
f.Add("-----BEGIN AGE ENCRYPTED FILE-----", "age1", "../x", "a\nb")
f.Add(good, "AAAA", "20260928T020000Z", strings.Repeat("x", 200))
f.Fuzz(func(t *testing.T, sidecar, to, stamp, label string) {
dir := t.TempDir()
r, err := resealFile(dir, fixtureWho, resealReq{Op: "start", Sidecar: sidecar, To: to, Stamp: stamp, HostLabel: label})
if err != nil {
if m, _ := resealRead(dir); len(m) != 0 {
t.Fatal("a refused request was filed")
}
return
}
if !backupStampRe.MatchString(r.Stamp) {
t.Fatalf("filed a request for %q", r.Stamp)
}
if _, err := age.ParseX25519Recipient(r.To); err != nil {
t.Fatalf("filed a request to an unusable key %q", r.To)
}
if strings.ContainsAny(r.HostLabel, "\n\r\t\x00") || len(r.HostLabel) > 120 {
t.Fatalf("filed a label that is not one short line: %q", r.HostLabel)
}
if len(r.Sidecar) > sidecarMaxBytes || r.State != "pending" {
t.Fatal("filed an oversized or already-decided request")
}
})
}
func FuzzOpenSidecarNamesItsBackup(f *testing.F) {
user, _ := age.GenerateX25519Identity()
pb, _ := age.GenerateX25519Identity()
good, _ := json.Marshal(backupSidecar{V: 1, Kind: sidecarKind, Identity: pb.String(),
Object: "b/" + fixtureStamp + ".tar.zst.age", EntityID: 1, Stamp: fixtureStamp, MadeAt: "2026-09-28T02:00:00Z"})
f.Add(good, "")
f.Add(bytes.Replace(good, []byte(`"b/`), []byte(`"s/`), 1), fixtureStamp)
f.Add(bytes.Replace(good, []byte(`"b/`), []byte(`"s/../b/`), 1), "")
f.Add([]byte(`{"v":1,"kind":"privatae-backup-key","stamp":"x","object":"b/x.tar.zst.age"}`), fixtureStamp)
f.Add([]byte("not json"), "")
f.Fuzz(func(t *testing.T, plain []byte, want string) {
sealed := armorSealF(t, plain, user.Recipient())
_, sc, err := openSidecar(sealed, []age.Identity{user}, want)
if err != nil {
return
}
if sc.V != 1 || sc.Kind != sidecarKind || !backupStampRe.MatchString(sc.Stamp) ||
(sc.Object != "b/"+sc.Stamp+".tar.zst.age" && sc.Object != "s/"+sc.Stamp+".tar.zst.age") ||
(want != "" && sc.Stamp != want) {
t.Fatalf("opened a sidecar that does not name its backup: %+v (want %q)", sc, want)
}
if _, err := age.ParseX25519Identity(sc.Identity); err != nil {
t.Fatal("opened a sidecar whose key does not parse")
}
if _, err := time.Parse(time.RFC3339, sc.MadeAt); err != nil {
t.Fatalf("opened a sidecar whose made_at %q is not a time", sc.MadeAt)
}
})
}
func armorSealF(tb testing.TB, plain []byte, to age.Recipient) []byte {
tb.Helper()
var out bytes.Buffer
aw := armor.NewWriter(&out)
w, err := age.Encrypt(aw, to)
if err != nil {
tb.Fatal(err)
}
_, _ = w.Write(plain)
_ = w.Close()
_ = aw.Close()
return out.Bytes()
}