Files
Charon/docs/plans/current_spec.md
Jeremy 9f94fdeade fix(ci): migrate to pure-Go SQLite and GoReleaser v2
Fixes nightly build failures caused by:

GoReleaser v2 requiring version 2 config syntax
Zig cross-compilation failing for macOS CGO targets
SQLite Driver Migration:

Replace gorm.io/driver/sqlite with github.com/glebarez/sqlite (pure-Go)
Execute PRAGMA statements via SQL instead of DSN parameters
All platforms now build with CGO_ENABLED=0
GoReleaser v2 Migration:

Update version: 1 → version: 2
snapshot.name_template → version_template
archives.format → formats (array syntax)
archives.builds → ids
nfpms.builds → ids
Remove Zig cross-compilation environment
Also fixes Docker Compose E2E image reference:

Use CHARON_E2E_IMAGE_TAG instead of bare digest
Add fallback default for local development
All database tests pass with the pure-Go SQLite driver.
2026-01-30 13:57:01 +00:00

16 KiB

GoReleaser v2 Migration & Nightly Build Failure Remediation

Status: Active
Created: 2026-01-30
Priority: CRITICAL (Blocking Nightly Builds)


Executive Summary

The nightly build workflow (nightly-build.yml) is failing with multiple issues:

  1. GoReleaser v2 Compatibility: Config uses deprecated v1 syntax
  2. Zig Cross-Compilation: Incorrect macOS target triple format
  3. 🆕 CGO/SQLite Dependency: Disabling CGO for darwin breaks SQLite (mattn/go-sqlite3 requires CGO)

Error Messages:

only version: 2 configuration files are supported, yours is version: 1, please update your configuration

Deprecation Warnings:

  • snapshot.name_template is deprecated
  • archives.format is deprecated
  • archives.builds is deprecated
  • nfpms.builds is deprecated

Build Error (Zig):

error: unable to find or provide libc for target 'x86_64-macos.11.7.1...13.3-gnu'
info: zig can provide libc for related target x86_64-macos.11-none

🔴 Critical Dependency: SQLite CGO Issue

Problem Statement

The current SQLite driver (gorm.io/driver/sqlite) depends on mattn/go-sqlite3, which is a CGO-based library. This means:

  • CGO_ENABLED=0 will cause build failures when SQLite is used
  • Cross-compilation for darwin from Linux is blocked by CGO complexity
  • The proposed fix of disabling CGO for darwin builds will break the application

Solution: Migrate to Pure-Go SQLite

Recommended Migration Path:

Current New Notes
gorm.io/driver/sqlite github.com/glebarez/sqlite GORM-compatible pure-Go driver
mattn/go-sqlite3 (indirect) modernc.org/sqlite (indirect) Pure-Go SQLite implementation

Benefits:

  1. No CGO required for any platform
  2. Simplified cross-compilation (no Zig needed for SQLite)
  3. Smaller binary size
  4. Faster build times
  5. Same GORM API - minimal code changes required

Files Requiring SQLite Driver Changes

File Line Change Required
backend/internal/database/database.go 10 gorm.io/driver/sqlitegithub.com/glebarez/sqlite
backend/internal/testutil/db_test.go 6 gorm.io/driver/sqlitegithub.com/glebarez/sqlite
backend/cmd/seed/main.go 13 gorm.io/driver/sqlitegithub.com/glebarez/sqlite
backend/go.mod 19 Replace gorm.io/driver/sqlite with github.com/glebarez/sqlite

Issue 1: GoReleaser v1 → v2 Migration (CRITICAL)

Problem Statement

GoReleaser v2 (currently v2.13.3) no longer supports version: 1 configuration files. The nightly workflow uses GoReleaser ~> v2 which requires v2 config syntax.

Root Cause Analysis

Current .goreleaser.yaml uses deprecated v1 syntax:

version: 1  # ❌ v2 requires "version: 2"

Multiple deprecated fields need updating:

Deprecated Field v2 Replacement
snapshot.name_template snapshot.version_template
archives.format archives.formats (array)
archives.builds archives.ids
nfpms.builds nfpms.ids

GoReleaser Deprecation Reference

