Skip to content

Commit 459c873

Browse files
AdamKorczIan Lewis
and
Ian Lewis
authored
chore: Make gradle publisher an action (#2497)
Closes #2464 and #2467 --------- Signed-off-by: AdamKorcz <[email protected]> Signed-off-by: AdamKorcz <[email protected]> Co-authored-by: Ian Lewis <[email protected]>
1 parent ec04624 commit 459c873

File tree

6 files changed

+336
-13
lines changed

6 files changed

+336
-13
lines changed

.github/workflows/builder_gradle_slsa3.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,24 @@ on:
3131
required: false
3232
default: 17
3333
type: number
34+
outputs:
35+
provenance-name:
36+
description: "The file name of the attestation upload artifact."
37+
# NOTE: This is an "untrusted" value returned from the build.
38+
value: "${{ fromJSON(jobs.slsa-run.outputs.build-artifacts-outputs).attestation-name }}"
39+
40+
provenance-download-name:
41+
description: "The name of the provenance attestation uploaded to the workflow run."
42+
value: "${{ jobs.slsa-run.outputs.attestations-download-name }}"
43+
44+
provenance-download-sha256:
45+
description: "The sha256 of the provenance attestation uploaded to the workflow run."
46+
value: "${{ jobs.slsa-run.outputs.attestations-download-sha256 }}"
47+
48+
target-download-sha256:
49+
description: "The sha256 of the target uploaded to the workflow run."
50+
# NOTE: This is an "untrusted" value returned from the build.
51+
value: "${{ fromJSON(jobs.slsa-run.outputs.build-artifacts-outputs).target-download-sha256 }}"
3452
jobs:
3553
slsa-setup:
3654
permissions:

actions/gradle/publish/README.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,271 @@ Before you use this publish Action, you will need to configure your Github proje
1111
Your project needs to be already set up with Gradle and must have a gradle wrapper file in order to use the Action.
1212

1313
The Action expects you to have built the artifacts using the SLSA Gradle builder and that the provenance is available in `./build/libs/slsa-attestations/`.
14+
15+
## Using the Gradle Publish action
16+
17+
To use the Gradle action you need to:
18+
19+
1. Modify your `build.gradle.kts` file.
20+
2. Add the step in your release workflow that invokes it.
21+
22+
### Modify your `build.gradle.kts` file
23+
24+
Assuming you have already configured your Gradle repository to release to Maven Central, your `build.gradle.kts` looks something like this:
25+
26+
```kotlin
27+
import java.io.File
28+
29+
plugins {
30+
`java-library`
31+
`maven-publish`
32+
`signing`
33+
}
34+
35+
repositories {
36+
mavenLocal()
37+
maven {
38+
url = uri("https://repo.maven.apache.org/maven2/")
39+
}
40+
}
41+
42+
group = "io.github.adamkorcz"
43+
version = "0.1.18"
44+
description = "Adam's test java project"
45+
java.sourceCompatibility = JavaVersion.VERSION_1_8
46+
47+
java {
48+
withSourcesJar()
49+
withJavadocJar()
50+
}
51+
52+
publishing {
53+
publications {
54+
create<MavenPublication>("maven") {
55+
artifactId = "test-java-project"
56+
from(components["java"])
57+
58+
pom {
59+
name.set("test-java-project")
60+
description.set("Adam's test java project")
61+
url.set("https://github.com/AdamKorcz/test-java-project")
62+
licenses {
63+
license {
64+
name.set("MIT License")
65+
url.set("http://www.opensource.org/licenses/mit-license.php")
66+
}
67+
}
68+
developers {
69+
developer {
70+
id.set("adamkrocz")
71+
name.set("Adam K")
72+
email.set("[email protected]")
73+
}
74+
}
75+
scm {
76+
connection.set("scm:git:git://github.com/adamkorcz/test-java-project.git")
77+
developerConnection.set("scm:git:ssh://github.com:simpligility/test-java-project.git")
78+
url.set("http://github.com/adamkorcz/test-java-project/tree/main")
79+
}
80+
}
81+
}
82+
}
83+
repositories {
84+
maven {
85+
credentials {
86+
username = System.getenv("MAVEN_USERNAME")
87+
password = System.getenv("MAVEN_PASSWORD")
88+
}
89+
name = "test-java-project"
90+
url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
91+
}
92+
}
93+
}
94+
95+
signing {
96+
useGpgCmd()
97+
sign(publishing.publications["maven"])
98+
}
99+
```
100+
101+
You need to add the following lines to your `build.gradle.kts` at the top inside of `create<MavenPublication>("maven")`:
102+
103+
```kotlin
104+
val base_dir = "build/libs/slsa-attestations"
105+
File(base_dir).walkTopDown().forEach {
106+
if (it.isFile()) {
107+
var path = it.getName()
108+
val name = path.replace(project.name + "-" + project.version, "").split(".", limit=2)
109+
if (name.size != 2) {
110+
throw StopExecutionException("Found incorrect file name: " + path)
111+
}
112+
var cls = name[0]
113+
var ext = name[1]
114+
if (cls.startsWith("-")) {
115+
cls = cls.substring(1)
116+
}
117+
artifact (base_dir + "/" + path) {
118+
classifier = cls
119+
extension = ext
120+
}
121+
}
122+
}
123+
```
124+
125+
Your final `build.gradle.kts` file should look like this:
126+
127+
```kotlin
128+
import java.io.File
129+
130+
plugins {
131+
`java-library`
132+
`maven-publish`
133+
`signing`
134+
}
135+
136+
repositories {
137+
mavenLocal()
138+
maven {
139+
url = uri("https://repo.maven.apache.org/maven2/")
140+
}
141+
}
142+
143+
group = "io.github.adamkorcz"
144+
version = "0.1.18"
145+
description = "Adams test java project"
146+
java.sourceCompatibility = JavaVersion.VERSION_1_8
147+
148+
java {
149+
withSourcesJar()
150+
withJavadocJar()
151+
}
152+
153+
publishing {
154+
publications {
155+
create<MavenPublication>("maven") {
156+
artifactId = "test-java-project"
157+
from(components["java"])
158+
val base_dir = "build/libs/slsa-attestations"
159+
File(base_dir).walkTopDown().forEach {
160+
if (it.isFile()) {
161+
var path = it.getName()
162+
val name = path.replace(project.name + "-" + project.version, "").split(".", limit=2)
163+
if (name.size != 2) {
164+
throw StopExecutionException("Found incorrect file name: " + path)
165+
}
166+
var cls = name[0]
167+
var ext = name[1]
168+
if (cls.startsWith("-")) {
169+
cls = cls.substring(1)
170+
}
171+
artifact (base_dir + "/" + path) {
172+
classifier = cls
173+
extension = ext
174+
}
175+
}
176+
}
177+
pom {
178+
name.set("test-java-project")
179+
description.set("Adams test java project")
180+
url.set("https://github.com/AdamKorcz/test-java-project")
181+
licenses {
182+
license {
183+
name.set("MIT License")
184+
url.set("http://www.opensource.org/licenses/mit-license.php")
185+
}
186+
}
187+
developers {
188+
developer {
189+
id.set("adamkrocz")
190+
name.set("Adam K")
191+
email.set("[email protected]")
192+
}
193+
}
194+
scm {
195+
connection.set("scm:git:git://github.com/adamkorcz/test-java-project.git")
196+
developerConnection.set("scm:git:ssh://github.com:simpligility/test-java-project.git")
197+
url.set("http://github.com/adamkorcz/test-java-project/tree/main")
198+
}
199+
}
200+
}
201+
}
202+
repositories {
203+
maven {
204+
credentials {
205+
username = System.getenv("MAVEN_USERNAME")
206+
password = System.getenv("MAVEN_PASSWORD")
207+
}
208+
name = "test-java-project"
209+
url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
210+
}
211+
}
212+
}
213+
214+
signing {
215+
useGpgCmd()
216+
sign(publishing.publications["maven"])
217+
}
218+
```
219+
220+
You don't need to configure anything inside that code snippet; Adding them to your `build.gradle.kts` file is enough.
221+
222+
### Add the publish action to your release workflow
223+
224+
Before using the Gradle publish action, you should have a workflow that invokes the Gradle builder. It will look something like this:
225+
226+
```yaml
227+
name: Publish Gradle with action
228+
on:
229+
- workflow_dispatch
230+
231+
permissions: read-all
232+
233+
jobs:
234+
build:
235+
permissions:
236+
id-token: write
237+
contents: read
238+
actions: read
239+
packages: read
240+
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
241+
with:
242+
rekor-log-public: true
243+
artifact-list: build/libs/artifact1-0.1.18.jar,build/libs/artifact-0.1.18-javadoc.jar,build/libs/artifact-0.1.18-sources.jar
244+
```
245+
246+
To use the Publish action, you need to add another job:
247+
248+
```yaml
249+
publish:
250+
runs-on: ubuntu-latest
251+
needs: build
252+
permissions:
253+
id-token: write
254+
contents: read
255+
actions: read
256+
steps:
257+
- name: publish
258+
id: publish
259+
uses: slsa-framework/slsa-github-generator/actions/gradle/[email protected]
260+
with:
261+
provenance-download-name: "${{ needs.build.outputs.provenance-download-name }}"
262+
provenance-download-sha256: "${{ needs.build.outputs.provenance-download-sha256 }}"
263+
target-download-sha256: "${{ needs.build.outputs.target-download-sha256 }}"
264+
maven-username: ${{ secrets.OSSRH_USERNAME }}
265+
maven-password: ${{ secrets.OSSRH_PASSWORD }}
266+
gpg-key-pass: ${{ secrets.GPG_PASSPHRASE }}
267+
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
268+
jdk-version: "17"
269+
```
270+
271+
Set the values of "maven-username", "maven-password", "gpg-key-pass" and " gpg-private-key" for your account. The parameters to `provenance-download-name`, `provenance-download-sha256` and `target-download-sha256` should not be changed.
272+
273+
Once you trigger this workflow, your artifacts and provenance files will be added to a staging repository in Maven Central. You need to close the staging repository and then release:
274+
275+
Closing the staging repository:
276+
277+
![closing the staging repository](/actions/gradle/publish/images/gradle-publisher-staging-repository.png)
278+
279+
Releasing:
280+
281+
![releasing the Gradle artefacts](/actions/gradle/publish/images/gradle-publisher-release-closed-repository.png)

actions/gradle/publish/action.yml

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@
1414

1515
name: Gradle publish Action for Maven Central
1616
inputs:
17+
provenance-download-name:
18+
description: "The artifact name for the package provenance."
19+
required: true
20+
type: string
21+
provenance-download-sha256:
22+
description: "The sha256 of the package provenance artifact."
23+
required: false
24+
type: string
25+
target-download-sha256:
26+
description: "The sha256 of the target directory."
27+
required: true
28+
type: string
1729
jdk-version:
1830
description: "The JDK version for the action"
1931
required: true
@@ -38,30 +50,42 @@ runs:
3850
- name: Set up JDK
3951
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
4052
env:
41-
MAVEN_USERNAME: ${{ secrets.maven-username }}
42-
MAVEN_PASSWORD: ${{ secrets.maven-password }}
43-
GPG_KEY_PASS: ${{ secrets.gpg-key-pass }}
53+
MAVEN_USERNAME: ${{ inputs.maven-username }}
54+
MAVEN_PASSWORD: ${{ inputs.maven-password }}
55+
GPG_KEY_PASS: ${{ inputs.gpg-key-pass }}
4456
with:
4557
distribution: temurin
4658
java-version: ${{ inputs.jdk-version }}
4759
server-id: ossrh
4860
server-username: MAVEN_USERNAME
4961
server-password: MAVEN_PASSWORD
50-
gpg-private-key: ${{ secrets.gpg-private-key }}
62+
gpg-private-key: ${{ inputs.gpg-private-key }}
5163
gpg-passphrase: GPG_KEY_PASS
64+
- name: Download the slsa attestation
65+
uses: slsa-framework/slsa-github-generator/.github/actions/secure-download-folder@main
66+
with:
67+
name: "${{ inputs.provenance-download-name }}"
68+
path: ./
69+
sha256: "${{ inputs.provenance-download-sha256 }}"
70+
71+
- name: Download the target dir
72+
uses: slsa-framework/slsa-github-generator/.github/actions/secure-download-folder@main
73+
with:
74+
name: build
75+
path: ./
76+
sha256: "${{ inputs.target-download-sha256 }}"
5277
- name: Upload to Maven Central
5378
shell: bash
5479
env:
55-
GPG_PRIVATE_KEY: ${{ secrets.gpg-private-key }}
56-
GPG_PASSPHRASE: ${{ secrets.gpg-key-pass }}
80+
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
81+
GPG_PASSPHRASE: ${{ inputs.gpg-key-pass }}
82+
SLSA_DIR: "${{ inputs.provenance-download-name }}"
83+
MAVEN_USERNAME: ${{ inputs.maven-username }}
84+
MAVEN_PASSWORD: ${{ inputs.maven-password }}
85+
PROVENANCE: "build/libs/slsa-attestations/"
5786
run: |
58-
# The Gradle publisher expect the provenance to exist in "./build/libs/slsa-attestations/"
59-
if [ ! -d "./build/libs/slsa-attestations" ]
60-
then
61-
echo "Could not find ./build/libs/slsa-attestations"
62-
echo "./build/libs/slsa-attestations should contain the provenance files"
63-
exit 1
64-
fi
87+
# Collect the provenance files into a subdirectory of "./build"
88+
mv "${SLSA_DIR}" ./build/libs/slsa-attestations
6589
# Import GPG signing key
6690
echo "${GPG_PRIVATE_KEY}" | gpg --batch --import --import-options import-show
6791
GPG_KEYNAME="$(echo "${GPG_PRIVATE_KEY}" | gpg --batch --show-keys --with-colons | awk -F: '$1 == "sec" { print $5 }')"
Loading
Loading

internal/builders/gradle/action.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ inputs:
3939
slsa-workflow-secret13: {}
4040
slsa-workflow-secret14: {}
4141
slsa-workflow-secret15: {}
42+
outputs:
43+
target-download-sha256:
44+
description: >
45+
The sha256 digest of the "build" directory.
46+
47+
Users should verify the download against this digest to prevent tampering.
48+
value: ${{ steps.upload-build-dir.outputs.sha256 }}
4249

4350
on:
4451
workflow_call:
@@ -71,3 +78,9 @@ runs:
7178
env:
7279
SLSA_OUTPUTS_ARTIFACTS_FILE: ${{ inputs.slsa-layout-file }}
7380
run: ./../__TOOL_ACTION_DIR__/create_attestation.sh
81+
- name: Upload build dir
82+
id: upload-build-dir
83+
uses: slsa-framework/slsa-github-generator/.github/actions/secure-upload-folder@main
84+
with:
85+
name: build
86+
path: build

0 commit comments

Comments
 (0)