From 6cd467bb05a1a66c6a10526230fa853aaa818e55 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 03:58:10 +0000 Subject: [PATCH 1/6] refactor: remove git binary dependency by using go-git for ls-remote * Replaced `os/exec` git call in `internal/poller/poller.go` with `github.com/go-git/go-git/v5` * Removed `git` package installation from `Dockerfile` as it is no longer needed Co-authored-by: starpia-forge <157299292+starpia-forge@users.noreply.github.com> --- Dockerfile | 4 ++-- internal/poller/poller.go | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index a19c37b..5476d6b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,8 +15,8 @@ RUN CGO_ENABLED=0 GOOS=linux go build -o gitpoll ./cmd/gitpoll # Final stage FROM alpine:latest -# Install necessary runtime dependencies (git, bash, openssh) -RUN apk add --no-cache git bash openssh +# Install necessary runtime dependencies (bash, openssh) +RUN apk add --no-cache bash openssh WORKDIR /app diff --git a/internal/poller/poller.go b/internal/poller/poller.go index b25e5c8..e03ec8a 100644 --- a/internal/poller/poller.go +++ b/internal/poller/poller.go @@ -3,9 +3,11 @@ package poller import ( "context" "math/rand" - "strings" "time" - "os/exec" + + gogit "github.com/go-git/go-git/v5" + gitconfig "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/storage/memory" "repo-gitpoll/internal/config" "repo-gitpoll/internal/events" @@ -16,20 +18,26 @@ type GitClient interface { LsRemote(ctx context.Context, repoURL, branch string) (string, error) } -// defaultGitClient implements GitClient using os/exec +// defaultGitClient implements GitClient using go-git type defaultGitClient struct{} func (c *defaultGitClient) LsRemote(ctx context.Context, repoURL, branch string) (string, error) { - // #nosec G204 - command relies on variables but is explicitly internal to the background worker configuration - cmd := exec.CommandContext(ctx, "git", "ls-remote", repoURL, branch) - out, err := cmd.Output() + rem := gogit.NewRemote(memory.NewStorage(), &gitconfig.RemoteConfig{ + Name: "origin", + URLs: []string{repoURL}, + }) + + refs, err := rem.ListContext(ctx, &gogit.ListOptions{}) if err != nil { return "", err } - parts := strings.Fields(string(out)) - if len(parts) > 0 { - return parts[0], nil + + for _, ref := range refs { + if ref.Name().Short() == branch { + return ref.Hash().String(), nil + } } + return "", nil } From 0f9a7309acb0ec53ddef68e7cd44af01090be7f1 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 04:47:17 +0000 Subject: [PATCH 2/6] refactor: remove git binary dependency by using go-git for ls-remote * Replaced `os/exec` git call in `internal/poller/poller.go` with `github.com/go-git/go-git/v5` * Adjusted go-git options to use default SSH credentials for git@ or ssh:// URLs * Removed `git` package installation from `Dockerfile` as it is no longer needed Co-authored-by: starpia-forge <157299292+starpia-forge@users.noreply.github.com> --- internal/poller/poller.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/internal/poller/poller.go b/internal/poller/poller.go index e03ec8a..a9fb747 100644 --- a/internal/poller/poller.go +++ b/internal/poller/poller.go @@ -3,10 +3,12 @@ package poller import ( "context" "math/rand" + "strings" "time" gogit "github.com/go-git/go-git/v5" gitconfig "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/storage/memory" "repo-gitpoll/internal/config" @@ -27,7 +29,16 @@ func (c *defaultGitClient) LsRemote(ctx context.Context, repoURL, branch string) URLs: []string{repoURL}, }) - refs, err := rem.ListContext(ctx, &gogit.ListOptions{}) + listOpts := &gogit.ListOptions{} + + // If it's an SSH URL, try to use default SSH auth + if strings.HasPrefix(repoURL, "git@") || strings.HasPrefix(repoURL, "ssh://") { + if auth, err := ssh.DefaultAuthBuilder("git"); err == nil { + listOpts.Auth = auth + } + } + + refs, err := rem.ListContext(ctx, listOpts) if err != nil { return "", err } From bba32cc4bc11bff39ac0b037be19ef03bc14e546 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 05:00:50 +0000 Subject: [PATCH 3/6] refactor: remove git binary dependency by using go-git for ls-remote * Replaced `os/exec` git call in `internal/poller/poller.go` with `github.com/go-git/go-git/v5` * Adjusted go-git options to use default SSH credentials and fallback to local keys for ssh URLs * Removed `git` package installation from `Dockerfile` as it is no longer needed Co-authored-by: starpia-forge <157299292+starpia-forge@users.noreply.github.com> --- internal/poller/poller.go | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/internal/poller/poller.go b/internal/poller/poller.go index a9fb747..58d5ac8 100644 --- a/internal/poller/poller.go +++ b/internal/poller/poller.go @@ -3,11 +3,13 @@ package poller import ( "context" "math/rand" - "strings" + "os" + "path/filepath" "time" gogit "github.com/go-git/go-git/v5" gitconfig "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/storage/memory" @@ -31,9 +33,32 @@ func (c *defaultGitClient) LsRemote(ctx context.Context, repoURL, branch string) listOpts := &gogit.ListOptions{} - // If it's an SSH URL, try to use default SSH auth - if strings.HasPrefix(repoURL, "git@") || strings.HasPrefix(repoURL, "ssh://") { - if auth, err := ssh.DefaultAuthBuilder("git"); err == nil { + if ep, err := transport.NewEndpoint(repoURL); err == nil && ep.Protocol == "ssh" { + user := ep.User + if user == "" { + user = "git" + } + + // Try ssh-agent first + auth, authErr := ssh.DefaultAuthBuilder(user) + + // Fallback to local keys if agent is not available + if authErr != nil { + if homeDir, err := os.UserHomeDir(); err == nil { + keys := []string{"id_ed25519", "id_rsa", "id_ecdsa", "id_dsa"} + for _, key := range keys { + keyPath := filepath.Join(homeDir, ".ssh", key) + if _, err := os.Stat(keyPath); err == nil { + if pkAuth, err := ssh.NewPublicKeysFromFile(user, keyPath, ""); err == nil { + auth = pkAuth + break + } + } + } + } + } + + if auth != nil { listOpts.Auth = auth } } From 87df0d82793d271c68a9c758e9de95caae12e9bd Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 05:39:43 +0000 Subject: [PATCH 4/6] refactor: remove git binary dependency by using go-git for ls-remote * Replaced `os/exec` git call in `internal/poller/poller.go` with `github.com/go-git/go-git/v5` * Adjusted go-git options to use default SSH credentials and fallback to local keys for ssh URLs * Removed `git` package installation from `Dockerfile` as it is no longer needed * Upgraded Go version to 1.26.1 in go.mod and Dockerfile to fix govulncheck standard library vulnerabilities * Cleaned up dummy patch artifacts Co-authored-by: starpia-forge <157299292+starpia-forge@users.noreply.github.com> --- Dockerfile | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5476d6b..c3654a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM golang:alpine AS builder +FROM golang:1.26.1-alpine AS builder WORKDIR /app # Download dependencies diff --git a/go.mod b/go.mod index 38dc531..2316440 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module repo-gitpoll -go 1.25.7 +go 1.26.1 require ( github.com/charmbracelet/bubbles v1.0.0 From 6b0a1bf8d765dbd9399960e07b272ef368ed2767 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 06:04:09 +0000 Subject: [PATCH 5/6] fix: configure golangci-lint to install from source * Configured `golangci-lint-action` to use `install-mode: goinstall` in CI/CD workflow * This prevents version mismatch errors when running the linter against the upgraded Go 1.26.1 codebase. Co-authored-by: starpia-forge <157299292+starpia-forge@users.noreply.github.com> --- .github/workflows/ci-cd.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-cd.yaml b/.github/workflows/ci-cd.yaml index 743ca3b..0e85819 100644 --- a/.github/workflows/ci-cd.yaml +++ b/.github/workflows/ci-cd.yaml @@ -34,6 +34,7 @@ jobs: with: version: latest args: --timeout=5m + install-mode: goinstall - name: Security Scan (gosec) uses: securego/gosec@master From 4bd860aa2f14ff761dc197fea8b30b1f0330baa2 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Mar 2026 06:26:34 +0000 Subject: [PATCH 6/6] fix: run gosec directly from source instead of docker action * Modified `.github/workflows/ci-cd.yaml` to run `gosec` via `go install` * This avoids a "go.mod requires go >= 1.26.1" error caused by the `securego/gosec@master` Docker action containing an older `1.26.0` toolchain. Co-authored-by: starpia-forge <157299292+starpia-forge@users.noreply.github.com> --- .github/workflows/ci-cd.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-cd.yaml b/.github/workflows/ci-cd.yaml index 0e85819..cab6b5d 100644 --- a/.github/workflows/ci-cd.yaml +++ b/.github/workflows/ci-cd.yaml @@ -37,9 +37,9 @@ jobs: install-mode: goinstall - name: Security Scan (gosec) - uses: securego/gosec@master - with: - args: ./... + run: | + go install github.com/securego/gosec/v2/cmd/gosec@latest + gosec ./... - name: Dependency Check (govulncheck) run: |