From goreleaser.com/deprecations:

  1. snapshot.name_templatesnapshot.version_template

    • Changed in v2.0.0
    • The template generates a version string, not a "name"
  2. archives.formatarchives.formats

    • Changed to array to support multiple formats per archive config
    • Must be formats: [tar.gz] not format: tar.gz
  3. archives.buildsarchives.ids

    • Renamed for clarity: it filters by build id, not "builds"
  4. nfpms.buildsnfpms.ids

    • Same rationale as archives

Required Changes

--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -1,4 +1,4 @@
-version: 1
+version: 2

 project_name: charon

@@ -62,10 +62,10 @@
       - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

 archives:
-  - format: tar.gz
+  - formats: [tar.gz]
     id: nix
-    builds:
+    ids:
       - linux
       - darwin
     name_template: >-
@@ -76,9 +76,9 @@
       - LICENSE
       - README.md

-  - format: zip
+  - formats: [zip]
     id: windows
-    builds:
+    ids:
       - windows
     name_template: >-
       {{ .ProjectName }}_
@@ -90,7 +90,7 @@

 nfpms:
   - id: packages
-    builds:
+    ids:
       - linux
     package_name: charon
     vendor: Charon
@@ -116,7 +116,7 @@
   name_template: 'checksums.txt'

 snapshot:
-  name_template: "{{ .Tag }}-next"
+  version_template: "{{ .Tag }}-next"

 changelog:
   sort: asc

Issue 2: Zig Cross-Compilation for macOS

Problem Statement

The nightly build fails during GoReleaser release step when cross-compiling for macOS (darwin) using Zig:

error: unable to find or provide libc for target 'x86_64-macos.11.7.1...13.3-gnu'
info: zig can provide libc for related target x86_64-macos.11-none

Root Cause Analysis

The .goreleaser.yaml darwin build uses -macos-none which is correct, but examining the actual file shows -macos-none is already in place. The error message suggests something is injecting version numbers.

Wait - Re-reading the current config, I see it actually says -macos-none already. Let me check if there's a different issue.

Actually, looking at the error more carefully:

target 'x86_64-macos.11.7.1...13.3-gnu'

This suggests the Go runtime/cgo is detecting the macOS version range and passing it to Zig incorrectly. The -gnu suffix shouldn't be there for macOS.

Current Configuration:

CC=zig cc -target {{ if eq .Arch "amd64" }}x86_64{{ else }}aarch64{{ end }}-macos-none

The current config is correct (-macos-none), but CGO may be interfering.

⚠️ UPDATE: This section is superseded by the SQLite driver migration (see "Critical Dependency: SQLite CGO Issue" above). Simply disabling CGO for darwin breaks SQLite functionality.

Actual Fix: Migrate to Pure-Go SQLite

By migrating from gorm.io/driver/sqlite (CGO) to github.com/glebarez/sqlite (pure-Go):

  1. Zig is no longer required for any platform
  2. CGO_ENABLED=0 can be used for ALL platforms (linux, darwin, windows)
  3. Cross-compilation is trivial - standard Go cross-compilation works
  4. Build times are faster - no C compiler invocation

This completely eliminates Issue 2 as a side effect of fixing the SQLite dependency issue.


Complete Updated .goreleaser.yaml

Note: After migrating to pure-Go SQLite (github.com/glebarez/sqlite), Zig cross-compilation is no longer required. All platforms now use CGO_ENABLED=0 for simpler, faster builds.

version: 2

project_name: charon

builds:
  - id: linux
    dir: backend
    main: ./cmd/api
    binary: charon
    env:
      - CGO_ENABLED=0
    goos:
      - linux
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w
      - -X github.com/Wikid82/charon/backend/internal/version.Version={{.Version}}
      - -X github.com/Wikid82/charon/backend/internal/version.GitCommit={{.Commit}}
      - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

  - id: windows
    dir: backend
    main: ./cmd/api
    binary: charon
    env:
      - CGO_ENABLED=0
    goos:
      - windows
    goarch:
      - amd64
    ldflags:
      - -s -w
      - -X github.com/Wikid82/charon/backend/internal/version.Version={{.Version}}
      - -X github.com/Wikid82/charon/backend/internal/version.GitCommit={{.Commit}}
      - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

  - id: darwin
    dir: backend
    main: ./cmd/api
    binary: charon
    env:
      - CGO_ENABLED=0
    goos:
      - darwin
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w
      - -X github.com/Wikid82/charon/backend/internal/version.Version={{.Version}}
      - -X github.com/Wikid82/charon/backend/internal/version.GitCommit={{.Commit}}
      - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

