Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ require (
github.com/extism/go-sdk v1.7.1 // indirect
github.com/fluxcd/cli-utils v1.2.1 // indirect
github.com/fxamacker/cbor/v2 v2.9.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
github.com/go-chi/chi/v5 v5.3.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-logr/logr v1.4.4 // indirect
Expand Down Expand Up @@ -414,7 +415,6 @@ require (
github.com/fluxcd/pkg/apis/acl v0.10.0 // indirect
github.com/fsnotify/fsnotify v1.10.1 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.13
github.com/gdamore/encoding v1.0.1 // indirect
github.com/github/go-spdx/v2 v2.7.0 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
Expand Down
54 changes: 36 additions & 18 deletions src/pkg/packager/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

"github.com/defenseunicorns/pkg/helpers/v2"
"github.com/defenseunicorns/pkg/oci"
"github.com/gabriel-vasile/mimetype"
"github.com/mholt/archives"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"

"github.com/zarf-dev/zarf/src/api"
Expand Down Expand Up @@ -206,13 +206,13 @@ func pullOCI(ctx context.Context, opts pullOCIOptions) (*layout.PackageLayout, e
return pkgLayout, nil
}

func pullHTTP(ctx context.Context, src, tarDir, shasum string, insecureTLSSkipVerify bool) (string, error) {
func pullHTTP(ctx context.Context, src, tarDir, shasum string, insecureTLSSkipVerify bool) (_ string, err error) {
if shasum == "" {
return "", errors.New("shasum cannot be empty")
}
tarPath := filepath.Join(tarDir, "data")

err := pullHTTPFile(ctx, src, tarPath, insecureTLSSkipVerify)
err = pullHTTPFile(ctx, src, tarPath, insecureTLSSkipVerify)
if err != nil {
return "", err
}
Expand All @@ -225,28 +225,46 @@ func pullHTTP(ctx context.Context, src, tarDir, shasum string, insecureTLSSkipVe
return "", fmt.Errorf("shasum mismatch for file %s, expected %s but got %s", tarPath, shasum, received)
}

mtype, err := mimetype.DetectFile(tarPath)
file, err := os.Open(tarPath)
if err != nil {
return "", err
}
defer func() {
if file != nil {
err = errors.Join(err, file.Close())
}
}()

format, _, err := archives.Identify(ctx, "data", file)
if errors.Is(err, archives.NoMatch) {
// A zstd filename lets archives identify streams that start with a skippable frame.
if _, err := file.Seek(0, io.SeekStart); err != nil {
return "", fmt.Errorf("unsupported archive format: %w", err)
}
format, _, err = archives.Identify(ctx, "data.zst", file)
}
if err != nil {
return "", fmt.Errorf("unsupported archive format: %w", err)
}

newPath := filepath.Join(tarDir, "data.tar")
switch format.MediaType() {
case "application/x-tar":
case "application/zstd":
newPath += ".zst"
default:
return "", fmt.Errorf("unsupported archive format: %s", format.MediaType())
}

if mtype.Is("application/x-tar") {
err = os.Rename(tarPath, newPath)
if err != nil {
return "", err
}
return newPath, nil
} else if mtype.Is("application/zstd") {
newPath = fmt.Sprintf("%s.zst", newPath)
err = os.Rename(tarPath, newPath)
if err != nil {
return "", err
}
return newPath, nil
if closeErr := file.Close(); closeErr != nil {
return "", closeErr
}
file = nil

if err := os.Rename(tarPath, newPath); err != nil {
return "", err
}
return "", fmt.Errorf("unsupported file type: %s", mtype.Extension())
return newPath, nil
}

func pullHTTPFile(ctx context.Context, src, tarPath string, insecureTLSSkipVerify bool) (err error) {
Expand Down
31 changes: 30 additions & 1 deletion src/pkg/packager/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package packager

import (
"crypto/sha256"
"encoding/hex"
"io"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -110,7 +112,34 @@ func TestPullUnsupported(t *testing.T) {
SHASum: "6e9dccce07ba9d3c45b7c872fae863c5415d296fd5e2fb72a2583530aa750ccd",
Architecture: "amd64",
})
require.EqualError(t, err, "unsupported file type: .txt", "unsupported file type: .txt")
require.ErrorContains(t, err, "unsupported archive format:")
}

func TestPullZstdWithSkippableFrame(t *testing.T) {
t.Parallel()

ctx := testutil.TestContext(t)
packageData, err := os.ReadFile(filepath.Join("testdata", "load-package", "compressed", "zarf-package-test-amd64-0.0.1.tar.zst"))
require.NoError(t, err)

payload := append([]byte{0x50, 0x2a, 0x4d, 0x18, 0x00, 0x00, 0x00, 0x00}, packageData...)
shasum := sha256.Sum256(payload)
srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
//nolint:errcheck // ignore
rw.Write(payload)
}))
t.Cleanup(srv.Close)

dir := t.TempDir()
pulledPath, err := Pull(ctx, srv.URL, dir, PullOptions{
SHASum: hex.EncodeToString(shasum[:]),
Architecture: "amd64",
})
require.NoError(t, err)

expectedPath := filepath.Join(dir, "zarf-package-test-amd64-0.0.1.tar.zst")
require.Equal(t, expectedPath, pulledPath)
require.FileExists(t, pulledPath)
}

func TestSupportsFiltering(t *testing.T) {
Expand Down