Skip to content

Commit 69918b1

Browse files
Switch CI to hardened runners with JFrog OIDC authentication (#753)
## Summary Route Maven dependency resolution through JFrog Artifactory on hardened runners that block direct access to Maven Central. Authenticate via GitHub Actions OIDC (zero stored secrets). Modeled after the CLI ([#4875](databricks/cli#4875)), Go SDK ([#1609](databricks/databricks-sdk-go#1609)), and Python SDK ([#1379](databricks/databricks-sdk-py#1379)). ## What changed - **New composite action** (`.github/actions/setup-build-environment/action.yml`): Sets up JFrog CLI via OIDC, installs the JDK, and generates a `~/.m2/settings.xml` that mirrors all Maven repositories through JFrog (`db-maven`). Skipped on macOS (not hardened). - **`push.yml`**: Added workflow-level `id-token: write` permission for OIDC. Switched `fmt`, `unit-tests` (Linux), and `check-lock` jobs to `databricks-protected-runner-group`. macOS tests remain on public runners. Used matrix `include` to map OS strings to runner configs, preserving the original check names for branch protection compatibility. - **`Makefile`**: Added `fix-lockfile` target. - **`lockfile.json`**: Regenerated to pick up `commons-configuration2` 2.13.0 (was out of date since PR #743 bumped the POM without regenerating the lockfile). ## Why settings.xml is needed Hardened runners terminate SSL handshakes to `repo.maven.apache.org`. Unlike Go (`GOPROXY` env var) or Python (`UV_INDEX_URL`), Maven has no environment variable to redirect repository access. The standard mechanism is a `~/.m2/settings.xml` with a `<mirror>` entry that routes all repository requests through JFrog. ## The lockfile problem Maven's `lockfile.json` stores the full download URL in each dependency's `resolved` field. When Maven resolves through JFrog, these become `https://databricks.jfrog.io/artifactory/db-maven/...` instead of `https://repo.maven.apache.org/maven2/...`. If someone runs `make lock` while Maven is routed through JFrog (CI, VPN), the lockfile would contain proxy URLs that shouldn't be committed. ### make fix-lockfile Replaces JFrog proxy URLs with their public Maven Central equivalents in all `lockfile.json` files. Prevents proxy URLs from being accidentally committed. **When to use it**: Run `make fix-lockfile` before committing if you regenerated the lockfile while Maven was routing through JFrog. **CI enforcement**: The `fmt` job runs `make fix-lockfile` followed by `git diff --exit-code`, so any committed proxy URLs will fail CI. ## Cache ordering The Maven cache (`~/.m2/repository`) must be restored **before** the composite action runs. The composite action generates `~/.m2/settings.xml` with a fresh OIDC token. If the cache step runs after and restores `~/.m2` (including a stale `settings.xml` from a previous run), the expired token causes 401 errors. Caching only `~/.m2/repository` (not all of `~/.m2`) prevents this. ## Out of scope - **release.yml**: Publishes to Maven Central via Sonatype. Needs special publish runners per the migration guide. Separate follow-up with the security team. - **tagging.yml**: Generated from Universe (openapi/genkit/sync/workflows/tagging.yml). JFrog setup needs to be upstreamed to the genkit template. - **conftest.yml**: Only downloads conftest binary from GitHub Releases (not Maven). Can stay on ubuntu-latest. ## Test plan - [x] Verify mvn --errors spotless:check passes (fmt job) - [x] Verify mvn --errors test passes on Linux (Java 8, 11, 17, 20) - [x] Verify mvn --errors test passes on macOS (Java 8, 11, 17, 20) - [x] Verify make check-lock passes (lockfile validation) - [x] Verify conftest passes on the new workflow files - [x] Verify check names match branch protection rules NO_CHANGELOG=true --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 4d195ac commit 69918b1

File tree

5 files changed

+192
-58
lines changed

5 files changed

+192
-58
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Setup build environment
2+
description: Set up JDK with JFrog Artifactory as Maven mirror for hardened runners
3+
4+
inputs:
5+
java-version:
6+
description: "Java version to install"
7+
required: true
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- name: Setup JFrog CLI with OIDC
13+
if: runner.os != 'macOS'
14+
id: jfrog
15+
uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1
16+
env:
17+
JF_URL: https://databricks.jfrog.io
18+
with:
19+
oidc-provider-name: github-actions
20+
21+
- name: Set up JDK
22+
uses: actions/setup-java@b6e674f4b717d7b0ae3baee0fbe79f498905dfde # v1.4.4
23+
with:
24+
java-version: ${{ inputs.java-version }}
25+
26+
- name: Configure Maven for JFrog
27+
if: runner.os != 'macOS'
28+
shell: bash
29+
run: |
30+
mkdir -p ~/.m2
31+
cat > ~/.m2/settings.xml << EOF
32+
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
33+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
34+
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
35+
<mirrors>
36+
<mirror>
37+
<id>jfrog-maven</id>
38+
<url>https://databricks.jfrog.io/artifactory/db-maven/</url>
39+
<mirrorOf>*</mirrorOf>
40+
</mirror>
41+
</mirrors>
42+
<servers>
43+
<server>
44+
<id>jfrog-maven</id>
45+
<username>${{ steps.jfrog.outputs.oidc-user }}</username>
46+
<password><![CDATA[${{ steps.jfrog.outputs.oidc-token }}]]></password>
47+
</server>
48+
</servers>
49+
</settings>
50+
EOF

.github/workflows/push.yml

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,66 +6,95 @@ on:
66
merge_group:
77
types: [checks_requested]
88

9+
permissions:
10+
id-token: write
11+
contents: read
12+
913
jobs:
1014
fmt:
11-
runs-on: ubuntu-latest
12-
steps:
13-
- name: Set up JDK 11
14-
uses: actions/setup-java@b6e674f4b717d7b0ae3baee0fbe79f498905dfde # v1.4.4
15-
with:
16-
java-version: 11
15+
runs-on:
16+
group: databricks-protected-runner-group
17+
labels: linux-ubuntu-latest
1718

19+
steps:
1820
- name: Checkout
1921
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
2022

2123
- name: Cache Maven packages
2224
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
2325
with:
24-
path: ~/.m2
26+
path: ~/.m2/repository
2527
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
2628
restore-keys: ${{ runner.os }}-m2
2729

30+
- name: Setup build environment
31+
uses: ./.github/actions/setup-build-environment
32+
with:
33+
java-version: 11
34+
2835
- name: Check formatting
2936
run: mvn --errors spotless:check
3037

38+
- name: Check for JFrog proxy URLs in lockfiles
39+
run: |
40+
make fix-lockfile
41+
git diff --exit-code -- '**/lockfile.json'
42+
3143
unit-tests:
3244
strategy:
3345
fail-fast: false
3446
matrix:
3547
os: [macos-latest, ubuntu-latest]
3648
java-version: [8, 11, 17, 20] # 20 is the latest version as of 2023 and 17 is the latest LTS
49+
include:
50+
- os: ubuntu-latest
51+
runner:
52+
group: databricks-protected-runner-group
53+
labels: linux-ubuntu-latest
54+
- os: macos-latest
55+
runner: macos-latest
3756

38-
runs-on: ${{ matrix.os }}
57+
runs-on: ${{ matrix.runner }}
3958

4059
steps:
41-
- name: Set up JDK
42-
uses: actions/setup-java@b6e674f4b717d7b0ae3baee0fbe79f498905dfde # v1.4.4
43-
with:
44-
java-version: ${{ matrix.java-version }}
45-
4660
- name: Checkout
4761
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
4862

4963
- name: Cache Maven packages
5064
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
5165
with:
52-
path: ~/.m2
66+
path: ~/.m2/repository
5367
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
5468
restore-keys: ${{ runner.os }}-m2
5569

70+
- name: Setup build environment
71+
uses: ./.github/actions/setup-build-environment
72+
with:
73+
java-version: ${{ matrix.java-version }}
74+
5675
- name: Check Unit Tests
5776
run: mvn --errors test
5877

5978
check-lock:
60-
runs-on: ubuntu-latest
61-
steps:
62-
- name: Set up JDK 11
63-
uses: actions/setup-java@b6e674f4b717d7b0ae3baee0fbe79f498905dfde # v1.4.4
64-
with:
65-
java-version: 11
79+
runs-on:
80+
group: databricks-protected-runner-group
81+
labels: linux-ubuntu-latest
6682

83+
steps:
6784
- name: Checkout
6885
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
6986

87+
- name: Cache Maven packages
88+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
89+
with:
90+
path: ~/.m2/repository
91+
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
92+
restore-keys: ${{ runner.os }}-m2
93+
94+
- name: Setup build environment
95+
uses: ./.github/actions/setup-build-environment
96+
with:
97+
java-version: 11
98+
7099
- name: Validate lockfile
71100
run: make check-lock

.github/workflows/release.yml

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,79 @@ on:
99
branches:
1010
- "**"
1111

12+
permissions:
13+
id-token: write
14+
contents: read
15+
1216
jobs:
1317
publish:
1418
# Dynamically set the job name based on the trigger
1519
name: ${{ startsWith(github.ref, 'refs/tags/') && 'Publish Release' || 'Run Release Dry-Run' }}
1620

1721
runs-on:
18-
group: databricks-deco-testing-runner-group
19-
labels: ubuntu-latest-deco
22+
group: databricks-protected-runner-group
23+
labels: linux-ubuntu-latest
2024

2125
steps:
2226
- name: Checkout
2327
uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
2428

29+
- name: Cache Maven packages
30+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
31+
with:
32+
path: ~/.m2/repository
33+
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
34+
restore-keys: ${{ runner.os }}-m2
35+
36+
- name: Setup JFrog CLI with OIDC
37+
id: jfrog
38+
uses: jfrog/setup-jfrog-cli@279b1f629f43dd5bc658d8361ac4802a7ef8d2d5 # v4.9.1
39+
env:
40+
JF_URL: https://databricks.jfrog.io
41+
with:
42+
oidc-provider-name: github-actions
43+
2544
- name: Set up Java for publishing to Maven Central Repository
2645
uses: actions/setup-java@17f84c3641ba7b8f6deff6309fc4c864478f5d62 # v3.14.1
2746
with:
2847
java-version: 8
29-
server-id: central
3048
distribution: "adopt"
31-
server-username: MAVEN_CENTRAL_USERNAME
32-
server-password: MAVEN_CENTRAL_PASSWORD
3349
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
3450
gpg-passphrase: GPG_PASSPHRASE
35-
51+
52+
- name: Configure Maven for JFrog and Maven Central
53+
run: |
54+
mkdir -p ~/.m2
55+
cat > ~/.m2/settings.xml << EOF
56+
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
57+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
58+
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
59+
<mirrors>
60+
<mirror>
61+
<id>jfrog-maven</id>
62+
<url>https://databricks.jfrog.io/artifactory/db-maven/</url>
63+
<mirrorOf>*</mirrorOf>
64+
</mirror>
65+
</mirrors>
66+
<servers>
67+
<server>
68+
<id>jfrog-maven</id>
69+
<username>${{ steps.jfrog.outputs.oidc-user }}</username>
70+
<password><![CDATA[${{ steps.jfrog.outputs.oidc-token }}]]></password>
71+
</server>
72+
<server>
73+
<id>central</id>
74+
<username>${{ secrets.MAVEN_CENTRAL_USERNAME }}</username>
75+
<password>${{ secrets.MAVEN_CENTRAL_PASSWORD }}</password>
76+
</server>
77+
<server>
78+
<id>gpg.passphrase</id>
79+
<passphrase>\${env.GPG_PASSPHRASE}</passphrase>
80+
</server>
81+
</servers>
82+
</settings>
83+
EOF
84+
3685
# This step runs ONLY on branch pushes (dry-run)
3786
- name: Run Release Dry-Run (Verify)
3887
if: "!startsWith(github.ref, 'refs/tags/')"
@@ -71,4 +120,4 @@ jobs:
71120
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15
72121
with:
73122
files: databricks-sdk-java/target/*.jar
74-
body_path: /tmp/release-notes/release-notes.md
123+
body_path: /tmp/release-notes/release-notes.md

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ lock:
1010
check-lock:
1111
mvn io.github.chains-project:maven-lockfile:5.5.2:validate
1212

13+
fix-lockfile:
14+
@# Replace JFrog proxy URLs with public Maven Central equivalents in lockfiles.
15+
@# Prevents proxy URLs from being accidentally committed.
16+
find . -type f -name 'lockfile.json' \
17+
-exec sed -i 's|databricks\.jfrog\.io/artifactory/db-maven|repo.maven.apache.org/maven2|g' {} +
18+

databricks-sdk-java/lockfile.json

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -735,68 +735,68 @@
735735
{
736736
"groupId": "org.apache.commons",
737737
"artifactId": "commons-configuration2",
738-
"version": "2.11.0",
738+
"version": "2.13.0",
739739
"checksumAlgorithm": "SHA-256",
740-
"checksum": "48957fc3a0d9fbd221fe4f5ff6d0294ce6646ea139793c36706703da59402683",
740+
"checksum": "7622799663317f95c81019b32b39e0c82e42b388f00abe6e5ab26489d90d9a6b",
741741
"scope": "compile",
742-
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-configuration2/2.11.0/commons-configuration2-2.11.0.jar",
743-
"selectedVersion": "2.11.0",
742+
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-configuration2/2.13.0/commons-configuration2-2.13.0.jar",
743+
"selectedVersion": "2.13.0",
744744
"included": true,
745-
"id": "org.apache.commons:commons-configuration2:2.11.0",
745+
"id": "org.apache.commons:commons-configuration2:2.13.0",
746746
"children": [
747747
{
748748
"groupId": "commons-logging",
749749
"artifactId": "commons-logging",
750-
"version": "1.3.2",
750+
"version": "1.3.5",
751751
"checksumAlgorithm": "SHA-256",
752-
"checksum": "6b858424f518015f32bfcd1183a373f4a827d72d026b6031da0c91cf0e8f3489",
752+
"checksum": "6d7a744e4027649fbb50895df9497d109f98c766a637062fe8d2eabbb3140ba4",
753753
"scope": "compile",
754-
"resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.3.2/commons-logging-1.3.2.jar",
755-
"selectedVersion": "1.3.2",
754+
"resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar",
755+
"selectedVersion": "1.3.5",
756756
"included": true,
757-
"id": "commons-logging:commons-logging:1.3.2",
758-
"parent": "org.apache.commons:commons-configuration2:2.11.0",
757+
"id": "commons-logging:commons-logging:1.3.5",
758+
"parent": "org.apache.commons:commons-configuration2:2.13.0",
759759
"children": []
760760
},
761761
{
762762
"groupId": "org.apache.commons",
763763
"artifactId": "commons-lang3",
764-
"version": "3.14.0",
764+
"version": "3.20.0",
765765
"checksumAlgorithm": "SHA-256",
766-
"checksum": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c",
766+
"checksum": "69e5c9fa35da7a51a5fd2099dfe56a2d8d32cf233e2f6d770e796146440263f4",
767767
"scope": "compile",
768-
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar",
769-
"selectedVersion": "3.14.0",
768+
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.20.0/commons-lang3-3.20.0.jar",
769+
"selectedVersion": "3.20.0",
770770
"included": true,
771-
"id": "org.apache.commons:commons-lang3:3.14.0",
772-
"parent": "org.apache.commons:commons-configuration2:2.11.0",
771+
"id": "org.apache.commons:commons-lang3:3.20.0",
772+
"parent": "org.apache.commons:commons-configuration2:2.13.0",
773773
"children": []
774774
},
775775
{
776776
"groupId": "org.apache.commons",
777777
"artifactId": "commons-text",
778-
"version": "1.12.0",
778+
"version": "1.14.0",
779779
"checksumAlgorithm": "SHA-256",
780-
"checksum": "de023257ff166044a56bd1aa9124e843cd05dac5806cc705a9311f3556d5a15f",
780+
"checksum": "121fce2282910c8f0c3ba793a5436b31beb710423cbe2d574a3fb7a73c508e92",
781781
"scope": "compile",
782-
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-text/1.12.0/commons-text-1.12.0.jar",
783-
"selectedVersion": "1.12.0",
782+
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-text/1.14.0/commons-text-1.14.0.jar",
783+
"selectedVersion": "1.14.0",
784784
"included": true,
785-
"id": "org.apache.commons:commons-text:1.12.0",
786-
"parent": "org.apache.commons:commons-configuration2:2.11.0",
785+
"id": "org.apache.commons:commons-text:1.14.0",
786+
"parent": "org.apache.commons:commons-configuration2:2.13.0",
787787
"children": [
788788
{
789789
"groupId": "org.apache.commons",
790790
"artifactId": "commons-lang3",
791-
"version": "3.14.0",
791+
"version": "3.18.0",
792792
"checksumAlgorithm": "SHA-256",
793-
"checksum": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c",
793+
"checksum": "4eeeae8d20c078abb64b015ec158add383ac581571cddc45c68f0c9ae0230720",
794794
"scope": "compile",
795-
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar",
796-
"selectedVersion": "3.14.0",
795+
"resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar",
796+
"selectedVersion": "3.20.0",
797797
"included": false,
798-
"id": "org.apache.commons:commons-lang3:3.14.0",
799-
"parent": "org.apache.commons:commons-text:1.12.0",
798+
"id": "org.apache.commons:commons-lang3:3.18.0",
799+
"parent": "org.apache.commons:commons-text:1.14.0",
800800
"children": []
801801
}
802802
]
@@ -837,7 +837,7 @@
837837
"checksum": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636",
838838
"scope": "compile",
839839
"resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar",
840-
"selectedVersion": "1.3.2",
840+
"selectedVersion": "1.3.5",
841841
"included": false,
842842
"id": "commons-logging:commons-logging:1.2",
843843
"parent": "org.apache.httpcomponents:httpclient:4.5.14",
@@ -1274,7 +1274,7 @@
12741274
"metaData": {
12751275
"environment": {
12761276
"osName": "Linux",
1277-
"mavenVersion": "3.9.9",
1277+
"mavenVersion": "3.9.14",
12781278
"javaVersion": "11.0.30"
12791279
},
12801280
"config": {

0 commit comments

Comments
 (0)