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: pathing issues loading images with Zarf on Windows #2106

Merged
merged 32 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1960645
initial fix for Zarf on Windows
Racer159 Oct 27, 2023
d7affc8
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Oct 31, 2023
d8cf223
Use ToSlash / FromSlash to normalize filepaths
Racer159 Oct 31, 2023
b297056
Add comments
Racer159 Oct 31, 2023
80b9e35
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Nov 1, 2023
0a4393b
Remove erroneuos warning
Racer159 Nov 1, 2023
054e3dd
Update tests for OCI to run on Windows and test slashes
Racer159 Nov 1, 2023
072a5ad
Change cache location for Windows compose test
Racer159 Nov 2, 2023
833c66f
Change Cloudflare for Github
Racer159 Nov 3, 2023
6cd7ecd
Fix reldir
Racer159 Nov 3, 2023
77a0972
Make the cache dir absolute
Racer159 Nov 3, 2023
7bcd00d
Make composing work on Windows
Racer159 Nov 3, 2023
9ebb402
Change the filepaths based on GOOS
Racer159 Nov 3, 2023
3f807de
Correct yaml spacing
Racer159 Nov 3, 2023
dc851fc
Add a helpre to normalize Windows filenames
Racer159 Nov 3, 2023
bf6cb6d
Add back in line endings
Racer159 Nov 3, 2023
c45d89c
Add the unit tests to the windows tests
Racer159 Nov 4, 2023
da6d1f9
Update paths test to be correct
Racer159 Nov 4, 2023
215bcd9
Improve tests for Windows
Racer159 Nov 4, 2023
ce9c856
Fix network tests
Racer159 Nov 4, 2023
1488f45
switch close to defer
Racer159 Nov 4, 2023
8e39ca1
Clarify what is being validated
Racer159 Nov 4, 2023
9426b94
Remove fromslash from validate and correct create and more messaging
Racer159 Nov 4, 2023
814043e
Update tests and confirm what filepath.Join does for us
Racer159 Nov 4, 2023
48de602
Update test to actually work
Racer159 Nov 4, 2023
32d68fc
Fix check annotations
Racer159 Nov 4, 2023
0f7535a
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Nov 4, 2023
88d2c2a
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Nov 6, 2023
793f217
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Nov 7, 2023
5bec1bf
fixed feedback
Racer159 Nov 7, 2023
f5335d9
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Nov 7, 2023
4893ac6
Merge branch 'main' into 2102-fix-zarf-on-windows
Racer159 Nov 7, 2023
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
16 changes: 12 additions & 4 deletions .github/actions/packages/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,26 @@ inputs:
description: 'Build the example packages'
required: false
default: 'true'
os:
description: 'Which OS to build for'
required: false
default: 'linux'
shell:
description: 'Which shell to build in'
required: false
default: 'bash'

runs:
using: composite
steps:
- run: |
make build-cli-linux-amd ARCH=amd64
shell: bash
make build-cli-${{ inputs.os }}-amd ARCH=amd64
shell: ${{ inputs.shell }}
- run: |
make init-package ARCH=amd64
shell: bash
shell: ${{ inputs.shell }}
if: ${{ inputs.init-package == 'true' }}
- run: |
make build-examples ARCH=amd64
shell: bash
shell: ${{ inputs.shell }}
if: ${{ inputs.build-examples == 'true' }}
25 changes: 14 additions & 11 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,24 @@ jobs:
- name: Setup golang
uses: ./.github/actions/golang

- name: Build windows binary
run: make build-cli-windows-amd
- name: Run Windows unit tests
run: make test-unit
shell: pwsh

# Builds an init package manually off of the v0.23.6 release since
# Windows in GitHub cannot natively build linux containers and
# the tests this workflow runs do not use the agent at all!
- name: Build Windows binary and zarf packages
uses: ./.github/actions/packages
with:
init-package: "false"
os: windows
shell: pwsh

# TODO: (@WSTARR) Builds an init package manually off of the v0.30.1
# release since Windows in GitHub cannot natively build linux containers
# and the tests this workflow run do not use the agent at all!
- name: Build init-package
run: |
make release-init-package ARCH=amd64 AGENT_IMAGE_TAG=v0.25.2

- name: Build zarf packages
run: make build-examples ARCH=amd64
shell: pwsh
make release-init-package ARCH=amd64 AGENT_IMAGE_TAG=v0.30.1

