Skip to content

Commit

Permalink
testutil/pkgdata: Create deb programatically
Browse files Browse the repository at this point in the history
Currently we only test with base-files deb which is embedded as base64
encoded binary in testutil/pkgdata.go. If we want to change the contents
of the data files, we have to un-ar it, un-tar it, change the data
files, tar it and ar it. Furthermore, these operations modify attributes
based on the workstation on which this process is run. So we end up with
arbitrary user/group ids/names names and dates.

Fix it by creating debs programatically. The new interface provides way
to create debs with arbitrary content of data tarball.
  • Loading branch information
woky committed Jan 10, 2023
1 parent 36cf47d commit cd75f89
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
114 changes: 114 additions & 0 deletions internal/testutil/pkgdata.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package testutil

import (
"archive/tar"
"bytes"
"encoding/base64"
"time"

"github.com/blakesmith/ar"
"github.com/klauspost/compress/zstd"
)

var PackageData = map[string][]byte{}
Expand Down Expand Up @@ -150,3 +156,111 @@ BIsAGAJD+LGgIzDiD2ntudH6JU80wD0rklyRGBV2dEx8VJG5LVwpcXb8PI0lMdi+wwUPoBkQGEIN
7UwLQKMDjg8YkdmAmRrEgCSRRhMWBgBBSuI7S4BVs7zODfj1ja0TF+KbjdQDGANIcRlZhwzQSlla
abj2Z7KoYMBXz9dwNNP2Aw13FguKkogezW5cqy4lCg==
`

type TarEntry struct {
Header tar.Header
NoFixup bool
Content []byte
}

var zeroTime time.Time
var epochStartTime time.Time = time.Unix(0, 0)

func fixupEntry(entry *TarEntry) {
hdr := &entry.Header
if hdr.Typeflag == 0 {
if hdr.Linkname != "" {
hdr.Typeflag = tar.TypeSymlink
} else if hdr.Name[len(hdr.Name)-1] == '/' {
hdr.Typeflag = tar.TypeDir
} else {
hdr.Typeflag = tar.TypeReg
}
}
if hdr.Mode == 0 {
switch hdr.Typeflag {
case tar.TypeDir:
hdr.Mode = 0755
case tar.TypeSymlink:
hdr.Mode = 0777
default:
hdr.Mode = 0644
}
}
if hdr.Size == 0 && entry.Content != nil {
hdr.Size = int64(len(entry.Content))
}
if hdr.Uid == 0 && hdr.Uname == "" {
hdr.Uname = "root"
}
if hdr.Gid == 0 && hdr.Gname == "" {
hdr.Gname = "root"
}
if hdr.ModTime == zeroTime {
hdr.ModTime = epochStartTime
}
if hdr.Format == 0 {
hdr.Format = tar.FormatGNU
}
}

func makeTar(entries []TarEntry) ([]byte, error) {
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
for _, entry := range entries {
if !entry.NoFixup {
fixupEntry(&entry)
}
if err := tw.WriteHeader(&entry.Header); err != nil {
return nil, err
}
if entry.Content != nil {
if _, err := tw.Write(entry.Content); err != nil {
return nil, err
}
}
}
return buf.Bytes(), nil
}

func compressBytesZstd(input []byte) ([]byte, error) {
var buf bytes.Buffer
writer, err := zstd.NewWriter(&buf)
if _, err = writer.Write(input); err != nil {
return nil, err
}
if err = writer.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

func MakeDeb(entries []TarEntry) ([]byte, error) {
var buf bytes.Buffer

tarData, err := makeTar(entries)
if err != nil {
return nil, err
}
compTarData, err := compressBytesZstd(tarData)
if err != nil {
return nil, err
}

writer := ar.NewWriter(&buf)
if err := writer.WriteGlobalHeader(); err != nil {
return nil, err
}
dataHeader := ar.Header{
Name: "data.tar.zst",
Mode: 0644,
Size: int64(len(compTarData)),
}
if err := writer.WriteHeader(&dataHeader); err != nil {
return nil, err
}
if _, err = writer.Write(compTarData); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
62 changes: 62 additions & 0 deletions internal/testutil/pkgdata_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package testutil_test

import (
"archive/tar"

_ "embed"

"github.com/canonical/chisel/internal/testutil"
"gopkg.in/check.v1"
)

type pkgdataSuite struct{}

var _ = check.Suite(&pkgdataSuite{})

var pkgdataTestEntries = []testutil.TarEntry{{
Header: tar.Header{Name: "./"},
}, {
Header: tar.Header{Name: "./admin/", Mode: 00700, Uname: "admin"},
}, {
Header: tar.Header{Name: "./admin/password", Mode: 00600, Uname: "admin"},
Content: []byte("swordf1sh"),
}, {
Header: tar.Header{Name: "./admin/setpassword", Mode: 04711, Uname: "admin"},
Content: []byte{0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01},
}, {
Header: tar.Header{Name: "./data/"},
}, {
Header: tar.Header{Name: "./data/invoice.txt"},
Content: []byte("$ 10"),
}, {
Header: tar.Header{Name: "./data/logs/"},
}, {
Header: tar.Header{Name: "./data/logs/task.log"},
Content: []byte("starting\nfinished\n"),
}, {
Header: tar.Header{Name: "./data/shared/", Mode: 02777},
}, {
Header: tar.Header{Name: "./home/"},
}, {
Header: tar.Header{Name: "./home/alice/", Uid: 1000},
}, {
Header: tar.Header{Name: "./home/alice/notes", Uid: 1000},
Content: []byte("check the cat"),
}, {
Header: tar.Header{Name: "./home/bob/", Uname: "bob", Uid: 1001},
}, {
Header: tar.Header{Name: "./home/bob/task.sh", Mode: 00700, Uname: "bob", Uid: 1001},
Content: []byte("#!/bin/sh\n"),
}, {
Header: tar.Header{Name: "./logs/", Linkname: "data/logs"},
}}

//go:embed testdata/pkgdata.deb
var pkgdataExpectedDeb []byte

func (s *pkgdataSuite) TestMakeDeb(c *check.C) {
deb, err := testutil.MakeDeb(pkgdataTestEntries)
c.Assert(err, check.IsNil)
//os.WriteFile("/tmp/pkdata.deb", deb, 0644)
c.Assert(deb, check.DeepEquals, pkgdataExpectedDeb)
}
Binary file added internal/testutil/testdata/pkgdata.deb
Binary file not shown.

0 comments on commit cd75f89

Please sign in to comment.