Skip to content

Commit 1e2d4cf

Browse files
committed
Merge remote-tracking branch 'origin/main' into gopal.lal/ES-1804970-enforce-embedded-schema-correctness
# Conflicts: # connection.go # internal/config/config.go
2 parents 851ea14 + f0487d1 commit 1e2d4cf

78 files changed

Lines changed: 4934 additions & 3665 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Require review from eng-oss-sql-driver for CI/CD workflow changes
2+
.github/ @databricks/eng-oss-sql-driver
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Setup JFrog OIDC
2+
description: Obtain a JFrog access token via GitHub OIDC and configure Go to use JFrog as a module proxy
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- name: Get JFrog OIDC token
8+
shell: bash
9+
run: |
10+
set -euo pipefail
11+
ID_TOKEN=$(curl -sLS \
12+
-H "User-Agent: actions/oidc-client" \
13+
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
14+
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=jfrog-github" | jq .value | tr -d '"')
15+
echo "::add-mask::${ID_TOKEN}"
16+
ACCESS_TOKEN=$(curl -sLS -XPOST -H "Content-Type: application/json" \
17+
"https://databricks.jfrog.io/access/api/v1/oidc/token" \
18+
-d "{\"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\", \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", \"subject_token\": \"${ID_TOKEN}\", \"provider_name\": \"github-actions\"}" | jq .access_token | tr -d '"')
19+
echo "::add-mask::${ACCESS_TOKEN}"
20+
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
21+
echo "FAIL: Could not extract JFrog access token"
22+
exit 1
23+
fi
24+
echo "JFROG_ACCESS_TOKEN=${ACCESS_TOKEN}" >> "$GITHUB_ENV"
25+
echo "JFrog OIDC token obtained successfully"
26+
27+
- name: Configure Go
28+
shell: bash
29+
run: |
30+
set -euo pipefail
31+
echo "GOPROXY=https://databricks.jfrog.io/artifactory/api/go/db-golang,direct" >> "$GITHUB_ENV"
32+
echo "GONOSUMDB=*" >> "$GITHUB_ENV"
33+
printf "machine databricks.jfrog.io\nlogin gha-service-account\npassword %s\n" "${JFROG_ACCESS_TOKEN}" > ~/.netrc
34+
chmod 600 ~/.netrc
35+
echo "Go configured to use JFrog registry"

.github/workflows/dco-check.yml

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,51 +12,24 @@ jobs:
1212
dco-check:
1313
runs-on:
1414
group: databricks-protected-runner-group
15-
labels: [linux-ubuntu-latest]
15+
labels: linux-ubuntu-latest
1616
name: Check DCO Sign-off
1717
steps:
1818
- name: Checkout
19-
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
19+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2020
with:
2121
fetch-depth: 0
22-
ref: ${{ github.event.pull_request.head.ref }}
23-
repository: ${{ github.event.pull_request.head.repo.full_name }}
24-
25-
- name: Add upstream remote (for forks)
26-
run: |
27-
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
28-
echo "This is a fork, adding upstream remote"
29-
git remote add upstream https://github.com/${{ github.repository }}.git
30-
git fetch upstream ${{ github.event.pull_request.base.ref }}
31-
else
32-
echo "This is not a fork, using origin"
33-
fi
3422

3523
- name: Check DCO Sign-off
24+
env:
25+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
26+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
3627
run: |
3728
#!/bin/bash
3829
set -e
3930
40-
BASE_SHA="${{ github.event.pull_request.base.sha }}"
41-
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
42-
4331
echo "Checking commits from $BASE_SHA to $HEAD_SHA"
4432
45-
if ! git cat-file -e "$BASE_SHA" 2>/dev/null; then
46-
echo "Error: Base commit $BASE_SHA not found"
47-
echo "Trying to fetch from upstream..."
48-
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
49-
git fetch upstream ${{ github.event.pull_request.base.ref }}
50-
else
51-
git fetch origin ${{ github.event.pull_request.base.ref }}
52-
fi
53-
fi
54-
55-
if ! git cat-file -e "$HEAD_SHA" 2>/dev/null; then
56-
echo "Error: Head commit $HEAD_SHA not found"
57-
exit 1
58-
fi
59-
6033
COMMITS=$(git rev-list --no-merges "$BASE_SHA..$HEAD_SHA")
6134
6235
if [ -z "$COMMITS" ]; then

.github/workflows/go.yml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,24 @@ on:
88

99
permissions:
1010
contents: read
11+
id-token: write
1112

1213
jobs:
1314
lint:
1415
name: Lint
1516
runs-on:
1617
group: databricks-protected-runner-group
17-
labels: [linux-ubuntu-latest]
18+
labels: linux-ubuntu-latest
1819

1920
steps:
2021
- name: Check out code into the Go module directory
21-
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
22+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
23+
24+
- name: Setup JFrog
25+
uses: ./.github/actions/setup-jfrog
2226

2327
- name: Set up Go Toolchain
24-
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
28+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
2529
with:
2630
go-version: '1.20.x'
2731
cache: false
@@ -35,23 +39,25 @@ jobs:
3539
strategy:
3640
matrix:
3741
go-version: [1.20.x]
38-
os: [ubuntu-latest]
3942
runs-on:
4043
group: databricks-protected-runner-group
41-
labels: [linux-ubuntu-latest]
44+
labels: linux-ubuntu-latest
4245

4346
steps:
4447
- name: Check out code into the Go module directory
45-
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
48+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
49+
50+
- name: Setup JFrog
51+
uses: ./.github/actions/setup-jfrog
4652

4753
- name: Set up Go Toolchain
48-
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
54+
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
4955
with:
5056
go-version: ${{ matrix.go-version }}
5157
cache: false
5258

5359
- name: Cache Go artifacts
54-
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
60+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
5561
with:
5662
path: |
5763
~/go/pkg/mod

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ linters-settings:
6363
exclude-generated: true
6464
severity: "low"
6565
confidence: "low"
66+
nolintlint:
67+
allow-unused: true
6668

6769
run:
6870
timeout: 5m

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,34 @@ To disable Cloud Fetch (e.g., when handling smaller datasets or to avoid additio
5656
token:[your token]@[Workspace hostname]:[Port number][Endpoint HTTP Path]?useCloudFetch=false
5757
```
5858

59+
### Telemetry Configuration (Optional)
60+
61+
The driver includes optional telemetry to help improve performance and reliability. Telemetry is **disabled by default** and requires explicit opt-in.
62+
63+
**Opt-in to telemetry** (respects server-side feature flags):
64+
```
65+
token:[your token]@[Workspace hostname]:[Port number][Endpoint HTTP Path]?enableTelemetry=true
66+
```
67+
68+
**Opt-out of telemetry** (explicitly disable):
69+
```
70+
token:[your token]@[Workspace hostname]:[Port number][Endpoint HTTP Path]?enableTelemetry=false
71+
```
72+
73+
**What data is collected:**
74+
- ✅ Query latency and performance metrics
75+
- ✅ Error codes (not error messages)
76+
- ✅ Feature usage (CloudFetch, LZ4, etc.)
77+
- ✅ Driver version and environment info
78+
79+
**What is NOT collected:**
80+
- ❌ SQL query text
81+
- ❌ Query results or data values
82+
- ❌ Table/column names
83+
- ❌ User identities or credentials
84+
85+
Telemetry has < 1% performance overhead and uses circuit breaker protection to ensure it never impacts your queries. For more details, see `telemetry/DESIGN.md` and `telemetry/TROUBLESHOOTING.md`.
86+
5987
### Connecting with a new Connector
6088

6189
You can also connect with a new connector object. For example:

SECURITY.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Security Policy
2+
3+
## Reporting a Vulnerability
4+
5+
If you discover a security vulnerability in this project, please report it responsibly.
6+
7+
**Do not open a public GitHub issue for security vulnerabilities.**
8+
9+
Instead, please report security issues by emailing [security@databricks.com](mailto:security@databricks.com).
10+
11+
Please include:
12+
- A description of the vulnerability
13+
- Steps to reproduce the issue
14+
- Any potential impact
15+
16+
We will acknowledge receipt within 3 business days and aim to provide a resolution timeline within 10 business days.
17+
18+
## Supported Versions
19+
20+
Security updates are applied to the latest release only.

auth/oauth/u2m/authenticator.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,17 @@ func NewAuthenticator(hostName string, timeout time.Duration) (auth.Authenticato
4040
cloud := oauth.InferCloudFromHost(hostName)
4141

4242
var clientID, redirectURL string
43-
if cloud == oauth.AWS {
43+
switch cloud {
44+
case oauth.AWS:
4445
clientID = awsClientId
4546
redirectURL = awsRedirectURL
46-
} else if cloud == oauth.Azure {
47+
case oauth.Azure:
4748
clientID = azureClientId
4849
redirectURL = azureRedirectURL
49-
} else if cloud == oauth.GCP {
50+
case oauth.GCP:
5051
clientID = gcpClientId
5152
redirectURL = gcpRedirectURL
52-
} else {
53+
default:
5354
return nil, errors.New("unhandled cloud type: " + cloud.String())
5455
}
5556

@@ -147,14 +148,14 @@ func (tsp *tokenSourceProvider) GetTokenSource() (oauth2.TokenSource, error) {
147148
if err != nil {
148149
return nil, err
149150
}
150-
defer listener.Close()
151+
defer listener.Close() //nolint:errcheck
151152

152153
srv := &http.Server{
153154
ReadHeaderTimeout: 3 * time.Second,
154155
WriteTimeout: 30 * time.Second,
155156
}
156157

157-
defer srv.Close()
158+
defer srv.Close() //nolint:errcheck
158159

159160
// Start local server to wait for callback
160161
go func() {
@@ -209,7 +210,7 @@ func (tsp *tokenSourceProvider) ServeHTTP(w http.ResponseWriter, r *http.Request
209210
if resp.err != "" {
210211
log.Error().Msg(resp.err)
211212
w.WriteHeader(http.StatusBadRequest)
212-
_, err := w.Write([]byte(errorHTML("Identity Provider returned an error: " + resp.err)))
213+
_, err := w.Write([]byte(errorHTML("Identity Provider returned an error: " + resp.err))) //nolint:gosec // XSS not a concern for local OAuth callback
213214
if err != nil {
214215
log.Error().Err(err).Msg("unable to write error response")
215216
}

auth/tokenprovider/exchange.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func (p *FederationProvider) tryTokenExchange(ctx context.Context, subjectToken
138138
}
139139

140140
// Create request
141-
req, err := http.NewRequestWithContext(ctx, "POST", exchangeURL, strings.NewReader(data.Encode()))
141+
req, err := http.NewRequestWithContext(ctx, "POST", exchangeURL, strings.NewReader(data.Encode())) //nolint:gosec // URL is from trusted config
142142
if err != nil {
143143
return nil, fmt.Errorf("failed to create request: %w", err)
144144
}
@@ -147,11 +147,11 @@ func (p *FederationProvider) tryTokenExchange(ctx context.Context, subjectToken
147147
req.Header.Set("Accept", "*/*")
148148

149149
// Make request
150-
resp, err := p.httpClient.Do(req)
150+
resp, err := p.httpClient.Do(req) //nolint:gosec // G704: URL is from trusted configuration
151151
if err != nil {
152152
return nil, fmt.Errorf("request failed: %w", err)
153153
}
154-
defer resp.Body.Close()
154+
defer resp.Body.Close() //nolint:errcheck
155155

156156
body, err := io.ReadAll(resp.Body)
157157
if err != nil {

auth/tokenprovider/federation_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ func TestFederationProvider_TokenExchangeSuccess(t *testing.T) {
108108
assert.Equal(t, "application/x-www-form-urlencoded", r.Header.Get("Content-Type"))
109109
assert.Equal(t, "*/*", r.Header.Get("Accept"))
110110

111-
// Parse form data
111+
// Parse form data - limit body size to prevent G120
112+
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
112113
err := r.ParseForm()
113114
require.NoError(t, err)
114115

@@ -155,13 +156,14 @@ func TestFederationProvider_TokenExchangeWithClientID(t *testing.T) {
155156

156157
// Create mock server that checks for client_id
157158
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
159+
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
158160
err := r.ParseForm()
159161
require.NoError(t, err)
160162

161163
// Verify client_id is present
162164
assert.Equal(t, clientID, r.FormValue("client_id"))
163165

164-
response := map[string]interface{}{
166+
response := map[string]interface{}{ //nolint:gosec // G101: test token, not a real credential
165167
"access_token": "sp-wide-federation-token",
166168
"token_type": "Bearer",
167169
"expires_in": 3600,

0 commit comments

Comments
 (0)