From f809066b0745769876be8006e00dcf44017ffe96 Mon Sep 17 00:00:00 2001 From: Alessio Greggi Date: Sat, 24 Jan 2026 04:59:56 +0100 Subject: [PATCH] feat(vex): support per-repo tls configuration (#10030) Signed-off-by: Alessio Greggi Co-authored-by: knqyf263 --- docs/guide/supply-chain/vex/repo.md | 11 +++++++++ pkg/downloader/download.go | 4 ++- pkg/vex/repo/manager.go | 6 ++++- pkg/vex/repo/manager_test.go | 38 ++++++++++++++++++++++------- pkg/vex/repo/repo.go | 10 ++++++-- pkg/vex/repo/repo_test.go | 6 +++-- 6 files changed, 60 insertions(+), 15 deletions(-) diff --git a/docs/guide/supply-chain/vex/repo.md b/docs/guide/supply-chain/vex/repo.md index b6c641aee9..eb7fd4944f 100644 --- a/docs/guide/supply-chain/vex/repo.md +++ b/docs/guide/supply-chain/vex/repo.md @@ -80,6 +80,17 @@ For private repositories: token: "my-token" ``` +#### TLS Verification + +In some cases, you might want to skip the TLS verification, per-repository: + +```yaml +- name: custom + url: https://example.com/custom-repo + enabled: true + insecure: true +``` + #### Repository Priority The priority of VEX repositories is determined by their order in the configuration file. diff --git a/pkg/downloader/download.go b/pkg/downloader/download.go index da3a9afd90..f47d0c9817 100644 --- a/pkg/downloader/download.go +++ b/pkg/downloader/download.go @@ -105,6 +105,7 @@ func Download(ctx context.Context, src, dst, pwd string, opts Options) (string, } type CustomTransport struct { + insecure bool auth Auth cachedETag string newETag string @@ -112,6 +113,7 @@ type CustomTransport struct { func NewCustomTransport(opts Options) *CustomTransport { return &CustomTransport{ + insecure: opts.Insecure, auth: opts.Auth, cachedETag: opts.ETag, } @@ -127,7 +129,7 @@ func (t *CustomTransport) RoundTrip(req *http.Request) (*http.Response, error) { req.SetBasicAuth(t.auth.Username, t.auth.Password) } - transport := xhttp.RoundTripper(req.Context()) + transport := xhttp.RoundTripper(req.Context(), xhttp.WithInsecure(t.insecure)) if req.URL.Host == "github.com" { transport = NewGitHubTransport(req.URL, t.auth.Token) } diff --git a/pkg/vex/repo/manager.go b/pkg/vex/repo/manager.go index 8fe2d90190..bcbce9bedb 100644 --- a/pkg/vex/repo/manager.go +++ b/pkg/vex/repo/manager.go @@ -173,7 +173,11 @@ func (m *Manager) List(ctx context.Context) error { if !repo.Enabled { status = "Disabled" } - output.WriteString(fmt.Sprintf("- Name: %s\n URL: %s\n Status: %s\n\n", repo.Name, repo.URL, status)) + tlsVerify := "" + if repo.Insecure { + tlsVerify = "\n TLS Verify: No" + } + output.WriteString(fmt.Sprintf("- Name: %s\n URL: %s\n Status: %s%s\n\n", repo.Name, repo.URL, status, tlsVerify)) } } diff --git a/pkg/vex/repo/manager_test.go b/pkg/vex/repo/manager_test.go index 74aa7a05e7..97faf4cfb7 100644 --- a/pkg/vex/repo/manager_test.go +++ b/pkg/vex/repo/manager_test.go @@ -154,9 +154,10 @@ func TestManager_DownloadRepositories(t *testing.T) { config: repo.Config{ Repositories: []repo.Repository{ { - Name: "test-repo", - URL: ts.URL, - Enabled: true, + Name: "test-repo", + URL: ts.URL, + Enabled: true, + Insecure: true, }, }, }, @@ -187,9 +188,10 @@ func TestManager_DownloadRepositories(t *testing.T) { Enabled: true, }, { - Name: "test-repo", - URL: ts.URL, - Enabled: true, + Name: "test-repo", + URL: ts.URL, + Enabled: true, + Insecure: true, }, }, }, @@ -212,6 +214,22 @@ func TestManager_DownloadRepositories(t *testing.T) { wantErr: "failed to download the repository", wantDownload: false, }, + { + name: "download error insecure flag false", + config: repo.Config{ + Repositories: []repo.Repository{ + { + Name: "test-repo", + URL: ts.URL, + Enabled: true, + Insecure: false, + }, + }, + }, + location: ts.URL + "/archive.zip", + wantErr: "failed to download the repository", + wantDownload: false, + }, } for _, tt := range tests { @@ -262,9 +280,10 @@ func TestManager_List(t *testing.T) { Enabled: true, }, { - Name: "custom", - URL: "https://example.com/custom-vex-repo", - Enabled: false, + Name: "custom", + URL: "https://example.com/custom-vex-repo", + Enabled: false, + Insecure: true, }, }, }, @@ -277,6 +296,7 @@ func TestManager_List(t *testing.T) { - Name: custom URL: https://example.com/custom-vex-repo Status: Disabled + TLS Verify: No `, }, diff --git a/pkg/vex/repo/repo.go b/pkg/vex/repo/repo.go index 9749d1aef8..d8442aec1b 100644 --- a/pkg/vex/repo/repo.go +++ b/pkg/vex/repo/repo.go @@ -93,6 +93,7 @@ type Repository struct { Username string Password string Token string // For Bearer + Insecure bool dir string // Root directory for this VEX repository, $CACHE_DIR/vex/repositories/$REPO_NAME/ } @@ -164,7 +165,9 @@ func (r *Repository) downloadManifest(ctx context.Context, opts Options) error { log.DebugContext(ctx, "Downloading the repository metadata...", log.String("url", u.String()), log.String("dst", r.dir)) _, err = downloader.Download(ctx, u.String(), filepath.Join(r.dir, manifestFile), ".", downloader.Options{ - Insecure: opts.Insecure, + // if one between global and per-repo insecure option is set, + // we set it to true accordingly + Insecure: opts.Insecure || r.Insecure, Auth: downloader.Auth{ Username: r.Username, Password: r.Password, @@ -239,8 +242,11 @@ func (r *Repository) download(ctx context.Context, ver Version, dst string, opts logger := log.With(log.String("repo", r.Name)) logger.DebugContext(ctx, "Downloading repository to cache dir...", log.String("url", loc.URL), log.String("dir", dst), log.String("etag", etags[loc.URL])) + etag, err := downloader.Download(ctx, loc.URL, dst, ".", downloader.Options{ - Insecure: opts.Insecure, + // if one between global and per-repo insecure option is set, + // we set it to true accordingly + Insecure: opts.Insecure || r.Insecure, Auth: downloader.Auth{ Username: r.Username, Password: r.Password, diff --git a/pkg/vex/repo/repo_test.go b/pkg/vex/repo/repo_test.go index 2d190554df..24cc8929f4 100644 --- a/pkg/vex/repo/repo_test.go +++ b/pkg/vex/repo/repo_test.go @@ -301,7 +301,9 @@ func TestRepository_Update(t *testing.T) { tt.setup(t, tempDir, &r) ctx := clock.With(t.Context(), tt.clockTime) - err = r.Update(ctx, repo.Options{}) + err = r.Update(ctx, repo.Options{ + Insecure: true, + }) if tt.wantErr != "" { assert.ErrorContains(t, err, tt.wantErr) return @@ -344,7 +346,7 @@ func setUpManifest(t *testing.T, dir, url string) { } func setUpRepository(t *testing.T) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + return httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/archive.zip": if r.Header.Get("If-None-Match") == "current-etag" {