Skip to content

Commit

Permalink
download: Fix saving OCI bundles on disk
Browse files Browse the repository at this point in the history
This commit fixes an issue related to zero-sized bundles being saved to disk,
which can cause OPA to fail to start if a remote OCI repository is unavailable.

Fixes: open-policy-agent#6939

Signed-off-by: Sergey-Kizimov <serget.kizimov@hiya.com>
  • Loading branch information
Sergey-Kizimov authored and brettmc committed Aug 22, 2024
1 parent 0780de9 commit ad7a605
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 3 deletions.
14 changes: 11 additions & 3 deletions download/oci_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package download

import (
"bytes"
"context"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -210,13 +211,14 @@ func (d *OCIDownloader) oneShot(ctx context.Context) error {
d.SetCache(resp.etag) // set the current etag sha to the cache

if d.f != nil {
d.f(ctx, Update{ETag: resp.etag, Bundle: resp.b, Error: nil, Metrics: m, Raw: resp.raw})
d.f(ctx, Update{ETag: resp.etag, Bundle: resp.b, Error: nil, Metrics: m, Raw: resp.raw, Size: resp.size})
}
return nil
}

func (d *OCIDownloader) download(ctx context.Context, m metrics.Metrics) (*downloaderResponse, error) {
d.logger.Debug("OCI - Download starting.")
var buf bytes.Buffer

preferences := []string{fmt.Sprintf("modes=%v,%v", defaultBundleMode, deltaBundleMode)}

Expand Down Expand Up @@ -256,10 +258,15 @@ func (d *OCIDownloader) download(ctx context.Context, m metrics.Metrics) (*downl
}, nil
}
fileReader, err := os.Open(bundleFilePath)

cnt := &count{}
r := io.TeeReader(fileReader, cnt)
tee := io.TeeReader(r, &buf)

if err != nil {
return nil, err
}
loader := bundle.NewTarballLoaderWithBaseURL(fileReader, d.localStorePath)
loader := bundle.NewTarballLoaderWithBaseURL(tee, d.localStorePath)
reader := bundle.NewCustomReader(loader).
WithMetrics(m).
WithBundleVerificationConfig(d.bvc).
Expand All @@ -274,9 +281,10 @@ func (d *OCIDownloader) download(ctx context.Context, m metrics.Metrics) (*downl

return &downloaderResponse{
b: &bundleInfo,
raw: fileReader,
raw: &buf,
etag: etag,
longPoll: false,
size: cnt.Bytes(),
}, nil
}

Expand Down
50 changes: 50 additions & 0 deletions download/oci_download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/base64"
"fmt"
"net/http"
"reflect"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -382,6 +383,55 @@ func TestOCICustomAuthPlugin(t *testing.T) {
}
}

func TestOCIValidateAndInjectDefaults(t *testing.T) {
ctx := context.Background()
fixture := newTestFixture(t)
fixture.server.expEtag = "sha256:c5834dbce332cabe6ae68a364de171a50bf5b08024c27d7c08cc72878b4df7ff"

updates := make(chan *Update)

config := Config{}
if err := config.ValidateAndInjectDefaults(); err != nil {
t.Fatal(err)
}

d := NewOCI(config, fixture.client, "ghcr.io/org/repo:latest", t.TempDir()).WithCallback(func(_ context.Context, u Update) {
updates <- &u
}).WithBundlePersistence(true)

d.Start(ctx)

// Give time for some download events to occur
time.Sleep(1 * time.Second)

u1 := <-updates

if u1.Size == 0 {
t.Fatal("expected non-0 size")
}

if u1.Raw == nil {
t.Fatal("expected bundle reader to be non-nil")
}

r := bundle.NewReader(u1.Raw)

b, err := r.Read()
if err != nil {
t.Fatal(err)
}

if !reflect.DeepEqual(b.Data, u1.Bundle.Data) {
t.Fatal("expected the bundle object and reader to have the same data")
}

if len(b.Modules) != len(u1.Bundle.Modules) {
t.Fatal("expected the bundle object and reader to have the same number of bundle modules")
}

d.Stop(ctx)
}

func mockAuthPluginLookup(string) rest.HTTPAuthPlugin {
return &mockAuthPlugin{}
}
Expand Down

0 comments on commit ad7a605

Please sign in to comment.