Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: check public key for signed packages during zarf package pull #3347

Merged
merged 4 commits into from
Dec 18, 2024
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 src/cmd/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ func (o *PackagePullOptions) Run(cmd *cobra.Command, args []string) error {
}
outputDir = wd
}
err := packager2.Pull(cmd.Context(), args[0], outputDir, pkgConfig.PkgOpts.Shasum, filters.Empty())
err := packager2.Pull(cmd.Context(), args[0], outputDir, pkgConfig.PkgOpts.Shasum, filters.Empty(), pkgConfig.PkgOpts.PublicKeyPath)
if err != nil {
return err
}
Expand Down
15 changes: 13 additions & 2 deletions src/internal/packager2/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ import (

"github.com/zarf-dev/zarf/src/api/v1alpha1"
"github.com/zarf-dev/zarf/src/config"
"github.com/zarf-dev/zarf/src/pkg/layout"
"github.com/zarf-dev/zarf/src/internal/packager2/layout"
"github.com/zarf-dev/zarf/src/pkg/packager/filters"
"github.com/zarf-dev/zarf/src/pkg/utils"
"github.com/zarf-dev/zarf/src/pkg/zoci"
)

// Pull fetches the Zarf package from the given sources.
func Pull(ctx context.Context, src, dir, shasum string, filter filters.ComponentFilterStrategy) error {
func Pull(ctx context.Context, src, dir, shasum string, filter filters.ComponentFilterStrategy, publicKeyPath string) error {
u, err := url.Parse(src)
if err != nil {
return err
Expand Down Expand Up @@ -63,6 +63,17 @@ func Pull(ctx context.Context, src, dir, shasum string, filter filters.Component
return fmt.Errorf("unknown scheme %s", u.Scheme)
}

// This loadFromTar is done so that validatePackageIntegrtiy and validatePackageSignature are called
layoutOpt := layout.PackageLayoutOptions{
PublicKeyPath: publicKeyPath,
SkipSignatureValidation: false,
IsPartial: false,
}
_, err = layout.LoadFromTar(ctx, tmpPath, layoutOpt)
if err != nil {
return err
}

name, err := nameFromMetadata(tmpPath)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion src/internal/packager2/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestPull(t *testing.T) {

dir := t.TempDir()
shasum := "bef73d652f004d214d5cf9e00195293f7ae8390b8ff6ed45e39c2c9eb622b873"
err := Pull(ctx, srv.URL, dir, shasum, filters.Empty())
err := Pull(ctx, srv.URL, dir, shasum, filters.Empty(), "")
require.NoError(t, err)

packageData, err := os.ReadFile(packagePath)
Expand Down
41 changes: 23 additions & 18 deletions src/test/e2e/11_oci_pull_inspect_test.go
Copy link
Contributor Author

@AustinAbro321 AustinAbro321 Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored this test to create and publish the package to an in memory registry, this way we don't rely on external private keys or external infrastructure. Added a test to ensure pulling the package without a public key fails and verified that it does fail on main.

Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ package test

import (
"fmt"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/zarf-dev/zarf/src/test/testutil"
"oras.land/oras-go/v2/registry"
)

type PullInspectTestSuite struct {
suite.Suite
*require.Assertions
Reference registry.Reference
PackagesDir string
Reference registry.Reference
}

var badPullInspectRef = registry.Reference{
Expand All @@ -28,34 +29,38 @@ var badPullInspectRef = registry.Reference{

func (suite *PullInspectTestSuite) SetupSuite() {
suite.Assertions = require.New(suite.T())
suite.PackagesDir = "build"
}

func (suite *PullInspectTestSuite) TearDownSuite() {
local := fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)
e2e.CleanFiles(suite.T(), local)
suite.Reference.Registry = testutil.SetupInMemoryRegistry(testutil.TestContext(suite.T()), suite.T(), 31888)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL testutil.SetupInMemoryRegistry

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's very useful for unit tests as well, once the create refactor is merged, we should be able to make tests for publish and pull with unit tests

}

func (suite *PullInspectTestSuite) Test_0_Pull() {
suite.T().Log("E2E: Package Pull oci://")

out := fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)
privateKeyFlag := "--signing-key=src/test/packages/zarf-test.prv-key"
publicKeyFlag := "--key=src/test/packages/zarf-test.pub"

// Build the fully qualified reference.
ref := fmt.Sprintf("oci://ghcr.io/zarf-dev/packages/dos-games:1.0.0-%s", e2e.Arch)
outputPath := suite.T().TempDir()
stdOut, stdErr, err := e2e.Zarf(suite.T(), "package", "create", "src/test/packages/11-simple-package", "-o", outputPath, privateKeyFlag, "--confirm")
suite.NoError(err, stdOut, stdErr)

// Pull the package via OCI.
stdOut, stdErr, err := e2e.Zarf(suite.T(), "package", "pull", ref)
out := filepath.Join(outputPath, fmt.Sprintf("zarf-package-simple-package-%s-0.0.1.tar.zst", e2e.Arch))
ref := suite.Reference.String()
stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "publish", out, "oci://"+ref, "--plain-http", publicKeyFlag)
suite.NoError(err, stdOut, stdErr)

sbomTmp := suite.T().TempDir()
simplePackageRef := fmt.Sprintf("oci://%s/simple-package:0.0.1", ref)
// fail to pull the package without providing the public key
stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "pull", simplePackageRef, "--plain-http")
suite.Error(err, stdOut, stdErr)

stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "pull", simplePackageRef, "--plain-http", publicKeyFlag)
suite.NoError(err, stdOut, stdErr)

stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", simplePackageRef, "--plain-http")
suite.Error(err, stdOut, stdErr)

// Verify the package was pulled correctly.
suite.FileExists(out)
stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", out, "--key", "https://raw.githubusercontent.com/zarf-dev/zarf/v0.38.2/cosign.pub", "--sbom-out", sbomTmp)
stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", simplePackageRef, "--plain-http", publicKeyFlag, "--sbom-out", suite.T().TempDir())
suite.NoError(err, stdOut, stdErr)

// Test pull w/ bad ref.
stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+badPullInspectRef.String(), "--plain-http")
suite.Error(err, stdOut, stdErr)
}
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions src/test/packages/11-simple-package/zarf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
kind: ZarfPackageConfig
metadata:
name: simple-package
description: simple small package to test pullling, publishing, and inspecting
version: 0.0.1

components:
- name: on-deploy-with-template-use-of-variable
required: true
files:
- source: test.txt
target: test.txt
Loading