diff --git a/.bot/prompts/engineer-followup/system.md b/.bot/prompts/engineer-followup/system.md index 352ddf01..f312f633 100644 --- a/.bot/prompts/engineer-followup/system.md +++ b/.bot/prompts/engineer-followup/system.md @@ -18,7 +18,7 @@ Your job: 4. End with a short summary of what changed. Repo facts you need: - - Go 1.25 `database/sql` driver; `go build ./...` has warmed the module cache on + - Go 1.27.3 `database/sql` driver; `go build ./...` has warmed the module cache on the runner. This follow-up job wires **NO live-warehouse connection env**, so only the pure-Go **`make test`** unit suite (CGO_ENABLED=0) runs here — do NOT run or add the live e2e tests in `driver_e2e_test.go` (they need warehouse diff --git a/.bot/prompts/engineer-mention/system.md b/.bot/prompts/engineer-mention/system.md index b6326448..8dcc4d04 100644 --- a/.bot/prompts/engineer-mention/system.md +++ b/.bot/prompts/engineer-mention/system.md @@ -18,7 +18,7 @@ the relevant source before editing. Never weaken tests or alter fixtures to make a check pass. Keep public API and dependency changes out of scope unless the maintainer explicitly requests them. -The runner provides Go 1.25 and a warmed module/tool cache. Verify Go edits with +The runner provides Go 1.27.3 and a warmed module/tool cache. Verify Go edits with the affected `go test -run ./` tests, then `make test`, `make lint`, and the read-only format check `gofmt -l -s .`. This job runs the pure-Go driver with CGO_ENABLED=0 and GOPROXY=off. It has no live-warehouse diff --git a/.bot/prompts/engineer/system.md b/.bot/prompts/engineer/system.md index 042c6f30..9d7703a6 100644 --- a/.bot/prompts/engineer/system.md +++ b/.bot/prompts/engineer/system.md @@ -11,7 +11,7 @@ prompt covers the repo-specific facts you need to follow it. == THE REPO == A Go `database/sql` driver (module `github.com/databricks/databricks-sql-go`, Go -1.25). Source is the root package `dbsql` (`connection.go`, `connector.go`, +1.27.3). Source is the root package `dbsql` (`connection.go`, `connector.go`, `driver.go`, `statement.go`, `result.go`, `parameters.go`, …) plus subpackages `auth/`, `rows/`, `errors/`, `logger/`, `driverctx/`, `telemetry/`, and `internal/` (client, Thrift protocol, fetcher, etc.). Public API stability diff --git a/.github/workflows/engineer-bot-followup.yml b/.github/workflows/engineer-bot-followup.yml index 984b37cf..8dc8c33e 100644 --- a/.github/workflows/engineer-bot-followup.yml +++ b/.github/workflows/engineer-bot-followup.yml @@ -100,7 +100,7 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false - name: Build + warm caches (pure-Go; while JFrog creds are present) diff --git a/.github/workflows/engineer-bot-mention.yml b/.github/workflows/engineer-bot-mention.yml index e8af5072..1a57f50d 100644 --- a/.github/workflows/engineer-bot-mention.yml +++ b/.github/workflows/engineer-bot-mention.yml @@ -103,7 +103,7 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false - name: Build and warm Go caches diff --git a/.github/workflows/engineer-bot.yml b/.github/workflows/engineer-bot.yml index 76b8f038..f9bdb3e1 100644 --- a/.github/workflows/engineer-bot.yml +++ b/.github/workflows/engineer-bot.yml @@ -75,7 +75,7 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false - name: Build driver + warm caches (pure-Go; while JFrog creds are present) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e60f5e76..92e32bb6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -33,28 +33,21 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false - name: Lint uses: golangci/golangci-lint-action@db582008a42febd596419635a5abc9d9815daa9c # v9.2.1 with: - # v2.x is built with go 1.25+, which is required so the - # linter can read Go 1.25 stdlib export data. The v1 family - # was built with go ≤1.23 and produces "could not import - # sync/atomic" typecheck errors against our `go 1.25.0` - # directive. - version: 'v2.12' + # Build the linter with the same Go toolchain as the driver. + version: 'v2.15.0' + install-mode: goinstall build-and-test: name: Test and Build strategy: - # Matches Go's release support window. Per go.dev/doc/devel/release, - # only the latest two major releases receive security patches. - # As of 2026-05 that's 1.25 (Active LTS) and 1.26. The protected - # runners pin GOTOOLCHAIN=local so we can't include 1.24 — Go would - # refuse to satisfy the `go 1.25.0` directive without auto-downloading. + # Test the minimum patched toolchain and the latest 1.27 patch. matrix: - go-version: ['1.25.x', '1.26.x'] + go-version: ['1.27.3', '1.27.x'] runs-on: group: databricks-protected-runner-group labels: linux-ubuntu-latest @@ -70,6 +63,7 @@ jobs: uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version: ${{ matrix.go-version }} + check-latest: true cache: false - name: Cache Go artifacts @@ -171,7 +165,7 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false # Install the exact toolchain the kernel .a is built with. rust-toolchain.toml diff --git a/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index 569d9e86..096a0240 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -49,7 +49,7 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false - name: Get dependencies @@ -141,7 +141,7 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: - go-version: '1.25.x' + go-version: '1.27.3' cache: false # Keep in lockstep with rust-toolchain.toml's channel (it governs the archive diff --git a/.github/workflows/securityScan.yml b/.github/workflows/securityScan.yml index 8aca3af7..07ebd103 100644 --- a/.github/workflows/securityScan.yml +++ b/.github/workflows/securityScan.yml @@ -16,13 +16,12 @@ name: Security Scan # # - workflow_dispatch: behaves like the cron run (full reporting). # -# Scanner: OSV-Scanner v2.3.8 (purl-based via OSV.dev; federates GHSA, +# Scanner: OSV-Scanner v2.7.0 (purl-based via OSV.dev; federates GHSA, # NVD, Go vuln DB, RustSec, PyPA). Reads `go.mod`/`go.sum` natively -- # no separate SBOM tool needed. # # Suppressions live in `osv-scanner.toml` as [[IgnoredVulns]] entries -# (CVE-id global; OSV-Scanner v2.3.8 doesn't support per-package CVE -# scoping). Each entry has a justification comment. +# (CVE-id global). Each entry has a justification comment. on: pull_request: @@ -46,9 +45,8 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - # JFrog OIDC + GOPROXY: skipped on fork PRs (no OIDC token from - # GitHub's perspective). Fork PRs still work because OSV-Scanner - # reads `go.mod` directly without needing to download modules. + # Fork PRs cannot obtain the JFrog OIDC token. Download the scanner + # from GitHub Releases so installation does not require GOPROXY. - name: Setup JFrog if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository uses: ./.github/actions/setup-jfrog @@ -56,20 +54,15 @@ jobs: - name: Set up Go Toolchain uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - # Must be >= the go.mod directive (1.25.0). A floating '1.25.x' - # resolves to the runner's cached latest 1.25 patch, which always - # satisfies the 1.25.0 floor. osv-scanner shells out to - # govulncheck, which loads the module with this toolchain; keeping - # the directive at the honest 1.25.0 floor (not an inflated patch) - # means '1.25.x' never falls below it. - go-version: '1.25.x' + # Match the minimum patched toolchain declared in go.mod. + go-version: '1.27.3' cache: false - name: Install osv-scanner run: | set -euo pipefail curl -fsSL -o /tmp/osv-scanner \ - https://github.com/google/osv-scanner/releases/download/v2.3.8/osv-scanner_linux_amd64 + https://github.com/google/osv-scanner/releases/download/v2.7.0/osv-scanner_linux_amd64 chmod +x /tmp/osv-scanner /tmp/osv-scanner --version @@ -151,14 +144,10 @@ jobs: # - Third-party UNKNOWN -> BLOCKING (fail closed). A scoreless # GHSA-only or MAL-* malware advisory on a dep we ship must not # slip the gate. - # - stdlib UNKNOWN -> report-only (NON-blocking). These are - # Go stdlib advisories flagged against the go.mod directive - # floor (e.g. `go 1.25.0`); they are delivered to consumers via - # GOTOOLCHAIN patch auto-download and are not a real exposure of - # the module itself. Inflating the directive to the latest patch - # purely to silence them would tighten the customer floor for no - # security gain, so we surface them (visible in the report) but - # do not block. Each finding carries `is_stdlib` for this split. + # - stdlib UNKNOWN -> report-only. Findings use the go.mod floor; + # actual exposure depends on the consumer's build toolchain. + # Consumers must rebuild with patched Go; GOTOOLCHAIN does not + # update an otherwise sufficient toolchain automatically. # # NOTE ON jq NUMBER PARSING: use `try (x|tonumber) catch null`, # NOT `x|tonumber?`. On a non-numeric string, `tonumber?` yields @@ -196,8 +185,7 @@ jobs: TOTAL_FINDINGS=$(echo "$ALL_FINDINGS" | jq 'length') # Scoreless (UNKNOWN) findings, split by stdlib vs third-party. - # stdlib UNKNOWNs are report-only (delivered via GOTOOLCHAIN, not a - # real module exposure); third-party UNKNOWNs are blocking. + # stdlib UNKNOWNs are report-only; third-party UNKNOWNs are blocking. UNKNOWN_COUNT=$(echo "$ALL_FINDINGS" | jq '[.[] | select(.severity == "UNKNOWN")] | length') UNKNOWN_STDLIB_COUNT=$(echo "$ALL_FINDINGS" | jq '[.[] | select(.severity == "UNKNOWN" and .is_stdlib)] | length') @@ -239,7 +227,7 @@ jobs: echo "" echo "- Total findings (any severity): \`$TOTAL_FINDINGS\`" echo "- Blocking findings (CVSS >= 7, or unscored non-stdlib; PR-blocking): \`$HIGH_COUNT\`" - echo "- Unscored/UNKNOWN findings: \`$UNKNOWN_COUNT\` total (of which \`$UNKNOWN_STDLIB_COUNT\` are stdlib — report-only, delivered via GOTOOLCHAIN)" + echo "- Unscored/UNKNOWN findings: \`$UNKNOWN_COUNT\` total (of which \`$UNKNOWN_STDLIB_COUNT\` are stdlib — report-only; rebuild with patched Go)" if [ "$TOTAL_FINDINGS" -gt 0 ]; then echo "" echo "All findings (sorted by severity desc):" diff --git a/CHANGELOG.md b/CHANGELOG.md index dbae70fa..61bd6c0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History +## Unreleased + +- Require Go 1.27.3 or newer to include the emSign certificate distrust fix (CVE-2026-111943). + ## v1.17.0 (2026-10-20) - Upgrade the SQL kernel bindings to v1.2.0. - Add opt-in GEOMETRY / GEOGRAPHY support on the kernel backend with `WithEnableGeoSpatialSupport` or `enableGeoSpatialSupport=true`. Enabled mode returns EWKB bytes with per-row SRIDs and geo column metadata; the default remains WKT / EWKT strings. Arrow batches retain the `{srid,wkb}` struct in enabled mode. diff --git a/Makefile b/Makefile index 9b7327b9..07fbaa33 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ help: ## Show this help. all: gen fmt lint test coverage ## format and test everything bin/golangci-lint: go.mod go.sum - GOBIN=$(CURDIR)/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 + GOBIN=$(CURDIR)/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.15.0 bin/gotestsum: go.mod go.sum @mkdir -p bin/ diff --git a/README.md b/README.md index d59054af..3fd292f8 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ parameter, whether it applies to **Both**, **Thrift-only**, or **SEA-only**. ## Building +Requires Go 1.27.3 or newer. + The two backends differ **at build time**, not just at connect. ### Thrift (default) — pure Go, no extra step diff --git a/go.mod b/go.mod index 7e3779d5..34863151 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/databricks/databricks-sql-go -go 1.25.0 +go 1.27.3 require ( github.com/apache/arrow/go/v12 v12.0.1 diff --git a/internal/client/client.go b/internal/client/client.go index fec632cd..351d1f73 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -603,7 +603,6 @@ func PooledTransport(cfg *config.Config) *http.Transport { DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, - DualStack: true, }).DialContext, TLSClientConfig: tlsConfig, ForceAttemptHTTP2: true, diff --git a/internal/errors/category_test.go b/internal/errors/category_test.go index e2e54aba..2441c16d 100644 --- a/internal/errors/category_test.go +++ b/internal/errors/category_test.go @@ -60,19 +60,23 @@ func TestCategoryFromError(t *testing.T) { }) t.Run("finds the tag through a fmt.Errorf %w wrapper", func(t *testing.T) { - inner := NewRequestError(context.TODO(), "inner", errors.New("cause")). + var inner error = NewRequestError(context.TODO(), "inner", errors.New("cause")). WithCategory(CategoryResultSet) wrapped := fmt.Errorf("outer: %w", inner) + assert.Same(t, inner, stderrors.Unwrap(wrapped)) + assert.ErrorIs(t, wrapped, inner) assert.Equal(t, CategoryResultSet, CategoryFromError(wrapped)) }) t.Run("finds the tag inside a tree-shaped chain", func(t *testing.T) { - inner := NewRequestError(context.TODO(), "inner", errors.New("cause")). + var inner error = NewRequestError(context.TODO(), "inner", errors.New("cause")). WithCategory(CategoryResultSet) joined := stderrors.Join(errors.New("sibling"), inner) + assert.ErrorIs(t, joined, inner) assert.Equal(t, CategoryResultSet, CategoryFromError(joined)) multiWrap := fmt.Errorf("a: %w, b: %w", errors.New("sibling"), inner) + assert.ErrorIs(t, multiWrap, inner) assert.Equal(t, CategoryResultSet, CategoryFromError(multiWrap)) }) } diff --git a/osv-scanner.toml b/osv-scanner.toml index 92401615..65e06c2a 100644 --- a/osv-scanner.toml +++ b/osv-scanner.toml @@ -42,9 +42,7 @@ reason = "golang.org/x/crypto/openpgp not imported by this driver (verified via id = "GO-2026-6354" # CVE-2026-78662 is a denial of service in golang.org/x/crypto/ssh. # The driver does not import ssh: `go list -buildvcs=false -deps -test ./...` -# resolves only golang.org/x/crypto/pbkdf2. There is no official v0.55.x -# backport; the first fixed release (v0.56.0) requires Go 1.26 and would raise -# the supported Go floor for code that cannot reach the vulnerable package. +# resolves only golang.org/x/crypto/pbkdf2; the vulnerable package is unreachable. ignoreUntil = 2027-03-09 reason = "golang.org/x/crypto/ssh is not imported by this driver or its tests (verified via go list -deps -test); only x/crypto/pbkdf2 is reachable. Re-review on expiry: confirm ssh remains unimported before renewing." @@ -52,8 +50,6 @@ reason = "golang.org/x/crypto/ssh is not imported by this driver or its tests (v id = "GO-2026-6355" # CVE-2026-56855 is a denial of service in golang.org/x/crypto/ssh. # The driver does not import ssh: `go list -buildvcs=false -deps -test ./...` -# resolves only golang.org/x/crypto/pbkdf2. There is no official v0.55.x -# backport; the first fixed release (v0.56.0) requires Go 1.26 and would raise -# the supported Go floor for code that cannot reach the vulnerable package. +# resolves only golang.org/x/crypto/pbkdf2; the vulnerable package is unreachable. ignoreUntil = 2027-03-09 reason = "golang.org/x/crypto/ssh is not imported by this driver or its tests (verified via go list -deps -test); only x/crypto/pbkdf2 is reachable. Re-review on expiry: confirm ssh remains unimported before renewing."