- name: Run windows tests
- name: Run windows E2E tests
run: make test-e2e ARCH=amd64 -e SKIP_K8S=true
shell: pwsh
6 changes: 3 additions & 3 deletions examples/component-actions/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ components:
- name: SNAKE_SOUND
# marks this variable as sensitive to prevent it from being output in the Zarf log
sensitive: true
# autoIndent tells Zarf to maintain spacing for any newlines when templating into a yaml file
# autoIndent tells Zarf to maintain spacing for any newlines when templating into a yaml file
autoIndent: true
# onSuccess will only run if steps in this component are successful
onSuccess:
Expand Down Expand Up @@ -185,13 +185,13 @@ components:
actions:
onCreate:
after:
- description: Cloudflare 1.1.1.1 site to be available
- description: Github.com to be available
maxTotalSeconds: 15
wait:
# wait for a network address to return a 200 OK response
network:
protocol: https
address: 1.1.1.1
address: github.com
code: 200

- name: on-deploy-with-wait-action
Expand Down
9 changes: 7 additions & 2 deletions src/pkg/layout/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ func (pp *PackagePaths) SetFromLayers(layers []ocispec.Descriptor) {
// SetFromPaths maps paths to package paths.
func (pp *PackagePaths) SetFromPaths(paths []string) {
for _, rel := range paths {
switch path := rel; {
// Convert from the standard '/' to the OS path separator for Windows support
switch path := filepath.FromSlash(rel); {
case path == ZarfYAML:
pp.ZarfYAML = filepath.Join(pp.Base, path)
case path == Signature:
Expand Down Expand Up @@ -213,16 +214,20 @@ func (pp *PackagePaths) SetFromPaths(paths []string) {
// Files returns a map of all the files in the package.
func (pp *PackagePaths) Files() map[string]string {
pathMap := make(map[string]string)

stripBase := func(path string) string {
rel, _ := filepath.Rel(pp.Base, path)
return rel
// Convert from the OS path separator to the standard '/' for Windows support
return filepath.ToSlash(rel)
}

add := func(path string) {
if path == "" {
return
}
pathMap[stripBase(path)] = path
}

add(pp.ZarfYAML)
add(pp.Signature)
add(pp.Checksums)
Expand Down
78 changes: 44 additions & 34 deletions src/pkg/layout/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package layout

import (
"runtime"
"strings"
"testing"

Expand All @@ -17,10 +18,10 @@ func TestPackageFiles(t *testing.T) {

raw := &PackagePaths{
Base: "test",
ZarfYAML: "test/zarf.yaml",
Checksums: "test/checksums.txt",
ZarfYAML: normalizePath("test/zarf.yaml"),
Checksums: normalizePath("test/checksums.txt"),
Components: Components{
Base: "test/components",
Base: normalizePath("test/components"),
},
}

Expand All @@ -29,8 +30,8 @@ func TestPackageFiles(t *testing.T) {
files := pp.Files()

expected := map[string]string{
"zarf.yaml": "test/zarf.yaml",
"checksums.txt": "test/checksums.txt",
"zarf.yaml": normalizePath("test/zarf.yaml"),
"checksums.txt": normalizePath("test/checksums.txt"),
}

require.Equal(t, expected, files)
Expand All @@ -47,23 +48,23 @@ func TestPackageFiles(t *testing.T) {
files = pp.Files()

expected = map[string]string{
"zarf.yaml": "test/zarf.yaml",
"checksums.txt": "test/checksums.txt",
"zarf.yaml.sig": "test/zarf.yaml.sig",
"zarf.yaml": normalizePath("test/zarf.yaml"),
"checksums.txt": normalizePath("test/checksums.txt"),
"zarf.yaml.sig": normalizePath("test/zarf.yaml.sig"),
}

require.Equal(t, expected, files)

pp = pp.AddImages()

files = pp.Files()

// Note that the map key will always be the forward "Slash" (/) version of the file path (never \)
expected = map[string]string{
"zarf.yaml": "test/zarf.yaml",
"checksums.txt": "test/checksums.txt",
"zarf.yaml.sig": "test/zarf.yaml.sig",
"images/index.json": "test/images/index.json",
"images/oci-layout": "test/images/oci-layout",
"zarf.yaml": normalizePath("test/zarf.yaml"),
"checksums.txt": normalizePath("test/checksums.txt"),
"zarf.yaml.sig": normalizePath("test/zarf.yaml.sig"),
"images/index.json": normalizePath("test/images/index.json"),
"images/oci-layout": normalizePath("test/images/oci-layout"),
}

require.Equal(t, expected, files)
Expand All @@ -79,10 +80,10 @@ func TestPackageFiles(t *testing.T) {
"zarf.yaml",
"checksums.txt",
"sboms.tar",
"components/c1.tar",
"images/index.json",
"images/oci-layout",
"images/blobs/sha256/" + strings.Repeat("1", 64),
normalizePath("components/c1.tar"),
normalizePath("images/index.json"),
normalizePath("images/oci-layout"),
normalizePath("images/blobs/sha256/" + strings.Repeat("1", 64)),
}

pp = New("test")
Expand All @@ -92,13 +93,13 @@ func TestPackageFiles(t *testing.T) {
files = pp.Files()

expected = map[string]string{
"zarf.yaml": "test/zarf.yaml",
"checksums.txt": "test/checksums.txt",
"sboms.tar": "test/sboms.tar",
"components/c1.tar": "test/components/c1.tar",
"images/index.json": "test/images/index.json",
"images/oci-layout": "test/images/oci-layout",
"images/blobs/sha256/" + strings.Repeat("1", 64): "test/images/blobs/sha256/" + strings.Repeat("1", 64),
"zarf.yaml": normalizePath("test/zarf.yaml"),
"checksums.txt": normalizePath("test/checksums.txt"),
"sboms.tar": normalizePath("test/sboms.tar"),
"components/c1.tar": normalizePath("test/components/c1.tar"),
"images/index.json": normalizePath("test/images/index.json"),
"images/oci-layout": normalizePath("test/images/oci-layout"),
"images/blobs/sha256/" + strings.Repeat("1", 64): normalizePath("test/images/blobs/sha256/" + strings.Repeat("1", 64)),
}

require.Len(t, pp.Images.Blobs, 1)
Expand All @@ -123,16 +124,25 @@ func TestPackageFiles(t *testing.T) {
files = pp.Files()

expected = map[string]string{
"zarf.yaml": "test/zarf.yaml",
"checksums.txt": "test/checksums.txt",
"sboms.tar": "test/sboms.tar",
"components/c1.tar": "test/components/c1.tar",
"components/c2.tar": "test/components/c2.tar",
"images/index.json": "test/images/index.json",
"images/oci-layout": "test/images/oci-layout",
"images/blobs/sha256/" + strings.Repeat("1", 64): "test/images/blobs/sha256/" + strings.Repeat("1", 64),
"images/blobs/sha256/" + strings.Repeat("2", 64): "test/images/blobs/sha256/" + strings.Repeat("2", 64),
"zarf.yaml": normalizePath("test/zarf.yaml"),
"checksums.txt": normalizePath("test/checksums.txt"),
"sboms.tar": normalizePath("test/sboms.tar"),
"components/c1.tar": normalizePath("test/components/c1.tar"),
"components/c2.tar": normalizePath("test/components/c2.tar"),
"images/index.json": normalizePath("test/images/index.json"),
"images/oci-layout": normalizePath("test/images/oci-layout"),
"images/blobs/sha256/" + strings.Repeat("1", 64): normalizePath("test/images/blobs/sha256/" + strings.Repeat("1", 64)),
"images/blobs/sha256/" + strings.Repeat("2", 64): normalizePath("test/images/blobs/sha256/" + strings.Repeat("2", 64)),
}

require.Equal(t, expected, files)
}

// normalizePath ensures that the filepaths being generated are normalized to the host OS.
func normalizePath(path string) string {
if runtime.GOOS != "windows" {
return path
}

return strings.ReplaceAll(path, "/", "\\")
}
5 changes: 3 additions & 2 deletions src/pkg/oci/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ func NewZarfOCIManifest(manifest *ocispec.Manifest) *ZarfOCIManifest {
}

// Locate returns the descriptor for the first layer with the given path or digest.
func (m *ZarfOCIManifest) Locate(uri string) ocispec.Descriptor {
func (m *ZarfOCIManifest) Locate(pathOrDigest string) ocispec.Descriptor {
return helpers.Find(m.Layers, func(layer ocispec.Descriptor) bool {
return layer.Annotations[ocispec.AnnotationTitle] == uri || layer.Digest.Encoded() == uri
// Convert from the OS path separator to the standard '/' for Windows support
return layer.Annotations[ocispec.AnnotationTitle] == filepath.ToSlash(pathOrDigest) || layer.Digest.Encoded() == pathOrDigest
})
}

Expand Down
9 changes: 7 additions & 2 deletions src/pkg/oci/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ var (

// FileDescriptorExists returns true if the given file exists in the given directory with the expected SHA.
func (o *OrasRemote) FileDescriptorExists(desc ocispec.Descriptor, destinationDir string) bool {
destinationPath := filepath.Join(destinationDir, desc.Annotations[ocispec.AnnotationTitle])
rel := desc.Annotations[ocispec.AnnotationTitle]
destinationPath := filepath.Join(destinationDir, rel)

info, err := os.Stat(destinationPath)
if err != nil {
return false
Expand Down Expand Up @@ -252,7 +254,10 @@ func (o *OrasRemote) PullLayer(desc ocispec.Descriptor, destinationDir string) e
if err != nil {
return err
}
return utils.WriteFile(filepath.Join(destinationDir, desc.Annotations[ocispec.AnnotationTitle]), b)

rel := desc.Annotations[ocispec.AnnotationTitle]

return utils.WriteFile(filepath.Join(destinationDir, rel), b)
}

// PullPackagePaths pulls multiple files from the remote repository and saves them to `destinationDir`.
Expand Down
2 changes: 0 additions & 2 deletions src/pkg/packager/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,6 @@ func (p *Packager) attemptClusterChecks() (err error) {
if existingInitPackage, _ := p.cluster.GetDeployedPackage("init"); existingInitPackage != nil {
// Use the build version instead of the metadata since this will support older Zarf versions
deprecated.PrintBreakingChanges(existingInitPackage.Data.Build.Version)
} else {
message.Warnf("Unable to retrieve the initialized Zarf version. There is potential for breaking changes.")
}

spinner.Success()
Expand Down
8 changes: 4 additions & 4 deletions src/pkg/packager/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ func (p *Packager) composeComponents() error {
// filter by architecture
if !composer.CompatibleComponent(component, arch, p.cfg.CreateOpts.Flavor) {
continue
} else {
// if a match was found, strip flavor and architecture to reduce bloat in the package definition
component.Only.Cluster.Architecture = ""
component.Only.Flavor = ""
}

// if a match was found, strip flavor and architecture to reduce bloat in the package definition
component.Only.Cluster.Architecture = ""
component.Only.Flavor = ""

// build the import chain
chain, err := composer.NewImportChain(component, arch, p.cfg.CreateOpts.Flavor)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions src/pkg/packager/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,7 @@ func (p *Packager) generatePackageChecksums() (string, error) {
if rel == layout.ZarfYAML || rel == layout.Checksums {
continue
}

sum, err := utils.GetSHA256OfFile(abs)
if err != nil {
return "", err
Expand Down
21 changes: 19 additions & 2 deletions src/pkg/packager/sources/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,15 @@ func (s *OCISource) LoadPackage(dst *layout.PackagePaths, unarchiveAll bool) (er
}

if !dst.IsLegacyLayout() {
spinner := message.NewProgressSpinner("Validating pulled layer checksums")
defer spinner.Stop()

if err := ValidatePackageIntegrity(dst, pkg.Metadata.AggregateChecksum, isPartial); err != nil {
return err
}

spinner.Success()

if err := ValidatePackageSignature(dst, s.PublicKeyPath); err != nil {
return err
}
Expand Down Expand Up @@ -131,8 +136,15 @@ func (s *OCISource) LoadPackageMetadata(dst *layout.PackagePaths, wantSBOM bool,
}

if !dst.IsLegacyLayout() {
if err := ValidatePackageIntegrity(dst, pkg.Metadata.AggregateChecksum, true); err != nil {
return err
if wantSBOM {
spinner := message.NewProgressSpinner("Validating SBOM checksums")
defer spinner.Stop()

if err := ValidatePackageIntegrity(dst, pkg.Metadata.AggregateChecksum, true); err != nil {
return err
}

spinner.Success()
}

if err := ValidatePackageSignature(dst, s.PublicKeyPath); err != nil {
Expand Down Expand Up @@ -176,10 +188,15 @@ func (s *OCISource) Collect(dir string) (string, error) {
return "", err
}

spinner := message.NewProgressSpinner("Validating full package checksums")
defer spinner.Stop()

if err := ValidatePackageIntegrity(loaded, pkg.Metadata.AggregateChecksum, false); err != nil {
return "", err
}

spinner.Success()

isSkeleton := strings.HasSuffix(s.Repo().Reference.Reference, oci.SkeletonSuffix)
name := NameFromMetadata(&pkg, isSkeleton)

Expand Down
Loading
Loading