diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46142d5b..c0482cf5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: git diff --exit-code -- go.mod go.sum - name: Build Source - run: go run ./magefiles/mage.go build:source + run: go build ./... - name: Install Lint uses: golangci/golangci-lint-action@v2 @@ -44,7 +44,7 @@ jobs: golangci-lint run - name: Run Tests - run: go run ./magefiles/mage.go cover:unit cover.out + run: go test -coverprofile cover.out -race ./... - name: Upload coverage report uses: codecov/codecov-action@v2 diff --git a/.golangci.yml b/.golangci.yml index bc922c1e..5e9952b1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,10 +2,6 @@ # For website terms of use, trademark policy, privacy policy and other # project policies see https://lfprojects.org/policies -run: - build-tags: - - mage - linters: disable-all: true enable: diff --git a/.goreleaser.yml b/.goreleaser.yml index f0f84886..3ee14c5d 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -71,4 +71,7 @@ archives: - linux-builds sboms: - - artifacts: archive + - documents: + - '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}.bom.cdx.json' + artifacts: binary + args: ["$artifact", "--file", "$document", "--output", "cyclonedx-json"] diff --git a/README.md b/README.md index e5fb8b28..4d165032 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build Status](https://github.com/apptainer/sif/actions/workflows/ci.yml/badge.svg)](https://github.com/apptainer/sif/actions/workflows/ci.yml) [![Code Coverage](https://codecov.io/gh/apptainer/sif/branch/master/graph/badge.svg)](https://codecov.io/gh/apptainer/sif) [![Go Report Card](https://goreportcard.com/badge/github.com/apptainer/sif)](https://goreportcard.com/report/github.com/apptainer/sif) -[![Built with Mage](https://magefile.org/badge.svg)](https://magefile.org) +[![Powered By GoReleaser](https://img.shields.io/badge/powered%20by-goreleaser-green.svg)](https://github.com/goreleaser) This module contains an open source implementation of the Singularity Image Format (SIF) that makes it easy to create complete and @@ -15,22 +15,9 @@ encapsulated container environments stored in a single file. Unless otherwise noted, the SIF source files are distributed under the BSD-style license found in the [LICENSE.md](LICENSE.md) file. -## Download and Install From Source +## Install Siftool -To get the sif package to use directly from your programs: - -```sh -go get -d github.com/apptainer/sif/v2 -``` - -To get the siftool CLI program installed to `$(go env GOPATH)/bin` to -manipulate SIF container files: - -```sh -git clone https://github.com/apptainer/sif -cd sif -go run ./magefiles/mage.go install -``` +Pre-built binaries are available with the [latest release](https://github.com/apptainer/sif/releases). ## Go Version Compatibility diff --git a/cmd/siftool/siftool.go b/cmd/siftool/siftool.go index 84e914f0..2151417f 100644 --- a/cmd/siftool/siftool.go +++ b/cmd/siftool/siftool.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2018-2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2018-2022, Sylabs Inc. All rights reserved. // Copyright (c) 2017, SingularityWare, LLC. All rights reserved. // Copyright (c) 2017, Yannick Cote All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the @@ -16,6 +16,7 @@ import ( "io" "os" "runtime" + "strconv" "text/tabwriter" "github.com/apptainer/sif/v2/pkg/sif" @@ -28,7 +29,6 @@ var ( date = "" builtBy = "" commit = "" - state = "" ) func writeVersion(w io.Writer) error { @@ -42,11 +42,7 @@ func writeVersion(w io.Writer) error { } if commit != "" { - if state == "" { - fmt.Fprintf(tw, "Commit:\t%v\n", commit) - } else { - fmt.Fprintf(tw, "Commit:\t%v (%v)\n", commit, state) - } + fmt.Fprintf(tw, "Commit:\t%v\n", commit) } if date != "" { @@ -83,7 +79,16 @@ possible to modify a SIF file via this tool via the add/del commands.`, root.AddCommand(getVersion()) - if err := siftool.AddCommands(&root); err != nil { + var experimental bool + if val, ok := os.LookupEnv("SIFTOOL_EXPERIMENTAL"); ok { + b, err := strconv.ParseBool(val) + if err != nil { + fmt.Fprintln(os.Stderr, "Error: failed to parse SIFTOOL_EXPERIMENTAL environment variable:", err) + } + experimental = b + } + + if err := siftool.AddCommands(&root, siftool.OptWithExperimental(experimental)); err != nil { fmt.Fprintln(os.Stderr, "Error:", err) os.Exit(1) } diff --git a/go.mod b/go.mod index a54c7997..6c29fa86 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,10 @@ module github.com/apptainer/sif/v2 go 1.17 require ( - github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f + github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 github.com/blang/semver/v4 v4.0.0 github.com/go-git/go-git/v5 v5.4.2 github.com/google/uuid v1.3.0 - github.com/magefile/mage v1.13.0 github.com/sebdah/goldie/v2 v2.5.3 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 @@ -28,7 +27,7 @@ require ( github.com/sergi/go-diff v1.1.0 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect - golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect - golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect + golang.org/x/net v0.0.0-20210326060303-6b1517762897 // indirect + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 55c96e7a..3a09e9a8 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f h1:J2FzIrXN82q5uyUraeJpLIm7U6PffRwje2ORho5yIik= -github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 h1:cSHEbLj0GZeHM1mWG84qEnGFojNEQ83W7cwaPRjcwXU= +github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= @@ -52,8 +52,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magefile/mage v1.13.0 h1:XtLJl8bcCM7EFoO8FyH8XK3t7G5hQAeK+i4tq+veT9M= -github.com/magefile/mage v1.13.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -90,9 +88,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -100,16 +97,13 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/app/siftool/app.go b/internal/app/siftool/app.go index e9c69405..f0865f8e 100644 --- a/internal/app/siftool/app.go +++ b/internal/app/siftool/app.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -17,6 +17,7 @@ import ( // appOpts contains configured options. type appOpts struct { out io.Writer + err io.Writer } // AppOpt are used to configure optional behavior. @@ -35,11 +36,23 @@ func OptAppOutput(w io.Writer) AppOpt { } } +// OptAppError specifies that errors should be written to w. +func OptAppError(w io.Writer) AppOpt { + return func(o *appOpts) error { + o.err = w + return nil + } +} + // New creates a new App configured with opts. +// +// By default, application output and errors are written to os.Stdout and os.Stderr respectively. +// To modify this behavior, consider using OptAppOutput and/or OptAppError. func New(opts ...AppOpt) (*App, error) { a := App{ opts: appOpts{ out: os.Stdout, + err: os.Stderr, }, } diff --git a/internal/app/siftool/mount.go b/internal/app/siftool/mount.go new file mode 100644 index 00000000..1287c61c --- /dev/null +++ b/internal/app/siftool/mount.go @@ -0,0 +1,24 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package siftool + +import ( + "context" + + "github.com/apptainer/sif/v2/pkg/user" +) + +// Mount mounts the primary system partition of the SIF file at path into mountPath. +func (a *App) Mount(ctx context.Context, path, mountPath string) error { + return user.Mount(ctx, path, mountPath, + user.OptMountStdout(a.opts.out), + user.OptMountStderr(a.opts.err), + ) +} diff --git a/internal/app/siftool/testdata/TestApp_Dump/Three.golden b/internal/app/siftool/testdata/TestApp_Dump/Three.golden index 6d1002b2..4e354d95 100644 --- a/internal/app/siftool/testdata/TestApp_Dump/Three.golden +++ b/internal/app/siftool/testdata/TestApp_Dump/Three.golden @@ -1,15 +1,15 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 -{"version":1,"header":{"digest":"sha256:635fa0a14a8ef0c0351ed3e985799ed1d4f75ce973dea3cc76c99710795cc3f1"},"objects":[{"relativeId":0,"descriptorDigest":"sha256:3634ad01db0dd5482ecf685267b53d6201690438ca27c3d7ea91c971a1f41f92","objectDigest":"sha256:004dfc8da678c309de28b5386a1e9efd57f536b150c40d29b31506aa0fb17ec2"},{"relativeId":1,"descriptorDigest":"sha256:db74cb63348414def73535c9f0f83e8ad7df61229ed2806f4da8b69d6d7464d6","objectDigest":"sha256:5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953"}]} +{"version":1,"header":{"digest":"sha256:635fa0a14a8ef0c0351ed3e985799ed1d4f75ce973dea3cc76c99710795cc3f1"},"objects":[{"relativeId":0,"descriptorDigest":"sha256:3634ad01db0dd5482ecf685267b53d6201690438ca27c3d7ea91c971a1f41f92","objectDigest":"sha256:004dfc8da678c309de28b5386a1e9efd57f536b150c40d29b31506aa0fb17ec2"},{"relativeId":1,"descriptorDigest":"sha256:04b5f87c9692a54f80d10fb6af00c779763aeca29d610348854bd97cd8bf66fd","objectDigest":"sha256:9f9c4e5e131934969b4ac8f495691c70b8c6c8e3f489c2c9ab5f1af82bce0604"}]} -----BEGIN PGP SIGNATURE----- wsBzBAEBCAAnBQJe+oD0CZCiDCfuf/e6hBYhBBIEXIwLEATQWN5L7aIMJ+5/97qE -AADY9ggAlW/Y+BssNOLcCAiu0dzZCf5BfbzmOUQ+VNajAsZyOIJnW1t19lDYoRNx -x3YolyyRfEmw9Kf1n6fctDHGPyzRIIOc1/0CVQzNzfKZQO+x0+9qvurILADijY/3 -1DKqhbxoO2a5iASXYHH9yYs3J82N3EKEYyFdDMTcHs4UijUnHvwcTt0smY6JQ9Su -vssWg+3qltuVjiYOQPgg9XR5i8suXE76poit9Ftp7jOD9eYtVcUEKRZLrVCsDJu9 -77QvejJmgquueYX4pM2EuH9EOFnDV3gl4Cuocsn5OLDgfhYuT1t5Hay1iAPpJqm6 -/EXQY7CECByIj6TCFurfXwc+uYSD9Q== -=rZoe +AAC46gf/VXyzZ649nttrX13JkM5kRVPlAIblBQxfoUxA1xwIXdRoM5ceDY0Em+YD +8b6Xl1w2sDTqo0R15cJSh8sf0ClFOvYpDQRNCwKx17k1Wd0gHcW4QVu6gJnlbNvN +o/EJdEN2TkbCM2aFvj34DAIfErRBIEsCeDDvJ/6WUSySWbnydfNU2pCsnK4A7l2H +KOXFzSaPijG9L/pU3O3vNZ+fXPffqHL9JVhs5Mt/Yo3oeoEnoVaKvJLGx/fyl+Gj +7qsfWFyHWzRCww9VFg/TCBeUku0CYRfXhxOgo4OuHNr8oo82rKDZU6+l3UZ2Sw8T ++kLe/zUkaILocGOvhvKdi630OGGb/Q== +=3Jq2 -----END PGP SIGNATURE----- \ No newline at end of file diff --git a/internal/app/siftool/testdata/TestApp_Dump/Two.golden b/internal/app/siftool/testdata/TestApp_Dump/Two.golden index 7d174b13..cf6539a5 100644 Binary files a/internal/app/siftool/testdata/TestApp_Dump/Two.golden and b/internal/app/siftool/testdata/TestApp_Dump/Two.golden differ diff --git a/internal/app/siftool/testdata/TestApp_Header/OneGroup.golden b/internal/app/siftool/testdata/TestApp_Header/OneGroup.golden index bc631d68..a2941c12 100644 --- a/internal/app/siftool/testdata/TestApp_Header/OneGroup.golden +++ b/internal/app/siftool/testdata/TestApp_Header/OneGroup.golden @@ -5,4 +5,4 @@ Descriptors Total: 48 Descriptors Offset: 4096 Descriptors Size: 27 KiB Data Offset: 32176 -Data Size: 5 KiB +Data Size: 9 KiB diff --git a/internal/app/siftool/testdata/TestApp_Header/TwoGroups.golden b/internal/app/siftool/testdata/TestApp_Header/TwoGroups.golden index 0db18f03..c16ef18c 100644 --- a/internal/app/siftool/testdata/TestApp_Header/TwoGroups.golden +++ b/internal/app/siftool/testdata/TestApp_Header/TwoGroups.golden @@ -5,4 +5,4 @@ Descriptors Total: 48 Descriptors Offset: 4096 Descriptors Size: 27 KiB Data Offset: 32176 -Data Size: 9 KiB +Data Size: 265 KiB diff --git a/internal/app/siftool/testdata/TestApp_Header/TwoGroupsSigned.golden b/internal/app/siftool/testdata/TestApp_Header/TwoGroupsSigned.golden index acf8b173..8a9d0134 100644 --- a/internal/app/siftool/testdata/TestApp_Header/TwoGroupsSigned.golden +++ b/internal/app/siftool/testdata/TestApp_Header/TwoGroupsSigned.golden @@ -5,4 +5,4 @@ Descriptors Total: 48 Descriptors Offset: 4096 Descriptors Size: 27 KiB Data Offset: 32176 -Data Size: 17 KiB +Data Size: 269 KiB diff --git a/internal/app/siftool/testdata/TestApp_Info/DataPartitionEXT3.golden b/internal/app/siftool/testdata/TestApp_Info/DataPartitionEXT3.golden index 34e9dde7..4fec1ec9 100644 --- a/internal/app/siftool/testdata/TestApp_Info/DataPartitionEXT3.golden +++ b/internal/app/siftool/testdata/TestApp_Info/DataPartitionEXT3.golden @@ -3,7 +3,7 @@ Group ID: 2 Linked ID: NONE Offset: 40960 - Size: 4 + Size: 262144 Filesystem Type: Ext3 Partition Type: System Architecture: amd64 diff --git a/internal/app/siftool/testdata/TestApp_Info/DataPartitionSquashFS.golden b/internal/app/siftool/testdata/TestApp_Info/DataPartitionSquashFS.golden index f34651f4..f49a5547 100644 --- a/internal/app/siftool/testdata/TestApp_Info/DataPartitionSquashFS.golden +++ b/internal/app/siftool/testdata/TestApp_Info/DataPartitionSquashFS.golden @@ -3,7 +3,7 @@ Group ID: 1 Linked ID: NONE Offset: 36864 - Size: 4 + Size: 4096 Filesystem Type: Squashfs Partition Type: *System Architecture: 386 diff --git a/internal/app/siftool/testdata/TestApp_Info/DataSignature.golden b/internal/app/siftool/testdata/TestApp_Info/DataSignature.golden index 411f3def..cb2859f7 100644 --- a/internal/app/siftool/testdata/TestApp_Info/DataSignature.golden +++ b/internal/app/siftool/testdata/TestApp_Info/DataSignature.golden @@ -2,7 +2,7 @@ ID: 4 Group ID: NONE Linked ID: 1 (G) - Offset: 45056 + Offset: 303104 Size: 1054 Hash Type: SHA-256 Entity: 12045C8C0B1004D058DE4BEDA20C27EE7FF7BA84 diff --git a/internal/app/siftool/testdata/TestApp_List/OneGroup.golden b/internal/app/siftool/testdata/TestApp_List/OneGroup.golden index fe78f62c..01400f9b 100644 --- a/internal/app/siftool/testdata/TestApp_List/OneGroup.golden +++ b/internal/app/siftool/testdata/TestApp_List/OneGroup.golden @@ -2,4 +2,4 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) diff --git a/internal/app/siftool/testdata/TestApp_List/OneGroupSigned.golden b/internal/app/siftool/testdata/TestApp_List/OneGroupSigned.golden index 98030e3a..5b663d3e 100644 --- a/internal/app/siftool/testdata/TestApp_List/OneGroupSigned.golden +++ b/internal/app/siftool/testdata/TestApp_List/OneGroupSigned.golden @@ -2,5 +2,5 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) 3 |NONE |1 (G) |40960-42014 |Signature (SHA-256) diff --git a/internal/app/siftool/testdata/TestApp_List/TwoGroups.golden b/internal/app/siftool/testdata/TestApp_List/TwoGroups.golden index 648c2801..1eca2ab2 100644 --- a/internal/app/siftool/testdata/TestApp_List/TwoGroups.golden +++ b/internal/app/siftool/testdata/TestApp_List/TwoGroups.golden @@ -2,5 +2,5 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) -3 |2 |NONE |40960-40964 |FS (Ext3/System/amd64) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) +3 |2 |NONE |40960-303104 |FS (Ext3/System/amd64) diff --git a/internal/app/siftool/testdata/TestApp_List/TwoGroupsSigned.golden b/internal/app/siftool/testdata/TestApp_List/TwoGroupsSigned.golden index f21bf6d0..b6793575 100644 --- a/internal/app/siftool/testdata/TestApp_List/TwoGroupsSigned.golden +++ b/internal/app/siftool/testdata/TestApp_List/TwoGroupsSigned.golden @@ -2,7 +2,7 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) -3 |2 |NONE |40960-40964 |FS (Ext3/System/amd64) -4 |NONE |1 (G) |45056-46110 |Signature (SHA-256) -5 |NONE |2 (G) |49152-50007 |Signature (SHA-256) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) +3 |2 |NONE |40960-303104 |FS (Ext3/System/amd64) +4 |NONE |1 (G) |303104-304158 |Signature (SHA-256) +5 |NONE |2 (G) |307200-308055 |Signature (SHA-256) diff --git a/magefiles/mage.go b/internal/app/siftool/unmount.go similarity index 56% rename from magefiles/mage.go rename to internal/app/siftool/unmount.go index a8104792..915df3f9 100644 --- a/magefiles/mage.go +++ b/internal/app/siftool/unmount.go @@ -2,19 +2,23 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. +// Copyright (c) 2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. -//go:build ignore - -package main +package siftool import ( - "os" + "context" - "github.com/magefile/mage/mage" + "github.com/apptainer/sif/v2/pkg/user" ) -func main() { os.Exit(mage.Main()) } +// Unmounts the filesystem at mountPath. +func (a *App) Unmount(ctx context.Context, mountPath string) error { + return user.Unmount(ctx, mountPath, + user.OptUnmountStdout(a.opts.out), + user.OptUnmountStderr(a.opts.err), + ) +} diff --git a/magefiles/magefile.go b/magefiles/magefile.go deleted file mode 100644 index f2e8a605..00000000 --- a/magefiles/magefile.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Contributors to the Apptainer project, established as -// Apptainer a Series of LF Projects LLC. -// For website terms of use, trademark policy, privacy policy and other -// project policies see https://lfprojects.org/policies -// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. -// This software is licensed under a 3-clause BSD license. Please consult the -// LICENSE file distributed with the sources of this project regarding your -// rights to use or distribute this software. - -//go:build mage - -package main - -import ( - "fmt" - "os" - "strings" - "time" - - "github.com/apptainer/sif/v2/internal/pkg/git" - "github.com/magefile/mage/mg" - "github.com/magefile/mage/sh" -) - -// Aliases defines command-line aliases exposed by Mage. -//nolint:deadcode -var Aliases = map[string]interface{}{ - "build": Build.All, - "cover": Cover.All, - "install": Install.All, - "test": Test.All, -} - -// env returns the environment to use when running Go commands. -func env() map[string]string { - return map[string]string{"CGO_ENABLED": "0"} -} - -// ldFlags returns linker flags to pass to various Go commands. -func ldFlags() string { - vals := []string{"-s", "-w", "-X", "main.builtBy=mage"} - - // Attempt to get git details. - if d, err := git.Describe("."); err == nil { - vals = append(vals, "-X", fmt.Sprintf("main.commit=%v", d.CommitHash())) - - if d.IsClean() { - vals = append(vals, - "-X", fmt.Sprintf("main.date=%v", d.CommitTime().UTC().Format(time.RFC3339)), - "-X", "main.state=clean", - ) - } else { - vals = append(vals, - "-X", fmt.Sprintf("main.date=%v", time.Now().UTC().Format(time.RFC3339)), - "-X", "main.state=dirty", - ) - } - - if v, err := d.Version(); err == nil { - vals = append(vals, "-X", fmt.Sprintf("main.version=%v", v)) - } else { - fmt.Fprintf(os.Stderr, "warning: failed to get version: %v\n", err) - } - } else { - fmt.Fprintf(os.Stderr, "warning: failed to describe git HEAD: %v\n", err) - - vals = append(vals, "-X", fmt.Sprintf("main.date=%v", time.Now().UTC().Format(time.RFC3339))) - } - - return strings.Join(vals, " ") -} - -type Build mg.Namespace - -// All compiles all assets. -func (ns Build) All() { - mg.Deps(ns.Source) -} - -// Source compiles all source code. -func (Build) Source() error { - return sh.RunWith(env(), mg.GoCmd(), "build", "-trimpath", "-ldflags", ldFlags(), "./...") -} - -type Install mg.Namespace - -// All installs all assets. -func (ns Install) All() { - mg.Deps(ns.Bin) -} - -// Bin installs binary to GOBIN. -func (Install) Bin() error { - return sh.RunWith(env(), mg.GoCmd(), "install", "-trimpath", "-ldflags", ldFlags(), "./cmd/siftool") -} - -type Test mg.Namespace - -// All runs all tests. -func (ns Test) All() { - mg.Deps(ns.Unit) -} - -// Unit runs all unit tests. -func (Test) Unit() error { - return sh.RunV(mg.GoCmd(), "test", "-race", "-cover", "./...") -} - -type Cover mg.Namespace - -// All runs all tests, writing coverage profile to the specified path. -func (ns Cover) All(path string) { - mg.Deps(mg.F(ns.Unit, path)) -} - -// Unit runs all unit tests, writing coverage profile to the specified path. -func (Cover) Unit(path string) error { - return sh.RunV(mg.GoCmd(), "test", "-race", "-coverprofile", path, "./...") -} diff --git a/pkg/integrity/testdata/TestGetImageMetadata/Object2.golden b/pkg/integrity/testdata/TestGetImageMetadata/Object2.golden index 9485be48..181f464a 100644 --- a/pkg/integrity/testdata/TestGetImageMetadata/Object2.golden +++ b/pkg/integrity/testdata/TestGetImageMetadata/Object2.golden @@ -1 +1 @@ -{"version":1,"header":{"digest":"sha1:86696357e7806b51baf75fc0bf9b8fc677e5cdd0"},"objects":[{"relativeId":1,"descriptorDigest":"sha1:ddf7e6609fec1f565545207f28d4b39f499d78c5","objectDigest":"sha1:d78f8bb992a56a597f6c7a1fb918bb78271367eb"}]} +{"version":1,"header":{"digest":"sha1:86696357e7806b51baf75fc0bf9b8fc677e5cdd0"},"objects":[{"relativeId":1,"descriptorDigest":"sha1:076d6ec6e32a6237d838ba20c825c6caa4c78544","objectDigest":"sha1:fd526afdbdea7c87d81c33314b0e0dbdfa5ba79f"}]} diff --git a/pkg/integrity/testdata/TestGetImageMetadata/SHA1.golden b/pkg/integrity/testdata/TestGetImageMetadata/SHA1.golden index 7d86f1a3..a474a502 100644 --- a/pkg/integrity/testdata/TestGetImageMetadata/SHA1.golden +++ b/pkg/integrity/testdata/TestGetImageMetadata/SHA1.golden @@ -1 +1 @@ -{"version":1,"header":{"digest":"sha1:86696357e7806b51baf75fc0bf9b8fc677e5cdd0"},"objects":[{"relativeId":0,"descriptorDigest":"sha1:1406a1a9c75a332fc50cb8519a9a7f9f2531480e","objectDigest":"sha1:15146b9bf4f1f5f9bf176a398d8c4f0321c63064"},{"relativeId":1,"descriptorDigest":"sha1:ddf7e6609fec1f565545207f28d4b39f499d78c5","objectDigest":"sha1:d78f8bb992a56a597f6c7a1fb918bb78271367eb"}]} +{"version":1,"header":{"digest":"sha1:86696357e7806b51baf75fc0bf9b8fc677e5cdd0"},"objects":[{"relativeId":0,"descriptorDigest":"sha1:1406a1a9c75a332fc50cb8519a9a7f9f2531480e","objectDigest":"sha1:15146b9bf4f1f5f9bf176a398d8c4f0321c63064"},{"relativeId":1,"descriptorDigest":"sha1:076d6ec6e32a6237d838ba20c825c6caa4c78544","objectDigest":"sha1:fd526afdbdea7c87d81c33314b0e0dbdfa5ba79f"}]} diff --git a/pkg/integrity/testdata/TestGetImageMetadata/SHA224.golden b/pkg/integrity/testdata/TestGetImageMetadata/SHA224.golden index 82dbc777..457318d0 100644 --- a/pkg/integrity/testdata/TestGetImageMetadata/SHA224.golden +++ b/pkg/integrity/testdata/TestGetImageMetadata/SHA224.golden @@ -1 +1 @@ -{"version":1,"header":{"digest":"sha224:88ecbdbaa9bf8410c9362213ddae5e6771fd2525da3eb390300fb666"},"objects":[{"relativeId":0,"descriptorDigest":"sha224:8ac2ffbf24282ce5f49fc591eee1e0a879b0ae2a9fa813b897b94113","objectDigest":"sha224:071bce5faa03c2016d3e1e086ccb60b6ea3cabc493c9aa1013594efd"},{"relativeId":1,"descriptorDigest":"sha224:fc5b7f5b3622982bcebfbb8b3a0d81b6f850228f2ff3631d03deaab6","objectDigest":"sha224:55b9eee5f60cc362ddc07676f620372611e22272f60fdbec94f243f8"}]} +{"version":1,"header":{"digest":"sha224:88ecbdbaa9bf8410c9362213ddae5e6771fd2525da3eb390300fb666"},"objects":[{"relativeId":0,"descriptorDigest":"sha224:8ac2ffbf24282ce5f49fc591eee1e0a879b0ae2a9fa813b897b94113","objectDigest":"sha224:071bce5faa03c2016d3e1e086ccb60b6ea3cabc493c9aa1013594efd"},{"relativeId":1,"descriptorDigest":"sha224:15f2307c74c24b5aff01556df7642009a968ad717514da242821b1cb","objectDigest":"sha224:1f26e23245e830c5aa90735377d43535b0a080d03981ea58e4b94372"}]} diff --git a/pkg/integrity/testdata/TestGetImageMetadata/SHA256.golden b/pkg/integrity/testdata/TestGetImageMetadata/SHA256.golden index 7286dc41..60eba6b2 100644 --- a/pkg/integrity/testdata/TestGetImageMetadata/SHA256.golden +++ b/pkg/integrity/testdata/TestGetImageMetadata/SHA256.golden @@ -1 +1 @@ -{"version":1,"header":{"digest":"sha256:635fa0a14a8ef0c0351ed3e985799ed1d4f75ce973dea3cc76c99710795cc3f1"},"objects":[{"relativeId":0,"descriptorDigest":"sha256:3634ad01db0dd5482ecf685267b53d6201690438ca27c3d7ea91c971a1f41f92","objectDigest":"sha256:004dfc8da678c309de28b5386a1e9efd57f536b150c40d29b31506aa0fb17ec2"},{"relativeId":1,"descriptorDigest":"sha256:db74cb63348414def73535c9f0f83e8ad7df61229ed2806f4da8b69d6d7464d6","objectDigest":"sha256:5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953"}]} +{"version":1,"header":{"digest":"sha256:635fa0a14a8ef0c0351ed3e985799ed1d4f75ce973dea3cc76c99710795cc3f1"},"objects":[{"relativeId":0,"descriptorDigest":"sha256:3634ad01db0dd5482ecf685267b53d6201690438ca27c3d7ea91c971a1f41f92","objectDigest":"sha256:004dfc8da678c309de28b5386a1e9efd57f536b150c40d29b31506aa0fb17ec2"},{"relativeId":1,"descriptorDigest":"sha256:04b5f87c9692a54f80d10fb6af00c779763aeca29d610348854bd97cd8bf66fd","objectDigest":"sha256:9f9c4e5e131934969b4ac8f495691c70b8c6c8e3f489c2c9ab5f1af82bce0604"}]} diff --git a/pkg/integrity/testdata/TestGetImageMetadata/SHA384.golden b/pkg/integrity/testdata/TestGetImageMetadata/SHA384.golden index a324654d..9e3b6de3 100644 --- a/pkg/integrity/testdata/TestGetImageMetadata/SHA384.golden +++ b/pkg/integrity/testdata/TestGetImageMetadata/SHA384.golden @@ -1 +1 @@ -{"version":1,"header":{"digest":"sha384:92bdcff06f2cde591d8af1f0ab80687e5eccf1dfe8fe7a8a8ef4b80d28bd2c7a77bcc4abfbcfdb3fc84ec7992ed54334"},"objects":[{"relativeId":0,"descriptorDigest":"sha384:ed532e8496b916182a4185a3d12f3a6d4c59d204965ef1a732013d1c05050291ec29b48b06ba100a948468868023fb82","objectDigest":"sha384:f8722c6694c4997334525090678b2148f6263502c3eb144a44e8be0d2bfd039f4067a3f8152f94ab3af7c63acfe78ce6"},{"relativeId":1,"descriptorDigest":"sha384:d06c5144e805d18f8ebbce1eef073dd711ab9a6550e76e1fb9b82e5a822dd83273069d258d099a437461e674f519ef9c","objectDigest":"sha384:0b7e0522460767c74abb4245bc0d3a27209a5aed111059faead54ffc74a93759160ac9642d7a7df3038ece62f2fa9815"}]} +{"version":1,"header":{"digest":"sha384:92bdcff06f2cde591d8af1f0ab80687e5eccf1dfe8fe7a8a8ef4b80d28bd2c7a77bcc4abfbcfdb3fc84ec7992ed54334"},"objects":[{"relativeId":0,"descriptorDigest":"sha384:ed532e8496b916182a4185a3d12f3a6d4c59d204965ef1a732013d1c05050291ec29b48b06ba100a948468868023fb82","objectDigest":"sha384:f8722c6694c4997334525090678b2148f6263502c3eb144a44e8be0d2bfd039f4067a3f8152f94ab3af7c63acfe78ce6"},{"relativeId":1,"descriptorDigest":"sha384:de7f8e386d3c1679711711f31812d12a913b0f5202503e46e9e1c5fd36c49908c5e288a3c08e6b72285dba177596668d","objectDigest":"sha384:da6cf2d305a04a53623df94d5e74bc22aee7961a5a62b289f99db693e5a980ee276526f254f6504f9e66621ce821b977"}]} diff --git a/pkg/integrity/testdata/TestGetImageMetadata/SHA512.golden b/pkg/integrity/testdata/TestGetImageMetadata/SHA512.golden index d067015c..1028bd36 100644 --- a/pkg/integrity/testdata/TestGetImageMetadata/SHA512.golden +++ b/pkg/integrity/testdata/TestGetImageMetadata/SHA512.golden @@ -1 +1 @@ -{"version":1,"header":{"digest":"sha512:503a1101d5a7f66e440f157576597c5ab9a3517b025259da985402f3b7de7c90c6034b8b5d3da992a9cae5b47dd355fce3f9932e92bc47422134cc5b7347e1e7"},"objects":[{"relativeId":0,"descriptorDigest":"sha512:4ccbff33c9be45cf2ba25412de4a87bd623fd48bf00598b756ea5a12a4eddb83aa93176a91a875b595750837b3ba77b5dfbbbd90e2126ca4d4828763db6dc591","objectDigest":"sha512:808e1f67ffbdbdae30946529b920a1ad6d49c0c50423bc0c9d41ece566e291b6c3e6b6839f3095fbab6bc15a5b971b07d4b8b2f22b982ce3c2b8fd05eef7e1b3"},{"relativeId":1,"descriptorDigest":"sha512:4759070398e2e62d47fc166051918ae99493c31e0cb533ad6b041941c69a81a3cd3141a665fb5d1adef21a5ab9ac3247ab2bd4b1551b9377728acf87e56d9870","objectDigest":"sha512:1284b2d521535196f22175d5f558104220a6ad7680e78b49fa6f20e57ea7b185d71ec1edb137e70eba528dedb141f5d2f8bb53149d262932b27cf41fed96aa7f"}]} +{"version":1,"header":{"digest":"sha512:503a1101d5a7f66e440f157576597c5ab9a3517b025259da985402f3b7de7c90c6034b8b5d3da992a9cae5b47dd355fce3f9932e92bc47422134cc5b7347e1e7"},"objects":[{"relativeId":0,"descriptorDigest":"sha512:4ccbff33c9be45cf2ba25412de4a87bd623fd48bf00598b756ea5a12a4eddb83aa93176a91a875b595750837b3ba77b5dfbbbd90e2126ca4d4828763db6dc591","objectDigest":"sha512:808e1f67ffbdbdae30946529b920a1ad6d49c0c50423bc0c9d41ece566e291b6c3e6b6839f3095fbab6bc15a5b971b07d4b8b2f22b982ce3c2b8fd05eef7e1b3"},{"relativeId":1,"descriptorDigest":"sha512:39bc9e8ecf3192e0656f0b4de529b7e6b1b0d892a6b19fd6f619bf476558bc15255ead250e440c3fe69bbf061b49c0ca0d7de18616c0b3172b2ca2d0753ef331","objectDigest":"sha512:c948c053d5494e944dc251ba774882c58c6b18dae241caa84123c779170d1ed0a22ced3af76d67c7090b668fa7d80531e5b9e3f4677b1b5aae64e8d0d24999bf"}]} diff --git a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group1.golden b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group1.golden index f7e09eeb..ade85d79 100644 Binary files a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group1.golden and b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group1.golden differ diff --git a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group2.golden b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group2.golden index 7f89006a..13cc3e52 100644 Binary files a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group2.golden and b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Group2.golden differ diff --git a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Object2.golden b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Object2.golden index a891e0f2..5a050a1d 100644 Binary files a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Object2.golden and b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/Object2.golden differ diff --git a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA256.golden b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA256.golden index f7e09eeb..ade85d79 100644 Binary files a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA256.golden and b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA256.golden differ diff --git a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA384.golden b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA384.golden index 02059393..156adf00 100644 Binary files a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA384.golden and b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA384.golden differ diff --git a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA512.golden b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA512.golden index 33c04f7b..f1d9afad 100644 Binary files a/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA512.golden and b/pkg/integrity/testdata/TestGroupSigner_SignWithEntity/SignatureConfigSHA512.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/EncryptedKey.golden b/pkg/integrity/testdata/TestSigner_Sign/EncryptedKey.golden index ea68b457..fb72e4a1 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/EncryptedKey.golden and b/pkg/integrity/testdata/TestSigner_Sign/EncryptedKey.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/NoKeyMaterial.golden b/pkg/integrity/testdata/TestSigner_Sign/NoKeyMaterial.golden index ea68b457..fb72e4a1 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/NoKeyMaterial.golden and b/pkg/integrity/testdata/TestSigner_Sign/NoKeyMaterial.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OneGroup.golden b/pkg/integrity/testdata/TestSigner_Sign/OneGroup.golden index 65f687e0..94225e7a 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OneGroup.golden and b/pkg/integrity/testdata/TestSigner_Sign/OneGroup.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignDeterministic.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignDeterministic.golden index dbcb7a60..6a497c85 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignDeterministic.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignDeterministic.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup1.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup1.golden index ffb54913..838cbf20 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup1.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup1.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup2.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup2.golden index ac5ed71d..8a0f4fa3 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup2.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignGroup2.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignObject1.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignObject1.golden index 0d072c71..87aaa135 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignObject1.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignObject1.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignObject2.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignObject2.golden index 4d278699..b5d103ce 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignObject2.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignObject2.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignObject3.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignObject3.golden index ac5ed71d..8a0f4fa3 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignObject3.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignObject3.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/OptSignObjects.golden b/pkg/integrity/testdata/TestSigner_Sign/OptSignObjects.golden index 17fca3c1..ebc2c8b3 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/OptSignObjects.golden and b/pkg/integrity/testdata/TestSigner_Sign/OptSignObjects.golden differ diff --git a/pkg/integrity/testdata/TestSigner_Sign/TwoGroups.golden b/pkg/integrity/testdata/TestSigner_Sign/TwoGroups.golden index 17fca3c1..ebc2c8b3 100644 Binary files a/pkg/integrity/testdata/TestSigner_Sign/TwoGroups.golden and b/pkg/integrity/testdata/TestSigner_Sign/TwoGroups.golden differ diff --git a/pkg/siftool/add_test.go b/pkg/siftool/add_test.go index a3d94755..f3c8d0d3 100644 --- a/pkg/siftool/add_test.go +++ b/pkg/siftool/add_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -50,7 +50,7 @@ func Test_command_getAdd(t *testing.T) { } args = append(args, tt.flags...) - runCommand(t, cmd, args) + runCommand(t, cmd, args, nil) }) } } diff --git a/pkg/siftool/del_test.go b/pkg/siftool/del_test.go index 8318a524..ff3f4cdd 100644 --- a/pkg/siftool/del_test.go +++ b/pkg/siftool/del_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -28,7 +28,7 @@ func Test_command_getDel(t *testing.T) { cmd := c.getDel() - runCommand(t, cmd, []string{"1", makeTestSIF(t, true)}) + runCommand(t, cmd, []string{"1", makeTestSIF(t, true)}, nil) }) } } diff --git a/pkg/siftool/dump_test.go b/pkg/siftool/dump_test.go index 75ceb502..46b67654 100644 --- a/pkg/siftool/dump_test.go +++ b/pkg/siftool/dump_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -43,7 +43,7 @@ func Test_command_getDump(t *testing.T) { cmd := c.getDump() - runCommand(t, cmd, []string{tt.id, tt.path}) + runCommand(t, cmd, []string{tt.id, tt.path}, nil) }) } } diff --git a/pkg/siftool/header_test.go b/pkg/siftool/header_test.go index a0442dd4..c93153e7 100644 --- a/pkg/siftool/header_test.go +++ b/pkg/siftool/header_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -72,7 +72,7 @@ func Test_command_getHeader(t *testing.T) { cmd := c.getHeader() - runCommand(t, cmd, []string{tt.path}) + runCommand(t, cmd, []string{tt.path}, nil) }) } } diff --git a/pkg/siftool/info_test.go b/pkg/siftool/info_test.go index ba7b9e44..5e793f9f 100644 --- a/pkg/siftool/info_test.go +++ b/pkg/siftool/info_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -43,7 +43,7 @@ func Test_command_getInfo(t *testing.T) { cmd := c.getInfo() - runCommand(t, cmd, []string{tt.id, tt.path}) + runCommand(t, cmd, []string{tt.id, tt.path}, nil) }) } } diff --git a/pkg/siftool/list_test.go b/pkg/siftool/list_test.go index 8e3fb0d2..951421a4 100644 --- a/pkg/siftool/list_test.go +++ b/pkg/siftool/list_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -72,7 +72,7 @@ func Test_command_getList(t *testing.T) { cmd := c.getList() - runCommand(t, cmd, []string{tt.path}) + runCommand(t, cmd, []string{tt.path}, nil) }) } } diff --git a/pkg/siftool/mount.go b/pkg/siftool/mount.go new file mode 100644 index 00000000..21f1fb8b --- /dev/null +++ b/pkg/siftool/mount.go @@ -0,0 +1,31 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package siftool + +import ( + "github.com/spf13/cobra" +) + +// getMount returns a command that mounts the primary system partition of a SIF image. +func (c *command) getMount() *cobra.Command { + return &cobra.Command{ + Use: "mount ", + Short: "Mount primary system partition", + Long: "Mount the primary system partition of a SIF image", + Example: c.opts.rootPath + " mount image.sif path/", + Args: cobra.ExactArgs(2), + PreRunE: c.initApp, + RunE: func(cmd *cobra.Command, args []string) error { + return c.app.Mount(cmd.Context(), args[0], args[1]) + }, + DisableFlagsInUseLine: true, + Hidden: true, // hide while command is experimental + } +} diff --git a/pkg/siftool/mount_test.go b/pkg/siftool/mount_test.go new file mode 100644 index 00000000..d1e46c44 --- /dev/null +++ b/pkg/siftool/mount_test.go @@ -0,0 +1,65 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package siftool + +import ( + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/apptainer/sif/v2/pkg/sif" +) + +func Test_command_getMount(t *testing.T) { + if _, err := exec.LookPath("squashfuse"); err != nil { + t.Skip("squashfuse not found, skipping mount tests") + } + + tests := []struct { + name string + opts commandOpts + path string + wantErr error + }{ + { + name: "Empty", + path: filepath.Join(corpus, "empty.sif"), + wantErr: sif.ErrNoObjects, + }, + { + name: "OneGroup", + path: filepath.Join(corpus, "one-group.sif"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + path, err := os.MkdirTemp("", "siftool-mount-*") + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + cmd := exec.Command("fusermount", "-u", path) + + if err := cmd.Run(); err != nil { + t.Log(err) + } + + os.RemoveAll(path) + }) + + c := &command{opts: tt.opts} + + cmd := c.getMount() + + runCommand(t, cmd, []string{tt.path, path}, tt.wantErr) + }) + } +} diff --git a/pkg/siftool/new_test.go b/pkg/siftool/new_test.go index 2a2c96dc..92860372 100644 --- a/pkg/siftool/new_test.go +++ b/pkg/siftool/new_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -36,7 +36,7 @@ func Test_command_getNew(t *testing.T) { cmd := c.getNew() - runCommand(t, cmd, []string{tf.Name()}) + runCommand(t, cmd, []string{tf.Name()}, nil) }) } } diff --git a/pkg/siftool/setprim_test.go b/pkg/siftool/setprim_test.go index df71de74..f9a50e3d 100644 --- a/pkg/siftool/setprim_test.go +++ b/pkg/siftool/setprim_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -28,7 +28,7 @@ func Test_command_getSetPrim(t *testing.T) { cmd := c.getSetPrim() - runCommand(t, cmd, []string{"1", makeTestSIF(t, true)}) + runCommand(t, cmd, []string{"1", makeTestSIF(t, true)}, nil) }) } } diff --git a/pkg/siftool/siftool.go b/pkg/siftool/siftool.go index 08c0193f..464875cd 100644 --- a/pkg/siftool/siftool.go +++ b/pkg/siftool/siftool.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2018-2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2018-2022, Sylabs Inc. All rights reserved. // Copyright (c) 2017, SingularityWare, LLC. All rights reserved. // Copyright (c) 2017, Yannick Cote All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the @@ -27,6 +27,7 @@ type command struct { func (c *command) initApp(cmd *cobra.Command, args []string) error { app, err := siftool.New( siftool.OptAppOutput(cmd.OutOrStdout()), + siftool.OptAppError(cmd.ErrOrStderr()), ) c.app = app @@ -35,12 +36,21 @@ func (c *command) initApp(cmd *cobra.Command, args []string) error { // commandOpts contains configured options. type commandOpts struct { - rootPath string + rootPath string + experimental bool } // CommandOpt are used to configure optional command behavior. type CommandOpt func(*commandOpts) error +// OptWithExperimental enables/disables experimental commands. +func OptWithExperimental(b bool) CommandOpt { + return func(co *commandOpts) error { + co.experimental = b + return nil + } +} + // AddCommands adds siftool commands to cmd according to opts. // // A set of commands are provided to display elements such as the SIF global @@ -70,5 +80,10 @@ func AddCommands(cmd *cobra.Command, opts ...CommandOpt) error { c.getSetPrim(), ) + if c.opts.experimental { + cmd.AddCommand(c.getMount()) + cmd.AddCommand(c.getUnmount()) + } + return nil } diff --git a/pkg/siftool/siftool_test.go b/pkg/siftool/siftool_test.go index 20c40647..518b5c24 100644 --- a/pkg/siftool/siftool_test.go +++ b/pkg/siftool/siftool_test.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2021-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the // LICENSE file distributed with the sources of this project regarding your // rights to use or distribute this software. @@ -10,6 +10,7 @@ package siftool import ( "bytes" + "errors" "os" "path/filepath" "testing" @@ -51,7 +52,7 @@ func makeTestSIF(t *testing.T, withDataObject bool) string { return tf.Name() } -func runCommand(t *testing.T, cmd *cobra.Command, args []string) { +func runCommand(t *testing.T, cmd *cobra.Command, args []string, wantErr error) { t.Helper() var out, err bytes.Buffer @@ -60,8 +61,8 @@ func runCommand(t *testing.T, cmd *cobra.Command, args []string) { cmd.SetArgs(args) - if err := cmd.Execute(); err != nil { - t.Fatal(err) + if got, want := cmd.Execute(), wantErr; !errors.Is(got, want) { + t.Fatalf("got error %v, want %v", got, want) } g := goldie.New(t, @@ -82,6 +83,11 @@ func TestAddCommands(t *testing.T) { name: "SifTool", args: []string{"help"}, }, + { + name: "SifToolExperimental", + opts: []CommandOpt{OptWithExperimental(true)}, + args: []string{"help"}, + }, { name: "Add", args: []string{"help", "add"}, @@ -114,6 +120,11 @@ func TestAddCommands(t *testing.T) { name: "SetPrim", args: []string{"help", "setprim"}, }, + { + name: "Mount", + opts: []CommandOpt{OptWithExperimental(true)}, + args: []string{"help", "mount"}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -125,7 +136,7 @@ func TestAddCommands(t *testing.T) { t.Fatal(err) } - runCommand(t, cmd, tt.args) + runCommand(t, cmd, tt.args, nil) }) } } diff --git a/pkg/siftool/testdata/TestAddCommands/Mount/err.golden b/pkg/siftool/testdata/TestAddCommands/Mount/err.golden new file mode 100644 index 00000000..e69de29b diff --git a/pkg/siftool/testdata/TestAddCommands/Mount/out.golden b/pkg/siftool/testdata/TestAddCommands/Mount/out.golden new file mode 100644 index 00000000..3df015d5 --- /dev/null +++ b/pkg/siftool/testdata/TestAddCommands/Mount/out.golden @@ -0,0 +1,10 @@ +Mount the primary system partition of a SIF image + +Usage: + siftool mount + +Examples: +siftool mount image.sif path/ + +Flags: + -h, --help help for mount diff --git a/pkg/siftool/testdata/TestAddCommands/SifToolExperimental/err.golden b/pkg/siftool/testdata/TestAddCommands/SifToolExperimental/err.golden new file mode 100644 index 00000000..e69de29b diff --git a/pkg/siftool/testdata/TestAddCommands/SifToolExperimental/out.golden b/pkg/siftool/testdata/TestAddCommands/SifToolExperimental/out.golden new file mode 100644 index 00000000..2d8532f5 --- /dev/null +++ b/pkg/siftool/testdata/TestAddCommands/SifToolExperimental/out.golden @@ -0,0 +1,19 @@ +Usage: + siftool [command] + +Available Commands: + add Add data object + completion Generate the autocompletion script for the specified shell + del Delete data object + dump Dump data object + header Display global header + help Help about any command + info Display data object info + list List data objects + new Create SIF image + setprim Set primary system partition + +Flags: + -h, --help help for siftool + +Use "siftool [command] --help" for more information about a command. diff --git a/pkg/siftool/testdata/Test_command_getDump/Three/out.golden b/pkg/siftool/testdata/Test_command_getDump/Three/out.golden index 6d1002b2..4e354d95 100644 --- a/pkg/siftool/testdata/Test_command_getDump/Three/out.golden +++ b/pkg/siftool/testdata/Test_command_getDump/Three/out.golden @@ -1,15 +1,15 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 -{"version":1,"header":{"digest":"sha256:635fa0a14a8ef0c0351ed3e985799ed1d4f75ce973dea3cc76c99710795cc3f1"},"objects":[{"relativeId":0,"descriptorDigest":"sha256:3634ad01db0dd5482ecf685267b53d6201690438ca27c3d7ea91c971a1f41f92","objectDigest":"sha256:004dfc8da678c309de28b5386a1e9efd57f536b150c40d29b31506aa0fb17ec2"},{"relativeId":1,"descriptorDigest":"sha256:db74cb63348414def73535c9f0f83e8ad7df61229ed2806f4da8b69d6d7464d6","objectDigest":"sha256:5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953"}]} +{"version":1,"header":{"digest":"sha256:635fa0a14a8ef0c0351ed3e985799ed1d4f75ce973dea3cc76c99710795cc3f1"},"objects":[{"relativeId":0,"descriptorDigest":"sha256:3634ad01db0dd5482ecf685267b53d6201690438ca27c3d7ea91c971a1f41f92","objectDigest":"sha256:004dfc8da678c309de28b5386a1e9efd57f536b150c40d29b31506aa0fb17ec2"},{"relativeId":1,"descriptorDigest":"sha256:04b5f87c9692a54f80d10fb6af00c779763aeca29d610348854bd97cd8bf66fd","objectDigest":"sha256:9f9c4e5e131934969b4ac8f495691c70b8c6c8e3f489c2c9ab5f1af82bce0604"}]} -----BEGIN PGP SIGNATURE----- wsBzBAEBCAAnBQJe+oD0CZCiDCfuf/e6hBYhBBIEXIwLEATQWN5L7aIMJ+5/97qE -AADY9ggAlW/Y+BssNOLcCAiu0dzZCf5BfbzmOUQ+VNajAsZyOIJnW1t19lDYoRNx -x3YolyyRfEmw9Kf1n6fctDHGPyzRIIOc1/0CVQzNzfKZQO+x0+9qvurILADijY/3 -1DKqhbxoO2a5iASXYHH9yYs3J82N3EKEYyFdDMTcHs4UijUnHvwcTt0smY6JQ9Su -vssWg+3qltuVjiYOQPgg9XR5i8suXE76poit9Ftp7jOD9eYtVcUEKRZLrVCsDJu9 -77QvejJmgquueYX4pM2EuH9EOFnDV3gl4Cuocsn5OLDgfhYuT1t5Hay1iAPpJqm6 -/EXQY7CECByIj6TCFurfXwc+uYSD9Q== -=rZoe +AAC46gf/VXyzZ649nttrX13JkM5kRVPlAIblBQxfoUxA1xwIXdRoM5ceDY0Em+YD +8b6Xl1w2sDTqo0R15cJSh8sf0ClFOvYpDQRNCwKx17k1Wd0gHcW4QVu6gJnlbNvN +o/EJdEN2TkbCM2aFvj34DAIfErRBIEsCeDDvJ/6WUSySWbnydfNU2pCsnK4A7l2H +KOXFzSaPijG9L/pU3O3vNZ+fXPffqHL9JVhs5Mt/Yo3oeoEnoVaKvJLGx/fyl+Gj +7qsfWFyHWzRCww9VFg/TCBeUku0CYRfXhxOgo4OuHNr8oo82rKDZU6+l3UZ2Sw8T ++kLe/zUkaILocGOvhvKdi630OGGb/Q== +=3Jq2 -----END PGP SIGNATURE----- \ No newline at end of file diff --git a/pkg/siftool/testdata/Test_command_getDump/Two/out.golden b/pkg/siftool/testdata/Test_command_getDump/Two/out.golden index 7d174b13..cf6539a5 100644 Binary files a/pkg/siftool/testdata/Test_command_getDump/Two/out.golden and b/pkg/siftool/testdata/Test_command_getDump/Two/out.golden differ diff --git a/pkg/siftool/testdata/Test_command_getHeader/OneGroup/out.golden b/pkg/siftool/testdata/Test_command_getHeader/OneGroup/out.golden index bc631d68..a2941c12 100644 --- a/pkg/siftool/testdata/Test_command_getHeader/OneGroup/out.golden +++ b/pkg/siftool/testdata/Test_command_getHeader/OneGroup/out.golden @@ -5,4 +5,4 @@ Descriptors Total: 48 Descriptors Offset: 4096 Descriptors Size: 27 KiB Data Offset: 32176 -Data Size: 5 KiB +Data Size: 9 KiB diff --git a/pkg/siftool/testdata/Test_command_getHeader/TwoGroups/out.golden b/pkg/siftool/testdata/Test_command_getHeader/TwoGroups/out.golden index 0db18f03..c16ef18c 100644 --- a/pkg/siftool/testdata/Test_command_getHeader/TwoGroups/out.golden +++ b/pkg/siftool/testdata/Test_command_getHeader/TwoGroups/out.golden @@ -5,4 +5,4 @@ Descriptors Total: 48 Descriptors Offset: 4096 Descriptors Size: 27 KiB Data Offset: 32176 -Data Size: 9 KiB +Data Size: 265 KiB diff --git a/pkg/siftool/testdata/Test_command_getHeader/TwoGroupsSigned/out.golden b/pkg/siftool/testdata/Test_command_getHeader/TwoGroupsSigned/out.golden index acf8b173..8a9d0134 100644 --- a/pkg/siftool/testdata/Test_command_getHeader/TwoGroupsSigned/out.golden +++ b/pkg/siftool/testdata/Test_command_getHeader/TwoGroupsSigned/out.golden @@ -5,4 +5,4 @@ Descriptors Total: 48 Descriptors Offset: 4096 Descriptors Size: 27 KiB Data Offset: 32176 -Data Size: 17 KiB +Data Size: 269 KiB diff --git a/pkg/siftool/testdata/Test_command_getInfo/Two/out.golden b/pkg/siftool/testdata/Test_command_getInfo/Two/out.golden index f34651f4..f49a5547 100644 --- a/pkg/siftool/testdata/Test_command_getInfo/Two/out.golden +++ b/pkg/siftool/testdata/Test_command_getInfo/Two/out.golden @@ -3,7 +3,7 @@ Group ID: 1 Linked ID: NONE Offset: 36864 - Size: 4 + Size: 4096 Filesystem Type: Squashfs Partition Type: *System Architecture: 386 diff --git a/pkg/siftool/testdata/Test_command_getList/OneGroup/out.golden b/pkg/siftool/testdata/Test_command_getList/OneGroup/out.golden index fe78f62c..01400f9b 100644 --- a/pkg/siftool/testdata/Test_command_getList/OneGroup/out.golden +++ b/pkg/siftool/testdata/Test_command_getList/OneGroup/out.golden @@ -2,4 +2,4 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) diff --git a/pkg/siftool/testdata/Test_command_getList/OneGroupSigned/out.golden b/pkg/siftool/testdata/Test_command_getList/OneGroupSigned/out.golden index 98030e3a..5b663d3e 100644 --- a/pkg/siftool/testdata/Test_command_getList/OneGroupSigned/out.golden +++ b/pkg/siftool/testdata/Test_command_getList/OneGroupSigned/out.golden @@ -2,5 +2,5 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) 3 |NONE |1 (G) |40960-42014 |Signature (SHA-256) diff --git a/pkg/siftool/testdata/Test_command_getList/TwoGroups/out.golden b/pkg/siftool/testdata/Test_command_getList/TwoGroups/out.golden index 648c2801..1eca2ab2 100644 --- a/pkg/siftool/testdata/Test_command_getList/TwoGroups/out.golden +++ b/pkg/siftool/testdata/Test_command_getList/TwoGroups/out.golden @@ -2,5 +2,5 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) -3 |2 |NONE |40960-40964 |FS (Ext3/System/amd64) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) +3 |2 |NONE |40960-303104 |FS (Ext3/System/amd64) diff --git a/pkg/siftool/testdata/Test_command_getList/TwoGroupsSigned/out.golden b/pkg/siftool/testdata/Test_command_getList/TwoGroupsSigned/out.golden index f21bf6d0..b6793575 100644 --- a/pkg/siftool/testdata/Test_command_getList/TwoGroupsSigned/out.golden +++ b/pkg/siftool/testdata/Test_command_getList/TwoGroupsSigned/out.golden @@ -2,7 +2,7 @@ ID |GROUP |LINK |SIF POSITION (start-end) |TYPE ------------------------------------------------------------------------------ 1 |1 |NONE |32768-32772 |FS (Raw/System/386) -2 |1 |NONE |36864-36868 |FS (Squashfs/*System/386) -3 |2 |NONE |40960-40964 |FS (Ext3/System/amd64) -4 |NONE |1 (G) |45056-46110 |Signature (SHA-256) -5 |NONE |2 (G) |49152-50007 |Signature (SHA-256) +2 |1 |NONE |36864-40960 |FS (Squashfs/*System/386) +3 |2 |NONE |40960-303104 |FS (Ext3/System/amd64) +4 |NONE |1 (G) |303104-304158 |Signature (SHA-256) +5 |NONE |2 (G) |307200-308055 |Signature (SHA-256) diff --git a/pkg/siftool/testdata/Test_command_getMount/Empty/err.golden b/pkg/siftool/testdata/Test_command_getMount/Empty/err.golden new file mode 100644 index 00000000..cd860b84 --- /dev/null +++ b/pkg/siftool/testdata/Test_command_getMount/Empty/err.golden @@ -0,0 +1 @@ +Error: failed to get partition descriptor: no objects in image diff --git a/pkg/siftool/testdata/Test_command_getMount/Empty/out.golden b/pkg/siftool/testdata/Test_command_getMount/Empty/out.golden new file mode 100644 index 00000000..f22522a8 --- /dev/null +++ b/pkg/siftool/testdata/Test_command_getMount/Empty/out.golden @@ -0,0 +1,9 @@ +Usage: + mount + +Examples: + mount image.sif path/ + +Flags: + -h, --help help for mount + diff --git a/pkg/siftool/testdata/Test_command_getMount/OneGroup/err.golden b/pkg/siftool/testdata/Test_command_getMount/OneGroup/err.golden new file mode 100644 index 00000000..e69de29b diff --git a/pkg/siftool/testdata/Test_command_getMount/OneGroup/out.golden b/pkg/siftool/testdata/Test_command_getMount/OneGroup/out.golden new file mode 100644 index 00000000..e69de29b diff --git a/pkg/siftool/testdata/Test_command_getUnmount/err.golden b/pkg/siftool/testdata/Test_command_getUnmount/err.golden new file mode 100644 index 00000000..e69de29b diff --git a/pkg/siftool/testdata/Test_command_getUnmount/out.golden b/pkg/siftool/testdata/Test_command_getUnmount/out.golden new file mode 100644 index 00000000..e69de29b diff --git a/pkg/siftool/unmount.go b/pkg/siftool/unmount.go new file mode 100644 index 00000000..fdb7c259 --- /dev/null +++ b/pkg/siftool/unmount.go @@ -0,0 +1,31 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package siftool + +import ( + "github.com/spf13/cobra" +) + +// getUnmount returns a command that unmounts the primary system partition of a SIF image. +func (c *command) getUnmount() *cobra.Command { + return &cobra.Command{ + Use: "unmount ", + Short: "Unmount primary system partition", + Long: "Unmount a primary system partition of a SIF image", + Example: c.opts.rootPath + " unmount path/", + Args: cobra.ExactArgs(1), + PreRunE: c.initApp, + RunE: func(cmd *cobra.Command, args []string) error { + return c.app.Unmount(cmd.Context(), args[0]) + }, + DisableFlagsInUseLine: true, + Hidden: true, // hide while command is experimental + } +} diff --git a/pkg/siftool/unmount_test.go b/pkg/siftool/unmount_test.go new file mode 100644 index 00000000..1cfd2656 --- /dev/null +++ b/pkg/siftool/unmount_test.go @@ -0,0 +1,46 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package siftool + +import ( + "context" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/apptainer/sif/v2/pkg/user" +) + +func Test_command_getUnmount(t *testing.T) { + if _, err := exec.LookPath("squashfuse"); err != nil { + t.Skip(" not found, skipping unmount tests") + } + if _, err := exec.LookPath("fusermount"); err != nil { + t.Skip(" not found, skipping unmount tests") + } + + path, err := os.MkdirTemp("", "siftool-unmount-*") + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + os.RemoveAll(path) + }) + + testSIF := filepath.Join(corpus, "one-group.sif") + if err := user.Mount(context.Background(), testSIF, path); err != nil { + t.Fatal(err) + } + + c := &command{} + cmd := c.getUnmount() + runCommand(t, cmd, []string{path}, nil) +} diff --git a/pkg/user/mount.go b/pkg/user/mount.go new file mode 100644 index 00000000..9283773c --- /dev/null +++ b/pkg/user/mount.go @@ -0,0 +1,126 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package user + +import ( + "context" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + + "github.com/apptainer/sif/v2/pkg/sif" +) + +// mountSquashFS mounts the SquashFS filesystem from path at offset into mountPath. +func mountSquashFS(ctx context.Context, offset int64, path, mountPath string, mo mountOpts) error { + args := []string{ + "-o", fmt.Sprintf("ro,offset=%d", offset), + filepath.Clean(path), + filepath.Clean(mountPath), + } + //nolint:gosec // note (gosec exclusion) - we require callers to be able to specify squashfuse not on PATH + cmd := exec.CommandContext(ctx, mo.squashfusePath, args...) + cmd.Stdout = mo.stdout + cmd.Stderr = mo.stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to mount: %w", err) + } + + return nil +} + +// mountOpts accumulates mount options. +type mountOpts struct { + stdout io.Writer + stderr io.Writer + squashfusePath string +} + +// MountOpt are used to specify mount options. +type MountOpt func(*mountOpts) error + +// OptMountStdout writes standard output to w. +func OptMountStdout(w io.Writer) MountOpt { + return func(mo *mountOpts) error { + mo.stdout = w + return nil + } +} + +// OptMountStderr writes standard error to w. +func OptMountStderr(w io.Writer) MountOpt { + return func(mo *mountOpts) error { + mo.stderr = w + return nil + } +} + +var errSquashfusePathInvalid = errors.New("squashfuse path must be relative or absolute") + +// OptMountSquashfusePath sets an explicit path to the squashfuse binary. The path must be an +// absolute or relative path. +func OptMountSquashfusePath(path string) MountOpt { + return func(mo *mountOpts) error { + if filepath.Base(path) == path { + return errSquashfusePathInvalid + } + mo.squashfusePath = path + return nil + } +} + +var errUnsupportedFSType = errors.New("unrecognized filesystem type") + +// Mount mounts the primary system partition of the SIF file at path into mountPath. +// +// Mount may start one or more underlying processes. By default, stdout and stderr of these +// processes is discarded. To modify this behavior, consider using OptMountStdout and/or +// OptMountStderr. +// +// By default, Mount searches for a squashfuse binary in the directories named by the PATH +// environment variable. To override this behavior, consider using OptMountSquashfusePath(). +func Mount(ctx context.Context, path, mountPath string, opts ...MountOpt) error { + mo := mountOpts{ + squashfusePath: "squashfuse", + } + + for _, opt := range opts { + if err := opt(&mo); err != nil { + return fmt.Errorf("%w", err) + } + } + + f, err := sif.LoadContainerFromPath(path, sif.OptLoadWithFlag(os.O_RDONLY)) + if err != nil { + return fmt.Errorf("failed to load image: %w", err) + } + defer func() { _ = f.UnloadContainer() }() + + d, err := f.GetDescriptor(sif.WithPartitionType(sif.PartPrimSys)) + if err != nil { + return fmt.Errorf("failed to get partition descriptor: %w", err) + } + + fs, _, _, err := d.PartitionMetadata() + if err != nil { + return fmt.Errorf("failed to get partition metadata: %w", err) + } + + switch fs { + case sif.FsSquash: + return mountSquashFS(ctx, d.Offset(), path, mountPath, mo) + default: + return errUnsupportedFSType + } +} diff --git a/pkg/user/unmount.go b/pkg/user/unmount.go new file mode 100644 index 00000000..4c48f79c --- /dev/null +++ b/pkg/user/unmount.go @@ -0,0 +1,97 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package user + +import ( + "context" + "errors" + "fmt" + "io" + "os/exec" + "path/filepath" +) + +// unmountSquashFS unmounts the filesystem at mountPath. +func unmountSquashFS(ctx context.Context, mountPath string, uo unmountOpts) error { + args := []string{ + "-u", + filepath.Clean(mountPath), + } + cmd := exec.CommandContext(ctx, uo.fusermountPath, args...) //nolint:gosec + cmd.Stdout = uo.stdout + cmd.Stderr = uo.stderr + + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to unmount: %w", err) + } + + return nil +} + +// unmountOpts accumulates unmount options. +type unmountOpts struct { + stdout io.Writer + stderr io.Writer + fusermountPath string +} + +// UnmountOpt are used to specify unmount options. +type UnmountOpt func(*unmountOpts) error + +// OptUnmountStdout writes standard output to w. +func OptUnmountStdout(w io.Writer) UnmountOpt { + return func(mo *unmountOpts) error { + mo.stdout = w + return nil + } +} + +// OptUnmountStderr writes standard error to w. +func OptUnmountStderr(w io.Writer) UnmountOpt { + return func(mo *unmountOpts) error { + mo.stderr = w + return nil + } +} + +var errFusermountPathInvalid = errors.New("fusermount path must be relative or absolute") + +// OptUnmountFusermountPath sets the path to the fusermount binary. +func OptUnmountFusermountPath(path string) UnmountOpt { + return func(mo *unmountOpts) error { + if filepath.Base(path) == path { + return errFusermountPathInvalid + } + mo.fusermountPath = path + return nil + } +} + +// Unmount unmounts the filesystem at mountPath. +// +// Unmount may start one or more underlying processes. By default, stdout and stderr of these +// processes is discarded. To modify this behavior, consider using OptUnmountStdout and/or +// OptUnmountStderr. +// +// By default, Unmount searches for a fusermount binary in the directories named by the PATH +// environment variable. To override this behavior, consider using OptUnmountFusermountPath(). +func Unmount(ctx context.Context, mountPath string, opts ...UnmountOpt) error { + uo := unmountOpts{ + fusermountPath: "fusermount", + } + + for _, opt := range opts { + if err := opt(&uo); err != nil { + return fmt.Errorf("%w", err) + } + } + + return unmountSquashFS(ctx, mountPath, uo) +} diff --git a/pkg/user/unmount_test.go b/pkg/user/unmount_test.go new file mode 100644 index 00000000..aea98658 --- /dev/null +++ b/pkg/user/unmount_test.go @@ -0,0 +1,143 @@ +// Copyright (c) Contributors to the Apptainer project, established as +// Apptainer a Series of LF Projects LLC. +// For website terms of use, trademark policy, privacy policy and other +// project policies see https://lfprojects.org/policies +// Copyright (c) 2022, Sylabs Inc. All rights reserved. +// This software is licensed under a 3-clause BSD license. Please consult the +// LICENSE file distributed with the sources of this project regarding your +// rights to use or distribute this software. + +package user + +import ( + "bufio" + "context" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +var corpus = filepath.Join("..", "..", "test", "images") + +func Test_Unmount(t *testing.T) { + if _, err := exec.LookPath("squashfuse"); err != nil { + t.Skip(" not found, skipping mount tests") + } + fusermountPath, err := exec.LookPath("fusermount") + if err != nil { + t.Skip(" not found, skipping mount tests") + } + + path, err := os.MkdirTemp("", "siftool-mount-*") + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + os.RemoveAll(path) + }) + + tests := []struct { + name string + mountSIF string + mountPath string + opts []UnmountOpt + wantErr bool + wantUnmounted bool + }{ + { + name: "Mounted", + mountSIF: filepath.Join(corpus, "one-group.sif"), + mountPath: path, + wantErr: false, + wantUnmounted: true, + }, + { + name: "NotMounted", + mountSIF: "", + mountPath: path, + wantErr: true, + }, + { + name: "NotSquashfuse", + mountSIF: "", + mountPath: "/dev", + wantErr: true, + }, + { + name: "FusermountBare", + mountSIF: "", + mountPath: path, + opts: []UnmountOpt{OptUnmountFusermountPath("fusermount")}, + wantErr: true, + }, + { + name: "FusermountValid", + mountSIF: filepath.Join(corpus, "one-group.sif"), + mountPath: path, + opts: []UnmountOpt{OptUnmountFusermountPath(fusermountPath)}, + wantErr: false, + wantUnmounted: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.mountSIF != "" { + err := Mount(context.Background(), tt.mountSIF, path) + if err != nil { + t.Fatal(err) + } + } + + err := Unmount(context.Background(), tt.mountPath, tt.opts...) + + if err != nil && !tt.wantErr { + t.Errorf("Unexpected error: %s", err) + } + if err == nil && tt.wantErr { + t.Error("Unexpected success") + } + + mounted, err := isMounted(tt.mountPath) + if err != nil { + t.Fatal(err) + } + if tt.wantUnmounted && mounted { + t.Errorf("Expected %s to be unmounted, but it is mounted", tt.mountPath) + } + }) + } +} + +var errBadMountInfo = errors.New("bad mount info") + +func isMounted(mountPath string) (bool, error) { + mountPath, err := filepath.Abs(mountPath) + if err != nil { + return false, err + } + + mi, err := os.Open("/proc/self/mountinfo") + if err != nil { + return false, fmt.Errorf("failed to open /proc/self/mountinfo: %w", err) + } + defer mi.Close() + + scanner := bufio.NewScanner(mi) + for scanner.Scan() { + fields := strings.Split(scanner.Text(), " ") + if len(fields) < 5 { + return false, fmt.Errorf("not enough mountinfo fields: %w", errBadMountInfo) + } + //nolint:lll + // 1348 63 0:77 / /tmp/siftool-mount-956028386 ro,nosuid,nodev,relatime shared:646 - fuse.squashfuse squashfuse ro,user_id=1000,group_id=100 + mntTarget := fields[4] + if mntTarget == mountPath { + return true, nil + } + } + return false, nil +} diff --git a/test/gen_sifs.go b/test/gen_sifs.go index 77c06fb7..60c82db3 100755 --- a/test/gen_sifs.go +++ b/test/gen_sifs.go @@ -2,7 +2,7 @@ // Apptainer a Series of LF Projects LLC. // For website terms of use, trademark policy, privacy policy and other // project policies see https://lfprojects.org/policies -// Copyright (c) 2020-2021, Sylabs Inc. All rights reserved. +// Copyright (c) 2020-2022, Sylabs Inc. All rights reserved. // This software is licensed under a 3-clause BSD license. Please consult the LICENSE.md file // distributed with the sources of this project regarding your rights to use or distribute this // software. @@ -70,15 +70,23 @@ func generateImages() error { } partPrimSys := func() (sif.DescriptorInput, error) { - return sif.NewDescriptorInput(sif.DataPartition, - bytes.NewReader([]byte{0xde, 0xad, 0xbe, 0xef}), + b, err := os.ReadFile(filepath.Join("input", "root.squashfs")) + if err != nil { + return sif.DescriptorInput{}, err + } + + return sif.NewDescriptorInput(sif.DataPartition, bytes.NewReader(b), sif.OptPartitionMetadata(sif.FsSquash, sif.PartPrimSys, "386"), ) } partSystemGroup2 := func() (sif.DescriptorInput, error) { - return sif.NewDescriptorInput(sif.DataPartition, - bytes.NewReader([]byte{0xba, 0xdd, 0xca, 0xfe}), + b, err := os.ReadFile(filepath.Join("input", "root.ext3")) + if err != nil { + return sif.DescriptorInput{}, err + } + + return sif.NewDescriptorInput(sif.DataPartition, bytes.NewReader(b), sif.OptPartitionMetadata(sif.FsExt3, sif.PartSystem, "amd64"), sif.OptGroupID(2), ) diff --git a/test/images/one-group-signed.sif b/test/images/one-group-signed.sif index 7ff9b96f..f7c6894b 100755 Binary files a/test/images/one-group-signed.sif and b/test/images/one-group-signed.sif differ diff --git a/test/images/one-group.sif b/test/images/one-group.sif index ea68b457..fb72e4a1 100755 Binary files a/test/images/one-group.sif and b/test/images/one-group.sif differ diff --git a/test/images/two-groups-signed.sif b/test/images/two-groups-signed.sif index 0899a9b0..b48e1424 100755 Binary files a/test/images/two-groups-signed.sif and b/test/images/two-groups-signed.sif differ diff --git a/test/images/two-groups.sif b/test/images/two-groups.sif index 0555d09d..36701ad5 100755 Binary files a/test/images/two-groups.sif and b/test/images/two-groups.sif differ diff --git a/test/input/root.ext3 b/test/input/root.ext3 new file mode 100644 index 00000000..6163e609 Binary files /dev/null and b/test/input/root.ext3 differ diff --git a/test/input/root.squashfs b/test/input/root.squashfs new file mode 100644 index 00000000..cf6539a5 Binary files /dev/null and b/test/input/root.squashfs differ diff --git a/test/keys/private.asc b/test/keys/private.asc index 0cb933ff..eddb82a7 100644 --- a/test/keys/private.asc +++ b/test/keys/private.asc @@ -1,4 +1,5 @@ -----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v2.0.22 (GNU/Linux) lQOYBF6nUPABCACmd6vggtFfkZvYHJRv/u2UfazFL78oLhD05UpqEaS90ripzPN9 G30IF6WqxQHxia0nV/IqJ9Tjozs0nIaK761y69gCYbac27e1r6Pf4uCoTfOWeGVZ @@ -19,39 +20,39 @@ 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 -=zxMk +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 +=gDqC -----END PGP PRIVATE KEY BLOCK-----