Skip to content

Latest commit

 

History

History
471 lines (350 loc) · 13.7 KB

dependency-pinning.md

File metadata and controls

471 lines (350 loc) · 13.7 KB
Status Active
Owner HyperFleet Platform Team
Last Updated 2026-01-26

Dependency and Tool Version Pinning Standard

Table of Contents

Overview

Prescribes how dependencies must be pinned for reproducible builds across all HyperFleet repositories. Covers Go module pinning, container image digest pinning, and tooling version management. Ensures that builds are deterministic and that supply chain risks from floating dependency versions are minimized.


All HyperFleet repositories containing Go code MUST use Bingo to pin development tool versions for reproducible builds across all environments.

Problem

  • Repos use different approaches for managing tool versions
  • CI builds produce inconsistent results based on installed tool versions
  • Non-reproducible builds due to lack of explicit version pinning
  • Tool dependency conflicts break builds unpredictably

Solution: Bingo

Feature Bingo tools.go Go 1.24+ tool
Mechanism Nested modules in .bingo/ tools.go file with build tags tool directive in go.mod
Dependency Isolation ✅ Total (Each tool has its own .mod) ❌ None (Pollutes go.mod) ❌ None (Pollutes go.mod)
Version Conflicts ✅ Zero (Tools are isolated islands) ❌ High (Tool vs. App conflicts) ❌ High (Graph is shared)
Go version Any with modules Any with modules Requires 1.24+
CI Cache Efficiency ✅ Excellent (Binaries cached by hash) ❌ Poor (Recompiles often) Medium (Go build cache)

Rationale: In a microservices architecture like HyperFleet, stability is paramount. We cannot accept a risk where updating a CLI tool (like a linter or generator) forces an upgrade of production libraries due to a shared dependency graph in go.mod.

Bingo provides the necessary "firewall" between development tools and production code. Your root go.mod remains clean, containing only the code required to run your service. The linter's heavy dependencies never touch your production dependency graph.


Directory Structure and File Naming

Standard Directory Layout

Every repository using Bingo MUST follow this structure:

repo-root/
├── .bingo/
│   ├── .gitignore                    # Git ignore rules for binaries
│   ├── Variables.mk                  # Makefile integration (auto-generated)
│   │
│   ├── golangci-lint.mod             # Tool version specification
│   ├── golangci-lint.sum             # Dependency checksums
│   ├── golangci-lint-v2.1.6          # Compiled binary (gitignored)
│   │
│   ├── mockgen.mod                   # Tool version specification
│   ├── mockgen.sum                   # Dependency checksums
│   ├── mockgen-v1.6.0                # Compiled binary (gitignored)
│   │
│   ├── oapi-codegen.mod              # Tool version specification
│   ├── oapi-codegen.sum              # Dependency checksums
│   └── oapi-codegen-v2.5.0           # Compiled binary (gitignored)
│
├── Makefile                          # MUST include .bingo/Variables.mk
├── go.mod                            # Main module (NO tool dependencies)
└── go.sum                            # Main checksums (NO tool checksums)

File Naming Conventions

Tool Module Files

Pattern: <tool-name>.mod and <tool-name>.sum

  • Naming: Use the tool's canonical binary name
  • Format: Lowercase with hyphens (e.g., golangci-lint, NOT golangci_lint)
  • Derivation: Bingo auto-derives from the import path's last component

Binary Files

Pattern: <tool-name>-v<version>

  • Format: {tool-name}-v{semantic-version}
  • Generated: Automatically by Bingo
  • Gitignored: MUST NOT be committed (pattern *-v[0-9]* in .gitignore)

Variables.mk

  • Purpose: Auto-generated Makefile variables for each tool
  • Format: Tool name in uppercase with underscores
  • Location: .bingo/Variables.mk
  • Generated by: bingo get and bingo init

Quick Start

Initialize in a Repository

# 1. Install Bingo (optional - can bootstrap from .mod files)
go install github.com/bwplotka/bingo@latest

# 2. Initialize .bingo directory
bingo init

# 3. Add required tools
bingo get github.com/golangci/golangci-lint/cmd/golangci-lint@v2.1.6

# 4. Update Makefile
grep -q '.bingo/Variables.mk' Makefile || cat >> Makefile <<'EOF'
include .bingo/Variables.mk

.PHONY: lint
lint: $(GOLANGCI_LINT)
 $(GOLANGCI_LINT) run ./...
EOF

# 5. Test
make lint

# 6. Commit
git add .bingo/ Makefile
git commit -m "build: add Bingo tool version pinning"

How to Add New Tools

Basic Command

# Add specific version (recommended)
bingo get <import-path>@<version>

# Example
bingo get github.com/golangci/golangci-lint/cmd/golangci-lint@v2.1.6

Complete Workflow

# 1. Add tool
bingo get github.com/golangci/golangci-lint/cmd/golangci-lint@v2.1.6

# 2. Verify
bingo list
ls .bingo/golangci-lint*  # Should show .mod, .sum, binary

# 3. Add Makefile target (skip if already exists)
grep -q 'lint.*GOLANGCI_LINT' Makefile || cat >> Makefile <<'EOF'
.PHONY: lint
lint: $(GOLANGCI_LINT)
 $(GOLANGCI_LINT) run ./...
EOF

# 4. Test
make lint

# 5. Commit
git add .bingo/golangci-lint.{mod,sum} .bingo/Variables.mk Makefile
git commit -m "build: add golangci-lint v2.1.6"

