package main import ( "bytes" "compress/gzip" "io" "os" "path/filepath" "strconv" "testing" ) func TestWriteInitramfsIsDeterministicAndContainsExecutableInit(t *testing.T) { first := filepath.Join(t.TempDir(), "first.cpio.gz") second := filepath.Join(t.TempDir(), "second.cpio.gz") for _, output := range []string{first, second} { if err := writeInitramfs(output, []byte("static-arm64-init")); err != nil { t.Fatal(err) } } one, _ := os.ReadFile(first) two, _ := os.ReadFile(second) if !bytes.Equal(one, two) { t.Fatal("initramfs output is not deterministic") } entries := readNewc(t, one) if got := string(entries["init"].data); got != "static-arm64-init" { t.Fatalf("init contents = %q", got) } if entries["init"].mode != 0o100755 { t.Fatalf("init mode = %#o", entries["init"].mode) } for _, directory := range []string{"dev", "proc", "sys", "userdata"} { if entries[directory].mode&0o170000 != 0o040000 { t.Fatalf("%s is not a directory", directory) } } } func TestWriteInitramfsIncludesReadOnlyTrustAnchor(t *testing.T) { output := filepath.Join(t.TempDir(), "recovery.cpio.gz") if err := writeInitramfsWithEntries(output, []byte("init"), []archiveEntry{{name: "etc/tera/update-trust/production.json", mode: 0o100444, data: []byte(`{"format_version":1}`)}}); err != nil { t.Fatal(err) } compressed, err := os.ReadFile(output) if err != nil { t.Fatal(err) } entries := readNewc(t, compressed) anchor := entries["etc/tera/update-trust/production.json"] if anchor.mode != 0o100444 || string(anchor.data) != `{"format_version":1}` { t.Fatalf("trust anchor = %+v", anchor) } } func readNewc(t *testing.T, compressed []byte) map[string]archiveEntry { t.Helper() reader, err := gzip.NewReader(bytes.NewReader(compressed)) if err != nil { t.Fatal(err) } data, err := io.ReadAll(reader) if err != nil { t.Fatal(err) } entries := map[string]archiveEntry{} for offset := 0; ; { if offset+110 > len(data) || string(data[offset:offset+6]) != "070701" { t.Fatalf("invalid newc header at %d", offset) } mode := parseHex(t, data[offset+14:offset+22]) size := int(parseHex(t, data[offset+54:offset+62])) nameSize := int(parseHex(t, data[offset+94:offset+102])) nameStart := offset + 110 name := string(data[nameStart : nameStart+nameSize-1]) dataStart := align4(nameStart + nameSize) if name == "TRAILER!!!" { break } entries[name] = archiveEntry{name: name, mode: mode, data: append([]byte(nil), data[dataStart:dataStart+size]...)} offset = align4(dataStart + size) } return entries } func parseHex(t *testing.T, value []byte) uint32 { t.Helper() parsed, err := strconv.ParseUint(string(value), 16, 32) if err != nil { t.Fatal(err) } return uint32(parsed) } func align4(value int) int { return (value + 3) &^ 3 }