archives:
  - formats: [tar.gz]
    id: nix
    ids:
      - linux
      - darwin
    name_template: >-
      {{ .ProjectName }}_
      {{- .Version }}_
      {{- .Os }}_
      {{- .Arch }}
    files:
      - LICENSE
      - README.md

  - formats: [zip]
    id: windows
    ids:
      - windows
    name_template: >-
      {{ .ProjectName }}_
      {{- .Version }}_
      {{- .Os }}_
      {{- .Arch }}
    files:
      - LICENSE
      - README.md

nfpms:
  - id: packages
    ids:
      - linux
    package_name: charon
    vendor: Charon
    homepage: https://github.com/Wikid82/charon
    maintainer: Wikid82
    description: "Charon - A powerful reverse proxy manager"
    license: MIT
    formats:
      - deb
      - rpm
    contents:
      - src: ./backend/data/
        dst: /var/lib/charon/data/
        type: dir
      - src: ./frontend/dist/
        dst: /usr/share/charon/frontend/
        type: dir
    dependencies:
      - libc6
      - ca-certificates

checksum:
  name_template: 'checksums.txt'

snapshot:
  version_template: "{{ .Tag }}-next"

changelog:
  sort: asc
  filters:
    exclude:
      - '^docs:'
      - '^test:'

Implementation Plan

Phase 0: SQLite Driver Migration (PREREQUISITE)

Objective: Migrate from CGO-dependent SQLite to pure-Go implementation.

Files to Modify:

File Change Reason
backend/go.mod Replace gorm.io/driver/sqlite with github.com/glebarez/sqlite Pure-Go SQLite driver
backend/internal/database/database.go Update import statement New driver package
backend/internal/testutil/db_test.go Update import statement New driver package
backend/cmd/seed/main.go Update import statement New driver package

Steps:

# 1. Update go.mod - replace CGO driver with pure-Go driver
cd backend
go get github.com/glebarez/sqlite
go mod edit -droprequire gorm.io/driver/sqlite

# 2. Update import statements in Go files
# (Manual step - update imports in 3 files listed above)

# 3. Tidy dependencies
go mod tidy

# 4. Verify build works without CGO
CGO_ENABLED=0 go build ./cmd/api
CGO_ENABLED=0 go build ./cmd/seed

# 5. Run tests to verify SQLite functionality
CGO_ENABLED=0 go test ./internal/database/... -v
CGO_ENABLED=0 go test ./internal/testutil/... -v

Validation:

  • CGO_ENABLED=0 go build ./backend/cmd/api succeeds
  • CGO_ENABLED=0 go build ./backend/cmd/seed succeeds
  • All database tests pass with CGO disabled
  • go.mod no longer references gorm.io/driver/sqlite or mattn/go-sqlite3

Phase 1: Update GoReleaser Config

Files to Modify:

File Change Reason
.goreleaser.yaml Update to version 2 syntax Required for GoReleaser ~> v2
.goreleaser.yaml Remove Zig cross-compilation No longer needed with pure-Go SQLite
.goreleaser.yaml Set CGO_ENABLED=0 for ALL platforms Consistent pure-Go builds

Simplified Build Configuration (No Zig Required):

