Skip to content

Remove GPL dependencies via golangci-lint binary distribution#15050

Merged
pelikhan merged 2 commits intomainfrom
copilot/remove-gpl-dependencies
Feb 12, 2026
Merged

Remove GPL dependencies via golangci-lint binary distribution#15050
pelikhan merged 2 commits intomainfrom
copilot/remove-gpl-dependencies

Conversation

Copy link
Contributor

Copilot AI commented Feb 12, 2026

The development dependency golangci-lint pulled in 6 GPL-licensed transitive dependencies incompatible with our MIT license. This blocks enterprise adoption and creates SBOM compliance issues.

Changes

Dependency removal

  • Removed golangci-lint from tools.go and go.mod
  • Eliminated 6 GPL packages: depguard, structtags, nonamedreturns, gosmopolitan, go-header, grouper
  • Net: -1012 lines from go.sum

Binary installation

  • Added install-golangci-lint Makefile target that downloads pre-built binaries from GitHub releases
  • Platform-aware: Linux/macOS/Windows, amd64/arm64
  • Idempotent version checking (v2.8.0)

CI/CD updates

  • Updated .github/workflows/ci.yml to use binary installation
  • Updated .github/actions/daily-perf-improver/build-steps/action.yml

Installation

make deps-dev              # Includes golangci-lint binary
make install-golangci-lint # Standalone installation

No configuration changes to .golangci.yml. Full linting functionality preserved.

Verification

go list -m all | grep -i "depguard\|golangci-lint"  # Empty output
golangci-lint version                                # 2.8.0
make lint                                            # Works as before
Original prompt

This section details on the original issue you should resolve

<issue_title>[gpl-dependency]Remove GPL dependencies from golangci-lint (6 GPL-licensed linters)</issue_title>
<issue_description>## Summary

The development dependency github.com/golangci/golangci-lint/v2 introduces GPL-licensed transitive dependencies that are incompatible with our MIT license. While golangci-lint itself is open-source, it bundles several linters licensed under GPL-3.0, creating license compliance risks for the project.

Dependency Chain

github.com/golangci/golangci-lint/v2 (tools.go)
  → github.com/OpenPeeDeeP/depguard/v2 (GPL-3.0)
  → github.com/ldez/structtags (GPL-3.0)
  → github.com/firefart/nonamedreturns (GPL-3.0)
  → github.com/xen0n/gosmopolitan (GPL-1.0-or-later AND GPL-3.0)
  → github.com/denis-tingaikin/go-header (GPL-3.0)
  → github.com/leonklingele/grouper (GPL-3.0)

GPL License Details

Primary GPL Dependency: depguard

Additional GPL Dependencies

  1. github.com/ldez/structtags v0.6.1 (GPL-3.0)
  2. github.com/firefart/nonamedreturns v1.0.6 (GPL-3.0)
  3. github.com/xen0n/gosmopolitan v1.3.0 (GPL-1.0-or-later AND GPL-3.0)
  4. github.com/denis-tingaikin/go-header v0.5.0 (GPL-3.0)
  5. github.com/leonklingele/grouper v1.1.2 (GPL-3.0)

Current Usage

Where It's Used

The direct dependency github.com/golangci/golangci-lint/v2 is imported in:

  • tools.go - Build-time tool dependency tracking (blank import)

Functionality Required

We use golangci-lint for:

  • Code linting with multiple linters (misspell, gomoddirectives, unconvert, testifylint)
  • Build-time code quality checks
  • CI/CD pipeline linting (make lint, make golint)
  • Development workflow linting

GPL Linters Usage Analysis

depguard linter: ❌ NOT configured or enabled in .golangci.yml

  • Purpose: Checks package imports against allowed/denied lists
  • Status: Not used by our project

Other GPL linters: ❌ NOT explicitly configured

  • These are bundled with golangci-lint but not actively enabled in our configuration

Direct GPL Usage

Analysis shows the GPL modules:

  • ❌ Are NOT directly used by our code
  • ❌ Are NOT explicitly enabled in .golangci.yml
  • ✅ Are pulled in transitively by golangci-lint
  • ⚠️ Create license compliance risk even though not actively used

Legal & Security Implications

GPL-3.0 License Restrictions

  1. Copyleft Requirements: GPL-3.0 requires derivative works to be distributed under GPL
  2. MIT Incompatibility: GPL's copyleft provisions conflict with MIT's permissive nature
  3. Distribution Risk: Binary distributions could trigger GPL obligations
  4. Dependency Contamination: GPL dependencies in build tools may affect final artifacts

Risk Assessment

Risk Level: MEDIUM-HIGH

Rationale:

  • GPL dependencies are in development toolchain (not runtime)
  • Not directly used or enabled in our configuration
  • However, bundled in binaries created by go install or go build
  • Creates potential licensing ambiguity for downstream users
  • May block enterprise adoption if license audits flag GPL in build tools

