feat(arch/binary): convert .pkg.tar.zst to Zeta binary package
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <[email protected]>
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
|
||||
"git.spectoria.dev/huntedbytheirs/zeta-reconstruct/internal/registry"
|
||||
)
|
||||
|
||||
const fixturePkg = "../../../testdata/hello-1.0-1-x86_64.pkg.tar.zst"
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
out := t.TempDir()
|
||||
err := Convert(fixturePkg, registry.Options{Output: out, Repo: "https://example.org/repo"})
|
||||
if err != nil {
|
||||
t.Fatalf("Convert() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
manifestPath := filepath.Join(out, "packages", "hello", "package.lua")
|
||||
tarballPath := filepath.Join(out, "packages", "hello", "hello-1.0-1.tar.gz")
|
||||
|
||||
content, err := os.ReadFile(manifestPath)
|
||||
if err != nil {
|
||||
t.Fatalf("package.lua not written: %v", err)
|
||||
}
|
||||
src := string(content)
|
||||
|
||||
if !strings.Contains(src, "archive = { strip = 1 }") {
|
||||
t.Errorf("package.lua does not contain archive mode marker:\n%s", src)
|
||||
}
|
||||
if !strings.Contains(src, `name = "hello"`) {
|
||||
t.Errorf("package.lua does not contain name field:\n%s", src)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tarballPath); err != nil {
|
||||
t.Fatalf("tarball not written: %v", err)
|
||||
}
|
||||
|
||||
// The sha256 field must equal a fresh hash of the written tarball.
|
||||
got := extractField(t, src, "sha256")
|
||||
want := fileSHA256(t, tarballPath)
|
||||
if got != want {
|
||||
t.Errorf("package.lua sha256 = %q, sha256(tarball) = %q", got, want)
|
||||
}
|
||||
|
||||
// Deps: glibc dropped, zlib renamed to libz.
|
||||
if !strings.Contains(src, `"libz"`) {
|
||||
t.Errorf("package.lua deps does not contain mapped libz:\n%s", src)
|
||||
}
|
||||
if strings.Contains(src, "glibc") {
|
||||
t.Errorf("package.lua still contains dropped glibc:\n%s", src)
|
||||
}
|
||||
|
||||
// Cross-tool validation: the emitted manifest must load through the
|
||||
// real Zeta manifest loader.
|
||||
lua, err := exec.LookPath("lua")
|
||||
if err != nil {
|
||||
t.Skip("lua not available; skipping cross-tool validation")
|
||||
}
|
||||
probe := `package.path="/home/specter/Public/ZETA/lib/?.lua;"..package.path; ` +
|
||||
`local m=require("manifest"); assert(m.load(` + quoteLua(manifestPath) + `))`
|
||||
cmd := exec.Command(lua, "-e", probe)
|
||||
if b, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("real Zeta manifest.load rejected the emitted manifest: %v\n%s", err, b)
|
||||
}
|
||||
|
||||
// The tarball must be a valid gzip+tar whose content matches the input
|
||||
// payload (usr/bin/hello).
|
||||
verifyTarballPayload(t, tarballPath)
|
||||
}
|
||||
|
||||
func TestConvertMissingPKGINFO(t *testing.T) {
|
||||
// A zstd-compressed tar without a .PKGINFO member.
|
||||
var buf strings.Builder
|
||||
tw := tar.NewWriter(&buf)
|
||||
body := "#!/bin/sh\n"
|
||||
if err := tw.WriteHeader(&tar.Header{Name: "usr/bin/x", Mode: 0o755, Size: int64(len(body))}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := tw.Write([]byte(body)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := tw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
enc, err := zstd.NewWriter(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
compressed := enc.EncodeAll([]byte(buf.String()), nil)
|
||||
|
||||
pkg := filepath.Join(t.TempDir(), "noinfo.pkg.tar.zst")
|
||||
if err := os.WriteFile(pkg, compressed, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = Convert(pkg, registry.Options{Output: t.TempDir(), Repo: "https://example.org/repo"})
|
||||
if err == nil {
|
||||
t.Fatal("Convert() error = nil, want error for archive without .PKGINFO")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "PKGINFO") {
|
||||
t.Errorf("Convert() error = %q, want it to name the missing .PKGINFO", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertMissingInput(t *testing.T) {
|
||||
err := Convert(filepath.Join(t.TempDir(), "nope.pkg.tar.zst"),
|
||||
registry.Options{Output: t.TempDir(), Repo: "https://example.org/repo"})
|
||||
if err == nil {
|
||||
t.Fatal("Convert() error = nil, want error for missing input file")
|
||||
}
|
||||
}
|
||||
|
||||
// extractField pulls the value of a `key = "value",` line from an emitted
|
||||
// package.lua.
|
||||
func extractField(t *testing.T, src, key string) string {
|
||||
t.Helper()
|
||||
for _, line := range strings.Split(src, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if !strings.HasPrefix(line, key) {
|
||||
continue
|
||||
}
|
||||
i := strings.Index(line, `"`)
|
||||
j := strings.LastIndex(line, `"`)
|
||||
if i < 0 || j <= i {
|
||||
t.Fatalf("field %q has no quoted value in %q", key, line)
|
||||
}
|
||||
return line[i+1 : j]
|
||||
}
|
||||
t.Fatalf("field %q not found in package.lua", key)
|
||||
return ""
|
||||
}
|
||||
|
||||
// fileSHA256 returns the lowercase hex sha256 of the file at path.
|
||||
func fileSHA256(t *testing.T, path string) string {
|
||||
t.Helper()
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// quoteLua renders a path as a safe single-quoted Lua string literal.
|
||||
func quoteLua(s string) string {
|
||||
return `'` + strings.ReplaceAll(s, `\`, `\\`) + `'`
|
||||
}
|
||||
|
||||
// verifyTarballPayload re-opens the emitted tarball and asserts the payload
|
||||
// file survived with the right content.
|
||||
func verifyTarballPayload(t *testing.T, path string) {
|
||||
t.Helper()
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
gz, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer gz.Close()
|
||||
|
||||
var found bool
|
||||
tr := tar.NewReader(gz)
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.TrimPrefix(hdr.Name, "./") == "usr/bin/hello" {
|
||||
found = true
|
||||
b, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(string(b), "hello") {
|
||||
t.Errorf("payload usr/bin/hello content = %q", b)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Error("payload member usr/bin/hello missing from tarball")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user