builds:
  - id: linux
    dir: backend
    main: ./cmd/api
    binary: charon
    env:
      - CGO_ENABLED=0
    goos:
      - linux
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w
      - -X github.com/Wikid82/charon/backend/internal/version.Version={{.Version}}
      - -X github.com/Wikid82/charon/backend/internal/version.GitCommit={{.Commit}}
      - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

  - id: windows
    dir: backend
    main: ./cmd/api
    binary: charon
    env:
      - CGO_ENABLED=0
    goos:
      - windows
    goarch:
      - amd64
    ldflags:
      - -s -w
      - -X github.com/Wikid82/charon/backend/internal/version.Version={{.Version}}
      - -X github.com/Wikid82/charon/backend/internal/version.GitCommit={{.Commit}}
      - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

  - id: darwin
    dir: backend
    main: ./cmd/api
    binary: charon
    env:
      - CGO_ENABLED=0
    goos:
      - darwin
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w
      - -X github.com/Wikid82/charon/backend/internal/version.Version={{.Version}}
      - -X github.com/Wikid82/charon/backend/internal/version.GitCommit={{.Commit}}
      - -X github.com/Wikid82/charon/backend/internal/version.BuildTime={{.Date}}

Phase 2: Verification Steps

# 1. Verify SQLite migration (Phase 0 complete)
cd backend
CGO_ENABLED=0 go build ./cmd/api
CGO_ENABLED=0 go test ./... -count=1

# 2. Validate the GoReleaser config locally
goreleaser check

# 3. Test snapshot build locally (no Zig required!)
goreleaser release --snapshot --skip=publish --clean

# 4. Trigger nightly workflow manually
gh workflow run nightly-build.yml -f reason="Test GoReleaser v2 migration with pure-Go SQLite"

# 5. Monitor workflow execution
gh run watch

Phase 3: Rollback Plan

If the fix fails:

SQLite Rollback:

  1. Revert go.mod to use gorm.io/driver/sqlite
  2. Revert import statement changes
  3. Re-enable CGO in GoReleaser config

GoReleaser Rollback:

  1. Revert .goreleaser.yaml changes
  2. Pin GoReleaser to v1.x in workflows:
    version: '1.26.2'  # Last v1 release
    

Requirements (EARS Notation)

  1. WHEN building for any platform, THE SYSTEM SHALL use CGO_ENABLED=0 (pure-Go builds).
  2. WHEN importing the SQLite driver, THE SYSTEM SHALL use github.com/glebarez/sqlite (pure-Go driver).
  3. WHEN GoReleaser executes, THE SYSTEM SHALL use version 2 configuration syntax.
  4. WHEN archiving builds, THE SYSTEM SHALL use formats (array) instead of deprecated format.
  5. WHEN referencing build IDs in archives/nfpms, THE SYSTEM SHALL use ids instead of deprecated builds.
  6. WHEN generating snapshot versions, THE SYSTEM SHALL use version_template instead of deprecated name_template.

Acceptance Criteria

Phase 0 (SQLite Migration):

  • backend/go.mod uses github.com/glebarez/sqlite instead of gorm.io/driver/sqlite
  • No references to mattn/go-sqlite3 in go.mod or go.sum
  • CGO_ENABLED=0 go build ./backend/cmd/api succeeds
  • CGO_ENABLED=0 go build ./backend/cmd/seed succeeds
  • All database tests pass with CGO_ENABLED=0

Phase 1 (GoReleaser v2):

  • goreleaser check passes without errors or deprecation warnings
  • Nightly build workflow completes successfully
  • Linux amd64/arm64 binaries are produced
  • Windows amd64 binary is produced
  • Darwin amd64/arm64 binaries are produced
  • .deb and .rpm packages are produced for Linux
  • No deprecation warnings in CI logs
  • No Zig-related errors in build logs

Risk Assessment

Risk Likelihood Impact Mitigation
Pure-Go SQLite has different behavior Low Medium Run full test suite; compare query results
Pure-Go SQLite performance differs Low Low Run benchmarks; acceptable for typical workloads
Other undocumented v2 breaking changes Low Medium Monitor GoReleaser changelog; test locally first
Import statement missed in some file Low High Use grep to find all gorm.io/driver/sqlite imports

References


ARCHIVED: Other CI Issues (Separate from GoReleaser)

The following issues are documented separately and may be addressed in future PRs:

  1. Playwright E2E - Emergency Server Connectivity - See docs/plans/e2e_remediation_spec.md
  2. Trivy Scan - Image Reference Validation - See docs/plans/docker_compose_ci_fix.md