Removal/Replacement Options

Option 1: Disable GPL Linters in golangci-lint

Approach: Continue using golangci-lint but explicitly disable GPL-licensed linters

Steps:

  1. Add depguard and other GPL linters to .golangci.yml disable list
  2. Document why these linters are disabled (GPL license incompatibility)
  3. Verify GPL dependencies are not pulled into compiled binaries
  4. Update CI/CD to run without GPL linters

Complexity: Low

Breaking Changes: No - We're not using these linters currently

Pros:

  • Minimal changes to existing workflow
  • Keeps golangci-lint ecosystem
  • Clear documentation of licensing decisions

Cons:

  • Doesn't fully remove GPL from dependency tree
  • May still appear in SBOM and license audits
  • Requires ongoing vigilance as golangci-lint evolves

Option 2: Migrate to Alternative Linting Tools [RECOMMENDED]

Approach: Replace golangci-lint with MIT/Apache-licensed alternatives

Alternative Packages:

  1. staticcheck (MIT)

  2. revive (MIT)

  3. go vet...


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

- Remove golangci-lint from tools.go and go.mod (GPL dependencies eliminated)
- Add install-golangci-lint Makefile target for binary downloads
- Update CI workflow to use binary installation instead of go install
- Update daily-perf-improver action to use binary installation
- Version: v2.8.0 (consistent with previous usage)

This change eliminates all GPL-licensed transitive dependencies:
- github.com/OpenPeeDeeP/depguard/v2 (GPL-3.0)
- github.com/ldez/structtags (GPL-3.0)
- github.com/firefart/nonamedreturns (GPL-3.0)
- github.com/xen0n/gosmopolitan (GPL-1.0-or-later AND GPL-3.0)
- github.com/denis-tingaikin/go-header (GPL-3.0)
- github.com/leonklingele/grouper (GPL-3.0)

Binary installation maintains clean MIT licensing while preserving
full golangci-lint functionality.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Remove GPL dependencies from golangci-lint Remove GPL dependencies via golangci-lint binary distribution Feb 12, 2026
Copilot AI requested a review from pelikhan February 12, 2026 00:56
@pelikhan pelikhan marked this pull request as ready for review February 12, 2026 00:57
Copilot AI review requested due to automatic review settings February 12, 2026 00:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes golangci-lint from the Go module dependency graph (to eliminate GPL-licensed transitive dependencies) and replaces go install usage with a pinned prebuilt golangci-lint binary download in local dev setup and CI.

Changes:

  • Remove github.com/golangci/golangci-lint/v2 from tools.go/go.mod and prune the resulting go.sum entries.
  • Add a Makefile target to install a pinned golangci-lint release binary and wire it into deps-dev.
  • Update CI and the daily perf improver composite action to install golangci-lint via GitHub release artifacts instead of go install.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tools.go Removes the golangci-lint blank import and notes binary-based installation.
go.mod Drops the golangci-lint/v2 requirement and prunes many indirect linter deps.
go.sum Removes checksums for golangci-lint and numerous transitive linter modules.
Makefile Adds install-golangci-lint target and includes it in deps-dev.
.github/workflows/ci.yml Switches lint-go job to download/install the prebuilt golangci-lint binary.
.github/actions/daily-perf-improver/build-steps/action.yml Switches tool setup to download/install the prebuilt golangci-lint binary.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +385 to +395
DOWNLOAD_URL="https://github.com/golangci/golangci-lint/releases/download/$$GOLANGCI_LINT_VERSION/golangci-lint-$${GOLANGCI_LINT_VERSION#v}-$$GOOS-$$GOARCH.tar.gz"; \
TEMP_DIR=$$(mktemp -d); \
trap "rm -rf $$TEMP_DIR" EXIT; \
echo "Downloading golangci-lint $$GOLANGCI_LINT_VERSION for $$GOOS/$$GOARCH..."; \
if curl -sSL "$$DOWNLOAD_URL" | tar -xz -C "$$TEMP_DIR"; then \
mkdir -p "$$GOPATH/bin"; \
mv "$$TEMP_DIR"/golangci-lint-*/$$BINARY_NAME "$$GOPATH/bin/$$BINARY_NAME"; \
chmod +x "$$GOPATH/bin/$$BINARY_NAME"; \
echo "✓ golangci-lint $$GOLANGCI_LINT_VERSION installed to $$GOPATH/bin/$$BINARY_NAME"; \
else \
echo "Error: Failed to download golangci-lint from $$DOWNLOAD_URL"; \
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The golangci-lint installer downloads and executes a prebuilt binary without verifying integrity (e.g., SHA-256 checksum/signature). Since this is part of the dev toolchain, it’s still a supply-chain risk. Consider fetching the release checksums file and validating the archive before extracting (similar to the checksum tooling in install-gh-aw.sh).

