Skip to content

Commit 76b63c9

Browse files
authored
fix: enforce hash format and fix regression (#49)
Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
1 parent b6cf9cb commit 76b63c9

File tree

4 files changed

+50
-17
lines changed

4 files changed

+50
-17
lines changed

app/cli/internal/action/artifact_download.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ func (a *ArtifactDownload) Run(downloadPath, digest string) error {
5454

5555
client := casclient.New(a.artifactsCASConn)
5656
ctx := context.Background()
57-
info, err := client.Describe(ctx, h.Hex)
57+
info, err := client.Describe(ctx, h.String())
5858
if err != nil {
59-
return fmt.Errorf("resource with digest %s not found", h)
59+
return fmt.Errorf("artifact with digest %s not found", h)
6060
}
6161

6262
if downloadPath == "" {
@@ -84,7 +84,7 @@ func (a *ArtifactDownload) Run(downloadPath, digest string) error {
8484
go renderOperationStatus(ctx, client.ProgressStatus, info.Size)
8585
defer close(client.ProgressStatus)
8686

87-
err = client.Download(ctx, w, h.Hex)
87+
err = client.Download(ctx, w, h.String())
8888
if err != nil {
8989
a.Logger.Debug().Err(err).Msg("problem downloading file")
9090
return errors.New("problem downloading file")

internal/casclient/downloader.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,23 @@ import (
2222
"io"
2323

2424
v1 "github.com/chainloop-dev/chainloop/app/artifact-cas/api/cas/v1"
25+
cr_v1 "github.com/google/go-containerregistry/pkg/v1"
2526
"google.golang.org/genproto/googleapis/bytestream"
2627
)
2728

2829
// Download downloads a file from the CAS and writes it to the provided writer
2930
func (c *Client) Download(ctx context.Context, w io.Writer, digest string) error {
30-
if digest == "" {
31-
return errors.New("a digest is required")
31+
// Check digest format, including the algorithm and the hex portion
32+
h, err := cr_v1.NewHash(digest)
33+
if err != nil {
34+
return fmt.Errorf("decoding digest: %w", err)
3235
}
3336

3437
ctx, cancel := context.WithCancel(ctx)
3538
defer cancel()
3639

3740
// Open the stream to start reading chunks
38-
reader, err := bytestream.NewByteStreamClient(c.conn).Read(ctx, &bytestream.ReadRequest{ResourceName: digest})
41+
reader, err := bytestream.NewByteStreamClient(c.conn).Read(ctx, &bytestream.ReadRequest{ResourceName: h.Hex})
3942
if err != nil {
4043
return fmt.Errorf("creating the gRPC client: %w", err)
4144
}
@@ -76,8 +79,14 @@ func (c *Client) Download(ctx context.Context, w io.Writer, digest string) error
7679
// Describe returns the metadata of a resource by its digest
7780
// We use this to get the filename and the total size of the artifact
7881
func (c *Client) Describe(ctx context.Context, digest string) (*ResourceInfo, error) {
82+
// Check digest format, including the algorithm and the hex portion
83+
h, err := cr_v1.NewHash(digest)
84+
if err != nil {
85+
return nil, fmt.Errorf("decoding digest: %w", err)
86+
}
87+
7988
client := v1.NewResourceServiceClient(c.conn)
80-
resp, err := client.Describe(ctx, &v1.ResourceServiceDescribeRequest{Digest: digest})
89+
resp, err := client.Describe(ctx, &v1.ResourceServiceDescribeRequest{Digest: h.Hex})
8190
if err != nil {
8291
return nil, fmt.Errorf("contacting API to get resource Info: %w", err)
8392
}

internal/casclient/uploader.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,25 @@ func (c *Client) UploadFile(ctx context.Context, filepath string) (*UpDownStatus
5656
return nil, fmt.Errorf("rewinding file pointer: %w", err)
5757
}
5858

59-
return c.Upload(ctx, f, path.Base(filepath), hash.Hex)
59+
return c.Upload(ctx, f, path.Base(filepath), hash.String())
6060
}
6161

6262
func (c *Client) Upload(ctx context.Context, r io.Reader, filename, digest string) (*UpDownStatus, error) {
63+
// Check digest format, including the algorithm and the hex portion
64+
h, err := cr_v1.NewHash(digest)
65+
if err != nil {
66+
return nil, fmt.Errorf("decoding digest: %w", err)
67+
}
68+
6369
ctx, cancel := context.WithCancel(ctx)
6470
defer cancel()
6571

66-
resource, err := encodeResource(filename, digest)
72+
resource, err := encodeResource(filename, h.String())
6773
if err != nil {
6874
return nil, fmt.Errorf("encoding resource name: %w", err)
6975
}
7076

71-
c.logger.Info().Msgf("uploading %s - sha256:%s", filename, digest)
77+
c.logger.Info().Msgf("uploading %s - %s", filename, h)
7278

7379
stream, err := bytestream.NewByteStreamClient(c.conn).Write(ctx)
7480
if err != nil {
@@ -127,7 +133,7 @@ doUpload:
127133

128134
latestStatus = &UpDownStatus{
129135
Filename: filename,
130-
Digest: digest,
136+
Digest: h.String(),
131137
ProcessedBytes: totalUploaded,
132138
}
133139

@@ -156,13 +162,16 @@ func encodeResource(fileName, digest string) (string, error) {
156162
return "", fmt.Errorf("file name is empty")
157163
}
158164

159-
if digest == "" {
160-
return "", fmt.Errorf("digest is empty")
165+
// Check digest format, including the algorithm and the hex portion
166+
h, err := cr_v1.NewHash(digest)
167+
if err != nil {
168+
return "", fmt.Errorf("decoding digest: %w", err)
161169
}
162170

163171
var encodedResource bytes.Buffer
164172
enc := gob.NewEncoder(&encodedResource)
165-
r := &v1.CASResource{FileName: fileName, Digest: digest}
173+
// Currently we only support SHA256
174+
r := &v1.CASResource{FileName: fileName, Digest: h.Hex}
166175

167176
if err := enc.Encode(r); err != nil {
168177
return "", err

internal/casclient/uploader_test.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ import (
1919
"bytes"
2020
"encoding/base64"
2121
"encoding/gob"
22+
"fmt"
2223
"testing"
2324

2425
v1 "github.com/chainloop-dev/chainloop/app/artifact-cas/api/cas/v1"
2526
"github.com/stretchr/testify/assert"
2627
)
2728

2829
func TestEncodeResource(t *testing.T) {
30+
const validDigestHex = "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
31+
2932
testCases := []struct {
3033
name string
3134
fileName string
@@ -44,10 +47,22 @@ func TestEncodeResource(t *testing.T) {
4447
wantError: true,
4548
},
4649
{
47-
name: "valid fields",
48-
digest: "deadbeef",
50+
name: "uncompleted digest",
51+
digest: "deadbeef",
52+
fileName: "foo.txt",
53+
wantError: true,
54+
},
55+
{
56+
name: "invalid digest",
57+
digest: "sha256:deadbeef",
58+
fileName: "foo.txt",
59+
wantError: true,
60+
},
61+
{
62+
name: "valid",
63+
digest: fmt.Sprintf("sha256:%s", validDigestHex),
4964
fileName: "foo.txt",
50-
want: &v1.CASResource{FileName: "foo.txt", Digest: "deadbeef"},
65+
want: &v1.CASResource{FileName: "foo.txt", Digest: validDigestHex},
5166
},
5267
}
5368

0 commit comments

Comments
 (0)