Version Options

# Specific version (recommended)
bingo get github.com/tool/cmd/tool@v1.2.3

# Latest version
bingo get github.com/tool/cmd/tool

# Commit SHA (for unreleased fixes)
bingo get github.com/tool/cmd/tool@abc1234

# Custom name (avoid conflicts)
bingo get -n custom-name github.com/tool/cmd/tool

Common Tools Quick Reference

Use Case Tool Command
Linting golangci-lint bingo get github.com/golangci/golangci-lint/cmd/golangci-lint@v2.1.6
Mocks mockgen bingo get go.uber.org/mock/mockgen@v0.5.0
OpenAPI oapi-codegen bingo get github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.5.0
Kubernetes CRDs controller-gen bingo get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.20.0
Protobuf protoc-gen-go bingo get google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11
gRPC protoc-gen-go-grpc bingo get google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.78.0

Makefile Variable Mapping

Bingo auto-generates uppercase variables:

Tool Name Makefile Variable
golangci-lint $(GOLANGCI_LINT)
mockgen $(MOCKGEN)
oapi-codegen $(OAPI_CODEGEN)
controller-gen $(CONTROLLER_GEN)

Common Operations

Upgrade Tool

# Upgrade to latest
bingo get github.com/golangci/golangci-lint/cmd/golangci-lint

# Upgrade to specific version
bingo get github.com/golangci/golangci-lint/cmd/golangci-lint@v2.2.0

# Review and commit
git diff .bingo/golangci-lint.mod
git add .bingo/golangci-lint.{mod,sum}
git commit -m "build: upgrade golangci-lint to v2.2.0"

Remove Tool

bingo rm golangci-lint

List Tools

bingo list

Makefile Targets for Tool Installation

Required Targets

All repositories MUST provide these targets:

include .bingo/Variables.mk

# Install all required tools (for initial setup)
.PHONY: tools-install
tools-install:
 @echo "Installing Bingo tools..."
 bingo get github.com/golangci/golangci-lint/cmd/golangci-lint@v2.1.6
 bingo get go.uber.org/mock/mockgen@v0.5.0
 bingo get github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.5.0
 @echo "Tools installed successfully!"

# List installed tools
.PHONY: tools-list
tools-list:
 @bingo list

# Update all tools to latest versions
.PHONY: tools-update
tools-update:
 @echo "Updating tools to latest versions..."
 bingo get github.com/golangci/golangci-lint/cmd/golangci-lint
 bingo get go.uber.org/mock/mockgen
 bingo get github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
 @echo "Tools updated!"

# Use tools in standard targets
.PHONY: lint
lint: $(GOLANGCI_LINT)
 $(GOLANGCI_LINT) run ./...

.PHONY: generate
generate: $(MOCKGEN) $(OAPI_CODEGEN)
 go generate ./...

Target Descriptions

Target Purpose When to Use
tools-install Install all tools at pinned versions First-time setup, onboarding new developers
tools-list List all installed tools and versions Check current tool versions
tools-update Update all tools to latest versions Monthly maintenance, security updates
lint Run linters using pinned tools Pre-commit, CI pipeline
generate Generate code using pinned tools After spec changes, pre-commit

How It Works

# Variables.mk provides tool paths
$(GOLANGCI_LINT) → .bingo/golangci-lint-v2.1.6

# If binary missing, auto-builds from .mod file
lint: $(GOLANGCI_LINT)  # Triggers build if needed
 $(GOLANGCI_LINT) run ./...

Key behaviors:

  • Tool binaries auto-build from .mod files when missing
  • Exact pinned versions always used (no surprises)
  • tools-install useful for new developer onboarding
  • tools-update updates versions in .mod files

CI Integration Pattern

GitHub Actions Example

name: CI

on:
  pull_request:
  push:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      # Cache Bingo tools
      - uses: actions/cache@v4
        with:
          path: .bingo
          key: ${{ runner.os }}-${{ runner.arch }}-bingo-${{ hashFiles('.bingo/*.mod') }}
          restore-keys: |
            ${{ runner.os }}-${{ runner.arch }}-bingo-

      - name: Run linter
        run: make lint  # Bingo auto-builds tool

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Run tests
        run: make test

  verify-generated:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - uses: actions/cache@v4
        with:
          path: .bingo
          key: ${{ runner.os }}-${{ runner.arch }}-bingo-${{ hashFiles('.bingo/*.mod') }}

      - name: Regenerate code
        run: make generate

      - name: Check for changes
        run: |
            if ! git diff --exit-code; then
                echo "::error::Generated code is out of sync. Run 'make generate' locally and commit the changes."
                git diff --stat
                exit 1
          fi

Key points:

  • No Bingo installation needed in CI
  • Tools build automatically from .mod files
  • Cache .bingo/ using hash of *.mod files for faster builds
  • Separate jobs for lint, test, and code generation verification

Template .bingo Directory

.bingo/.gitignore

# Ignore compiled tool binaries (Bingo format: tool-name-v1.2.3)
*-v[0-9]*

# Keep module definitions
!*.mod
!*.sum

# Keep Makefile variables
!Variables.mk

# Keep this gitignore
!.gitignore

Makefile Integration

See Makefile Targets for Tool Installation for complete Makefile examples.

GitHub Actions Integration

See CI Integration Pattern for complete GitHub Actions examples.


References

Documentation

Related HyperFleet Standards