Suggested change
DOWNLOAD_URL="https://github.com/golangci/golangci-lint/releases/download/$$GOLANGCI_LINT_VERSION/golangci-lint-$${GOLANGCI_LINT_VERSION#v}-$$GOOS-$$GOARCH.tar.gz"; \
TEMP_DIR=$$(mktemp -d); \
trap "rm -rf $$TEMP_DIR" EXIT; \
echo "Downloading golangci-lint $$GOLANGCI_LINT_VERSION for $$GOOS/$$GOARCH..."; \
if curl -sSL "$$DOWNLOAD_URL" | tar -xz -C "$$TEMP_DIR"; then \
mkdir -p "$$GOPATH/bin"; \
mv "$$TEMP_DIR"/golangci-lint-*/$$BINARY_NAME "$$GOPATH/bin/$$BINARY_NAME"; \
chmod +x "$$GOPATH/bin/$$BINARY_NAME"; \
echo "✓ golangci-lint $$GOLANGCI_LINT_VERSION installed to $$GOPATH/bin/$$BINARY_NAME"; \
else \
echo "Error: Failed to download golangci-lint from $$DOWNLOAD_URL"; \
TARBALL_NAME="golangci-lint-$${GOLANGCI_LINT_VERSION#v}-$$GOOS-$$GOARCH.tar.gz"; \
DOWNLOAD_URL="https://github.com/golangci/golangci-lint/releases/download/$$GOLANGCI_LINT_VERSION/$$TARBALL_NAME"; \
CHECKSUMS_URL="https://github.com/golangci/golangci-lint/releases/download/$$GOLANGCI_LINT_VERSION/golangci-lint-$${GOLANGCI_LINT_VERSION#v}-checksums.txt"; \
TEMP_DIR=$$(mktemp -d); \
trap "rm -rf $$TEMP_DIR" EXIT; \
echo "Downloading golangci-lint $$GOLANGCI_LINT_VERSION for $$GOOS/$$GOARCH..."; \
if ! curl -sSL -o "$$TEMP_DIR/$$TARBALL_NAME" "$$DOWNLOAD_URL"; then \
echo "Error: Failed to download golangci-lint from $$DOWNLOAD_URL"; \
exit 1; \
fi; \
echo "Downloading checksums from $$CHECKSUMS_URL..."; \
if ! curl -sSL -o "$$TEMP_DIR/checksums.txt" "$$CHECKSUMS_URL"; then \
echo "Error: Failed to download checksums from $$CHECKSUMS_URL"; \
exit 1; \
fi; \
EXPECTED_CHECKSUM=$$(grep " $$TARBALL_NAME$$" "$$TEMP_DIR/checksums.txt" | awk '{print $$1}'); \
if [ -z "$$EXPECTED_CHECKSUM" ]; then \
echo "Error: Checksum for $$TARBALL_NAME not found in checksums file"; \
exit 1; \
fi; \
if command -v sha256sum >/dev/null 2>&1; then \
ACTUAL_CHECKSUM=$$(sha256sum "$$TEMP_DIR/$$TARBALL_NAME" | awk '{print $$1}'); \
elif command -v shasum >/dev/null 2>&1; then \
ACTUAL_CHECKSUM=$$(shasum -a 256 "$$TEMP_DIR/$$TARBALL_NAME" | awk '{print $$1}'); \
else \
echo "Error: Neither sha256sum nor shasum is available to verify checksums"; \
exit 1; \
fi; \
if [ "$$EXPECTED_CHECKSUM" != "$$ACTUAL_CHECKSUM" ]; then \
echo "Error: Checksum verification failed for $$TARBALL_NAME"; \
echo "Expected: $$EXPECTED_CHECKSUM"; \
echo "Actual: $$ACTUAL_CHECKSUM"; \
exit 1; \
fi; \
if tar -xz -C "$$TEMP_DIR" -f "$$TEMP_DIR/$$TARBALL_NAME"; then \
mkdir -p "$$GOPATH/bin"; \
mv "$$TEMP_DIR"/golangci-lint-*/$$BINARY_NAME "$$GOPATH/bin/$$BINARY_NAME"; \
chmod +x "$$GOPATH/bin/$$BINARY_NAME"; \
echo "✓ golangci-lint $$GOLANGCI_LINT_VERSION installed to $$GOPATH/bin/$$BINARY_NAME"; \
else \
echo "Error: Failed to extract $$TEMP_DIR/$$TARBALL_NAME"; \

Copilot uses AI. Check for mistakes.
Comment on lines +846 to +859
run: |
GOLANGCI_LINT_VERSION="v2.8.0"
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
GOPATH=$(go env GOPATH)
BINARY_NAME="golangci-lint"

