Skip to content

Commit

Permalink
Remove temporary files after downloading binaries
Browse files Browse the repository at this point in the history
A user complained that when using a non ephemeral GitHub
Actions runner, they needed to delete temporary files from
/tmp.

Fixes: alexellis/arkade-get#63

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <[email protected]>
  • Loading branch information
alexellis committed Sep 29, 2023
1 parent 077a575 commit 8f02858
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 146 deletions.
18 changes: 0 additions & 18 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
github.com/alexellis/go-execute/v2 v2.0.0 h1:e2fB9kZcPG0yg65XHL1/t6efcCUdt32AMbr/mv7A2tc=
github.com/alexellis/go-execute/v2 v2.0.0/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ=
github.com/alexellis/go-execute/v2 v2.1.0 h1:0HccwWLNzAonu9Mei2bL8dQThHoaS1c/vq2hQwQW0XY=
github.com/alexellis/go-execute/v2 v2.1.0/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ=
github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
Expand All @@ -13,7 +11,6 @@ github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNA
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
Expand All @@ -27,18 +24,13 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ=
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
Expand All @@ -56,22 +48,17 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY=
github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
Expand All @@ -83,7 +70,6 @@ github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRM
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
Expand All @@ -99,10 +85,6 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
10 changes: 8 additions & 2 deletions pkg/get/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,17 @@ func Download(tool *Tool, arch, operatingSystem, version string, movePath string
if !quiet {
log.Printf("Copying %s to %s\n", outFilePath, localPath)
}
_, err = CopyFile(outFilePath, localPath)
if err != nil {

if _, err = CopyFile(outFilePath, localPath); err != nil {
return "", "", err
}

// Remove parent folder of the binary
tempPath := filepath.Dir(outFilePath)
if err := os.RemoveAll(tempPath); err != nil {
log.Printf("Error removing temporary directory: %s", err)
}

outFilePath = localPath

return outFilePath, finalName, nil
Expand Down
136 changes: 10 additions & 126 deletions pkg/update/update.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package update

import (
"context"
"crypto/sha256"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"

"github.com/alexellis/arkade/pkg"
"github.com/alexellis/arkade/pkg/get"
"github.com/alexellis/go-execute/v2"
)

type Resolver interface {
GetRelease() (string, error)
GetDownloadURL(release string) (string, error)
}

type Updater struct {
resolver Resolver
verify bool
Expand All @@ -23,87 +22,12 @@ type Updater struct {
versionCheck VersionCheck
}

type Resolver interface {
GetRelease() (string, error)
GetDownloadURL(release string) (string, error)
}

type Verifier interface {
Verify(digestUrl, newBinary string) error
}

type DefaultVerifier struct {
}

func (d DefaultVerifier) Verify(downloadUrl, newBinary string) error {
digest, err := downloadDigest(downloadUrl + ".sha256")
if err != nil {
return err
}

if err := compareSHA(digest, newBinary); err != nil {
return fmt.Errorf("checksum failed for %s, error: %w", newBinary, err)
}

fmt.Printf("Checksum verified..OK.\n")
return nil
}

func downloadDigest(uri string) (string, error) {
req, err := http.NewRequest(http.MethodGet, uri, nil)
if err != nil {
return "", err
}

req.Header.Set("User-Agent", pkg.UserAgent())

res, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}

var body []byte
if res.Body != nil {
defer res.Body.Close()
body, _ = io.ReadAll(res.Body)
}

if res.StatusCode != http.StatusOK {
return "", fmt.Errorf("unexpected status code %d, body: %s", res.StatusCode, string(body))
}

return string(body), nil
}

// compareSHA returns a nil error if the local digest matches the remote digest
func compareSHA(remoteDigest, localFile string) error {

// GitHub format may sometimes include the binary name and a space, i.e.
// "9dcfd1611440aa15333980b860220bcd55ca1d6875692facc458caf7eb1cd042 bin/arkade-darwin-arm64"
if strings.Contains(remoteDigest, " ") {
t, _, _ := strings.Cut(remoteDigest, " ")
remoteDigest = t
}

localDigest, err := getSHA256Checksum(localFile)
if err != nil {
return err
}

if remoteDigest != localDigest {
return fmt.Errorf("checksum mismatch, want: %s, but got: %s", remoteDigest, localDigest)
}

return nil
}

func getSHA256Checksum(path string) (string, error) {
f, err := os.ReadFile(path)
if err != nil {
return "", err
func NewUpdater() Updater {
return Updater{
verify: true,
force: false,
versionCheck: DefaultVersionCheck{},
}

return fmt.Sprintf("%x", sha256.Sum256(f)), nil
}

func (u Updater) WithVerifier(verifier Verifier) Updater {
Expand All @@ -116,14 +40,6 @@ func (u Updater) WithResolver(resolver Resolver) Updater {
return u
}

func NewUpdater() Updater {
return Updater{
verify: true,
force: false,
versionCheck: DefaultVersionCheck{},
}
}

func (u Updater) WithVersionCheck(check VersionCheck) Updater {
u.versionCheck = check
return u
Expand Down Expand Up @@ -224,35 +140,3 @@ func replaceExec(currentExec, newBinary string) error {

return nil
}

type VersionCheck interface {
UpdateRequired(target string) (bool, error)
}

type DefaultVersionCheck struct {
Command string
Argument string
}

func (d DefaultVersionCheck) UpdateRequired(target string) (bool, error) {
executable, err := os.Executable()
if err != nil {
return false, err
}

task := execute.ExecTask{
Command: executable,
Args: []string{"version"},
}

res, err := task.Execute(context.TODO())
if err != nil {
return false, err
}

if !strings.Contains(res.Stdout, target) {
return true, nil
}

return false, nil
}
90 changes: 90 additions & 0 deletions pkg/update/verifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package update

import (
"crypto/sha256"
"fmt"
"io"
"net/http"
"os"
"strings"

"github.com/alexellis/arkade/pkg"
)

type Verifier interface {
Verify(digestUrl, newBinary string) error
}

type DefaultVerifier struct {
}

func (d DefaultVerifier) Verify(downloadUrl, newBinary string) error {
digest, err := downloadDigest(downloadUrl + ".sha256")
if err != nil {
return err
}

if err := compareSHA(digest, newBinary); err != nil {
return fmt.Errorf("checksum failed for %s, error: %w", newBinary, err)
}

fmt.Printf("Checksum verified..OK.\n")
return nil
}

func downloadDigest(uri string) (string, error) {
req, err := http.NewRequest(http.MethodGet, uri, nil)
if err != nil {
return "", err
}

req.Header.Set("User-Agent", pkg.UserAgent())

res, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}

var body []byte
if res.Body != nil {
defer res.Body.Close()
body, _ = io.ReadAll(res.Body)
}

if res.StatusCode != http.StatusOK {
return "", fmt.Errorf("unexpected status code %d, body: %s", res.StatusCode, string(body))
}

return string(body), nil
}

// compareSHA returns a nil error if the local digest matches the remote digest
func compareSHA(remoteDigest, localFile string) error {

// GitHub format may sometimes include the binary name and a space, i.e.
// "9dcfd1611440aa15333980b860220bcd55ca1d6875692facc458caf7eb1cd042 bin/arkade-darwin-arm64"
if strings.Contains(remoteDigest, " ") {
t, _, _ := strings.Cut(remoteDigest, " ")
remoteDigest = t
}

localDigest, err := getSHA256Checksum(localFile)
if err != nil {
return err
}

if remoteDigest != localDigest {
return fmt.Errorf("checksum mismatch, want: %s, but got: %s", remoteDigest, localDigest)
}

return nil
}

func getSHA256Checksum(path string) (string, error) {
f, err := os.ReadFile(path)
if err != nil {
return "", err
}

return fmt.Sprintf("%x", sha256.Sum256(f)), nil
}
Loading

0 comments on commit 8f02858

Please sign in to comment.