From d4cfb786b240ba3b1767f60d20d19b80bff3cbd9 Mon Sep 17 00:00:00 2001 From: Arpit Jain Date: Sat, 15 Aug 2026 06:40:13 +0900 Subject: [PATCH] Report a malformed github release slug instead of panicking fetchTagSelection splits opts.Slug on / and indexes element 1 without checking. Nothing validates the slug's shape between vendir.yml and that line, so a config with a missing organization, e.g. githubRelease: slug: myrepo tagSelection: {...} crashes the sync: panic: runtime error: index out of range [1] with length 1 The split happens before the API call, so it fails with no network and without a token. Return the format error instead. Signed-off-by: Arpit Jain --- pkg/vendir/fetch/githubrelease/sync.go | 6 ++-- .../fetch/githubrelease/sync_slug_test.go | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 pkg/vendir/fetch/githubrelease/sync_slug_test.go diff --git a/pkg/vendir/fetch/githubrelease/sync.go b/pkg/vendir/fetch/githubrelease/sync.go index 94629b93..e4c8ce65 100644 --- a/pkg/vendir/fetch/githubrelease/sync.go +++ b/pkg/vendir/fetch/githubrelease/sync.go @@ -237,8 +237,10 @@ func (d Sync) matchesAssetName(name string) (bool, error) { func (d Sync) fetchTagSelection() (string, error) { listOpt := github.ListOptions{PerPage: 40} tags := []string{} - ownerName := strings.Split(d.opts.Slug, "/")[0] - repoName := strings.Split(d.opts.Slug, "/")[1] + ownerName, repoName, found := strings.Cut(d.opts.Slug, "/") + if !found || ownerName == "" || repoName == "" { + return "", fmt.Errorf("Expected github release slug to be in 'organization/repository' format, but was '%s'", d.opts.Slug) + } for { tagList, resp, err := d.client.Repositories.ListTags(context.Background(), ownerName, repoName, &listOpt) diff --git a/pkg/vendir/fetch/githubrelease/sync_slug_test.go b/pkg/vendir/fetch/githubrelease/sync_slug_test.go new file mode 100644 index 00000000..241f99f8 --- /dev/null +++ b/pkg/vendir/fetch/githubrelease/sync_slug_test.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Carvel Authors. +// SPDX-License-Identifier: Apache-2.0 + +package githubrelease + +import ( + "strings" + "testing" + + ctlconf "carvel.dev/vendir/pkg/vendir/config" +) + +// A slug is taken from vendir.yml as written, and nothing validates its shape +// before it is split, so a missing organization used to be an index panic. +func TestFetchTagSelectionRejectsMalformedSlug(t *testing.T) { + for _, slug := range []string{"norepo", "", "/repo", "owner/"} { + d := Sync{opts: ctlconf.DirectoryContentsGithubRelease{Slug: slug}} + + _, err := d.fetchTagSelection() + if err == nil { + t.Errorf("slug %q: expected an error, got none", slug) + continue + } + if !strings.Contains(err.Error(), "organization/repository") { + t.Errorf("slug %q: expected a format error, got %v", slug, err) + } + } +}