echo "Installing golangci-lint $GOLANGCI_LINT_VERSION for $GOOS/$GOARCH..."
DOWNLOAD_URL="https://github.com/golangci/golangci-lint/releases/download/$GOLANGCI_LINT_VERSION/golangci-lint-${GOLANGCI_LINT_VERSION#v}-$GOOS-$GOARCH.tar.gz"

curl -sSL "$DOWNLOAD_URL" | tar -xz -C /tmp
mkdir -p "$GOPATH/bin"
mv /tmp/golangci-lint-*/$BINARY_NAME "$GOPATH/bin/$BINARY_NAME"
chmod +x "$GOPATH/bin/$BINARY_NAME"
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CI step duplicates the golangci-lint download logic from the Makefile target and extracts into a shared /tmp path. To reduce drift and avoid collisions/leftovers, prefer calling make install-golangci-lint here and have the Makefile handle temp dirs/cleanup (and checksum verification).

See below for a potential fix:

      # Delegate installation to the Makefile to avoid duplication and handle temp dirs/checksums.
      - name: Install golangci-lint
        run: |
          make install-golangci-lint

Copilot uses AI. Check for mistakes.
Comment on lines +84 to 88
curl -sSL "$DOWNLOAD_URL" | tar -xz -C /tmp 2>&1 | tee -a build-steps.log
mkdir -p "$GOPATH/bin"
mv /tmp/golangci-lint-*/$BINARY_NAME "$GOPATH/bin/$BINARY_NAME" 2>&1 | tee -a build-steps.log
chmod +x "$GOPATH/bin/$BINARY_NAME"

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This installs golangci-lint by downloading and extracting an archive to /tmp without integrity verification or cleanup. For better supply-chain safety and to avoid /tmp collisions, download into a unique temp dir, verify checksums/signatures, then move the binary into place (or reuse the Makefile install target).

Suggested change
curl -sSL "$DOWNLOAD_URL" | tar -xz -C /tmp 2>&1 | tee -a build-steps.log
mkdir -p "$GOPATH/bin"
mv /tmp/golangci-lint-*/$BINARY_NAME "$GOPATH/bin/$BINARY_NAME" 2>&1 | tee -a build-steps.log
chmod +x "$GOPATH/bin/$BINARY_NAME"
TMP_DIR="$(mktemp -d)"
echo "Using temporary directory: $TMP_DIR" | tee -a build-steps.log
ARCHIVE_PATH="$TMP_DIR/golangci-lint.tar.gz"
CHECKSUM_PATH="$TMP_DIR/golangci-lint.tar.gz.sha256"
echo "Downloading golangci-lint archive..." | tee -a build-steps.log
curl -sSL -o "$ARCHIVE_PATH" "$DOWNLOAD_URL" 2>&1 | tee -a build-steps.log
echo "Downloading golangci-lint checksum..." | tee -a build-steps.log
curl -sSL -o "$CHECKSUM_PATH" "${DOWNLOAD_URL}.sha256" 2>&1 | tee -a build-steps.log
echo "Verifying golangci-lint archive checksum..." | tee -a build-steps.log
(cd "$TMP_DIR" && sha256sum -c "$(basename "$CHECKSUM_PATH")") 2>&1 | tee -a build-steps.log
echo "Extracting golangci-lint archive..." | tee -a build-steps.log
tar -xzf "$ARCHIVE_PATH" -C "$TMP_DIR" 2>&1 | tee -a build-steps.log
mkdir -p "$GOPATH/bin"
mv "$TMP_DIR"/golangci-lint-*/"$BINARY_NAME" "$GOPATH/bin/$BINARY_NAME" 2>&1 | tee -a build-steps.log
chmod +x "$GOPATH/bin/$BINARY_NAME"
echo "Cleaning up temporary directory..." | tee -a build-steps.log
rm -rf "$TMP_DIR"

Copilot uses AI. Check for mistakes.
// Package tools tracks build-time tool dependencies.
// Import tools here with blank imports to include them in go.mod.
// This ensures consistent tool versions across development and CI.
// Note: golangci-lint is installed via binary distribution to avoid GPL dependencies
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: end this sentence with a period for consistency with the surrounding comment style.

Suggested change
// Note: golangci-lint is installed via binary distribution to avoid GPL dependencies
// Note: golangci-lint is installed via binary distribution to avoid GPL dependencies.

Copilot uses AI. Check for mistakes.
@pelikhan pelikhan merged commit 9694d52 into main Feb 12, 2026
166 checks passed
@pelikhan pelikhan deleted the copilot/remove-gpl-dependencies branch February 12, 2026 01:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[gpl-dependency]Remove GPL dependencies from golangci-lint (6 GPL-licensed linters)

2 participants

Comments