From 04585f6ff1bc0034e2e271deb2917839abaf13d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Apr 2026 08:05:55 +0000 Subject: [PATCH 1/4] fix(ci): resolve dotfiles default branch via remote and silence Linux gosec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolveBranch fell back to "main" whenever local origin/HEAD wasn't a symbolic ref (e.g. cloned from an empty bare), causing TestClone_DetachedHeadFallback and any user with a master-default repo to fail with "ambiguous argument 'origin/main'". Add a final fallback that consults the remote via `git ls-remote --symref origin HEAD`. Also annotate the syscall.Statfs block-size conversion in brew.CheckDiskSpace so `golangci-lint run` is clean on Linux too (stat.Bsize is int64 on linux, uint32 on darwin — value is always non-negative). --- internal/brew/brew.go | 4 +++- internal/dotfiles/dotfiles.go | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/internal/brew/brew.go b/internal/brew/brew.go index 460bb42..cf2da8a 100644 --- a/internal/brew/brew.go +++ b/internal/brew/brew.go @@ -289,7 +289,9 @@ func CheckDiskSpace() (float64, error) { if err := syscall.Statfs(home, &stat); err != nil { return 0, err } - availableGB := float64(stat.Bavail*uint64(stat.Bsize)) / (1024 * 1024 * 1024) + // stat.Bsize is uint32 on darwin and int64 on linux; the kernel always + // reports a non-negative block size so the conversion is safe. + availableGB := float64(stat.Bavail*uint64(stat.Bsize)) / (1024 * 1024 * 1024) //nolint:gosec // see comment above return availableGB, nil } diff --git a/internal/dotfiles/dotfiles.go b/internal/dotfiles/dotfiles.go index 519a251..38a17de 100644 --- a/internal/dotfiles/dotfiles.go +++ b/internal/dotfiles/dotfiles.go @@ -159,6 +159,19 @@ func resolveBranch(dotfilesPath string) string { branch = strings.TrimPrefix(ref, "refs/remotes/origin/") } } + // origin/HEAD may not be configured locally — ask the remote what its default branch is. + if branch == "" || branch == "HEAD" { + if out, err := gitOutputFunc([]string{"-C", dotfilesPath, "ls-remote", "--symref", "origin", "HEAD"}); err == nil { + for _, line := range strings.Split(string(out), "\n") { + if rest, ok := strings.CutPrefix(line, "ref: "); ok { + if fields := strings.Fields(rest); len(fields) >= 1 { + branch = strings.TrimPrefix(fields[0], "refs/heads/") + break + } + } + } + } + } if branch == "" || branch == "HEAD" { return "main" } From b52f07252fa3f4931ba357eab701b78d33953791 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Apr 2026 08:12:22 +0000 Subject: [PATCH 2/4] ci: bump golangci-lint-action to v7 and migrate labeler config to v5 - golangci/golangci-lint-action@v6 only supports golangci-lint v1; with the recent bump to v2.11.4 it errors out at startup. Bump the action to v7, which is the v2-compatible release. - actions/labeler@v5 requires the new `changed-files` schema. The current config uses the v4 flat-glob form, so every PR fails labeling with "found unexpected type for label 'catalog'". Convert each entry to the v5 `changed-files: any-glob-to-any-file` form. --- .github/labeler.yml | 34 +++++++++++++++++++++++++--------- .github/workflows/test.yml | 2 +- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index f8fc354..d3eb041 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,24 +1,40 @@ catalog: - - internal/config/data/packages.yaml + - changed-files: + - any-glob-to-any-file: + - internal/config/data/packages.yaml brew: - - internal/brew/** + - changed-files: + - any-glob-to-any-file: + - internal/brew/** installer: - - internal/installer/** + - changed-files: + - any-glob-to-any-file: + - internal/installer/** ci: - - .github/workflows/** + - changed-files: + - any-glob-to-any-file: + - .github/workflows/** docs: - - "*.md" - - docs/** + - changed-files: + - any-glob-to-any-file: + - "*.md" + - docs/** tests: - - "**/*_test.go" + - changed-files: + - any-glob-to-any-file: + - "**/*_test.go" snapshot: - - internal/snapshot/** + - changed-files: + - any-glob-to-any-file: + - internal/snapshot/** ui: - - internal/ui/** + - changed-files: + - any-glob-to-any-file: + - internal/ui/** diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 24bf00b..8c23e68 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: with: go-version-file: "go.mod" - name: golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v7 with: version: v2.11.4 From 7d66ddc251d0a4d6230ddd5d823281457f99b002 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Apr 2026 08:15:12 +0000 Subject: [PATCH 3/4] ci(lint): move dir exclusions out of run.exclude-dirs (rejected by v2.11.4) golangci-lint v2.11.4 enforces a stricter schema than 2.5 and rejects the deprecated `run.exclude-dirs` key with "additional properties 'exclude-dirs' not allowed". Move the directory list to `linters.exclusions.paths` (the v2 location) and drop the now-redundant per-path testutil rule. --- .golangci.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index df49b3f..ef86cb7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,9 +2,6 @@ version: "2" run: timeout: 5m - exclude-dirs: - - vendor - - testutil formatters: enable: @@ -46,13 +43,11 @@ linters: excludes: - G304 # File path provided as taint input — acceptable for CLI tools exclusions: + paths: + - vendor + - testutil rules: - path: "_test\\.go" linters: - errcheck - gosec - - path: "testutil/" - linters: - - gosec - - errcheck - - unused From 22f8692117782f5ac9eb833abab0685fed9d6793 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 19 Apr 2026 08:31:05 +0000 Subject: [PATCH 4/4] fix(snapshot): CaptureNpm returns []string{} instead of nil when no globals When npm is installed but `npm list -g --depth=0 --parseable` returns only the prefix line (or only npm/corepack), the loop never appends and `var packages []string` stays nil. TestCaptureNpm_NoPanic asserts the returned slice is not nil, so the test fails on macOS-CI runners where npm is present but has no user-installed globals. Initialise as an empty slice to match the early-return contract. --- internal/snapshot/capture.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/snapshot/capture.go b/internal/snapshot/capture.go index e65f251..51c5987 100644 --- a/internal/snapshot/capture.go +++ b/internal/snapshot/capture.go @@ -183,7 +183,7 @@ func CaptureNpm() ([]string, error) { if len(lines) <= 1 { return []string{}, nil } - var packages []string + packages := []string{} for _, line := range lines[1:] { line = strings.TrimSpace(line) if line == "" {