Publisher #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publisher | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| build_run_id: | |
| required: true | |
| type: string | |
| workflow_call: | |
| inputs: | |
| # docs.github.com/en/actions/reference/workflows-and-actions/contexts | |
| run_id: | |
| description: "Workflow run id that produced signed artifacts" | |
| required: true | |
| type: string | |
| vcsver: | |
| description: "Short git version" | |
| required: false | |
| type: string | |
| artifact_subjects: | |
| description: "JSON array of artifact subjects with sha256 digests" | |
| required: false | |
| type: string | |
| sbom_info: | |
| description: "SBOM info JSON blob with subjects and digest" | |
| required: false | |
| type: string | |
| jobs: | |
| publish: | |
| name: 🚚 Publish | |
| runs-on: ubuntu-latest | |
| env: | |
| # docs.github.com/en/actions/reference/workflows-and-actions/contexts#github-context | |
| GROUP_GITHUB: ${{ format('com.github.{0}', github.repository_owner) }} | |
| GROUP_OSSRH: com.celzero | |
| # project artifactId; see: pom.xml | |
| ARTIFACT: firestack | |
| REPO_GITHUB: github | |
| # central.sonatype.org/pages/ossrh-eol | |
| # or "central" | |
| REPO_OSSRH: ossrh | |
| # artefact type | |
| PACK: aar | |
| # final out from make-aar | |
| FOUT: firestack.aar | |
| FOUTDBG: firestack-debug.aar | |
| # artifact classifier; full unused | |
| CLASSFULL: full | |
| CLASSDBG: debug | |
| # artifact bytecode sources | |
| SOURCES: build/intra/tun2socks-sources.jar | |
| # POM for Maven Central | |
| POM_OSSRH: ossrhpom.xml | |
| DIST_DIR: dist | |
| RUN_ID: ${{ inputs.run_id || inputs.build_run_id }} | |
| VCSVER_INPUT: ${{ inputs.vcsver }} | |
| # workflow input constants | |
| ARTIFACT_SUBJECTS: ${{ inputs.artifact_subjects }} | |
| SBOM_INFO: ${{ inputs.sbom_info }} | |
| ARTIFACT_PATTERN: "firestack-aar-*" | |
| SBOM_PATTERN: "firestack-sbom-*" | |
| SBOM_MANIFEST: "manifest.spdx.json" | |
| SBOM_PREDICATE: "https://spdx.dev/Document/v2.2" | |
| permissions: | |
| contents: read | |
| actions: read | |
| attestations: read | |
| packages: write | |
| steps: | |
| - name: 🥏 Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: 📀 Metadata | |
| id: runmeta | |
| env: | |
| RUN_ID: ${{ env.RUN_ID }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| if [ -n "${VCSVER_INPUT:-}" ]; then | |
| printf 'vcsver=%s\n' "${VCSVER_INPUT}" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| info=$(gh run view "$RUN_ID" --json headSha,headBranch,event,displayTitle) | |
| echo "$info" | jq | |
| sha=$(echo "$info" | jq -r '.headSha') | |
| if [ -z "$sha" ] || [ "$sha" = "null" ]; then | |
| echo "::error::unable to resolve head sha for run $RUN_ID" >&2 | |
| exit 11 | |
| fi | |
| # git version (short commit sha) | |
| printf 'sha=%s\n' "$sha" >> "$GITHUB_OUTPUT" | |
| printf 'vcsver=%s\n' "${sha:0:10}" >> "$GITHUB_OUTPUT" | |
| - name: ⬇️ Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: ${{ env.ARTIFACT_PATTERN }} | |
| run-id: ${{ env.RUN_ID }} | |
| github-token: ${{ github.token }} | |
| path: ${{ env.DIST_DIR }} | |
| - name: ⬇️ Download SBOM artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: ${{ env.SBOM_PATTERN }} | |
| run-id: ${{ env.RUN_ID }} | |
| github-token: ${{ github.token }} | |
| path: sbom | |
| - name: 🔐 Verify artifact attestations | |
| env: | |
| REPO: ${{ github.repository }} | |
| ART_DIR: ${{ env.DIST_DIR }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| for file in "$ART_DIR/${FOUT}" "$ART_DIR/${FOUTDBG}"; do | |
| if [ ! -f "$file" ]; then | |
| echo "::error::missing artifact $file" >&2 | |
| exit 12 | |
| fi | |
| gh attestation verify "$file" -R "$REPO" | |
| done | |
| if [ -n "${ARTIFACT_SUBJECTS:-}" ]; then | |
| jq -c '.[]' <<<"${ARTIFACT_SUBJECTS}" | while read -r subject; do | |
| name=$(jq -r '.name' <<<"$subject") | |
| digest=$(jq -r '.digest' <<<"$subject") | |
| file="${ART_DIR}/${name##*/}" | |
| if [ ! -f "$file" ]; then | |
| echo "::error::missing artifact $file for digest check" >&2 | |
| exit 13 | |
| fi | |
| want=${digest#sha256:} | |
| got=$(sha256sum "$file" | awk '{print $1}') | |
| if [ "$got" != "$want" ]; then | |
| echo "::error::digest mismatch for $file (got $got, want $want)" >&2 | |
| exit 14 | |
| fi | |
| done | |
| fi | |
| - name: 🔐 Verify SBOM attestation | |
| env: | |
| REPO: ${{ github.repository }} | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # andrewlock.net/creating-sbom-attestations-in-github-actions/ | |
| set -euo pipefail | |
| if [ -n "${SBOM_INFO:-}" ]; then | |
| name=$(jq -r '.path' <<<"${SBOM_INFO}") | |
| sbom_file="sbom/$(jq -r '.artifactName' <<<"${SBOM_INFO}")/${name}" | |
| digest=$(jq -r '.digest' <<<"${SBOM_INFO}") | |
| else | |
| sbom_file=$(find sbom -name "${SBOM_MANIFEST}" -print -quit) | |
| digest="" | |
| fi | |
| if [ -z "$sbom_file" ]; then | |
| echo "::error::SBOM file not found in sbom/" >&2 | |
| exit 15 | |
| fi | |
| if [ -n "$digest" ] && [ "$digest" != "null" ]; then | |
| want=${digest#sha256:} | |
| got=$(sha256sum "$sbom_file" | awk '{print $1}') | |
| if [ "$got" != "$want" ]; then | |
| echo "::error::SBOM digest mismatch (got $got, want $want)" >&2 | |
| exit 16 | |
| fi | |
| fi | |
| gh attestation verify "$sbom_file" -R "$REPO" --predicate-type "${SBOM_PREDICATE}" | |
| - name: 🏷️ Setup for GitHub Packages | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| # docs.github.com/en/actions/tutorials/build-and-test-code/java-with-maven | |
| # docs.github.com/en/actions/tutorials/publish-packages/publish-java-packages-with-maven#publishing-packages-to-github-packages | |
| - name: 😺 Publish to GitHub Packages | |
| shell: bash | |
| env: | |
| REPOSITORY: ${{ github.repository }} | |
| GITHUB_ACTOR: ${{ github.actor }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| VCSVER: ${{ steps.runmeta.outputs.vcsver }} | |
| run: | | |
| # uploaded at: | |
| # maven.pkg.github.com/celzero/firestack/com/github/celzero/firestack/<commit>/firestack-<commit>.aar | |
| # github.com/deelaa-marketplace/commons-workflow/blob/637dc111/flows/publish-api.yml#L49 | |
| # github.com/markocto/cf-octopub/blob/bba2de2c/github/script/action.yaml#L118 | |
| # publish both stripped and debug | |
| mvn deploy:deploy-file \ | |
| -DgroupId="${GROUP_GITHUB}" \ | |
| -DartifactId="${ARTIFACT}" \ | |
| -Dversion="$VCSVER" \ | |
| -Dpackaging="${PACK}" \ | |
| -Dfile="${DIST_DIR}/${FOUT}" \ | |
| -Dfiles="${DIST_DIR}/${FOUTDBG}" \ | |
| -Dtypes="${PACK}" \ | |
| -Dclassifiers=${CLASSDBG} \ | |
| -DrepositoryId="${REPO_GITHUB}" \ | |
| -Dsources="${DIST_DIR}/${SOURCES}" \ | |
| -Durl="https://maven.pkg.github.com/${REPOSITORY}" | |
| # central.sonatype.org/publish/publish-portal-api/#authentication-authorization | |
| # github.com/slsa-framework/slsa-github-generator/blob/4876e96b8268/actions/maven/publish/action.yml#L49 | |
| # docs.github.com/en/actions/tutorials/publish-packages/publish-java-packages-with-maven#publishing-packages-to-the-maven-central-repository-and-github-packages | |
| - name: 🏛️ Setup for Maven Central | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| server-id: ossrh | |
| server-username: MAVEN_USERNAME | |
| server-password: MAVEN_PASSWORD | |
| gpg-private-key: ${{ secrets.OSSRH_CELZERO_GPG_PRIVATE_KEY }} | |
| gpg-passphrase: ${{ secrets.OSSRH_CELZERO_GPG_PASSPHRASE }} | |
| - name: 📦 Publish to Maven Central | |
| shell: bash | |
| env: | |
| MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} | |
| MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} | |
| MAVEN_NS: ${{ secrets.OSSRH_CELZERO_NAMESPACE }} | |
| MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_CELZERO_GPG_PASSPHRASE }} | |
| VCSVER: ${{ steps.runmeta.outputs.vcsver }} | |
| run: | | |
| mvn -f ${POM_OSSRH} versions:set -DnewVersion=${VCSVER} -DgenerateBackupPoms=false | |
| # central.sonatype.org/publish/publish-portal-ossrh-staging-api/#getting-started-for-maven-api-like-plugins | |
| # github.com/videolan/vlc-android/blob/c393dd0699/buildsystem/maven/deploy-to-mavencentral.sh#L119 | |
| mvn gpg:sign-and-deploy-file \ | |
| -DgroupId="${GROUP_OSSRH}" \ | |
| -DartifactId="${ARTIFACT}" \ | |
| -Dversion="$VCSVER" \ | |
| -Dpackaging="${PACK}" \ | |
| -Dfile="${DIST_DIR}/${FOUT}" \ | |
| -DrepositoryId="${REPO_OSSRH}" \ | |
| -DpomFile=${POM_OSSRH} \ | |
| -Dgpg.keyname=C3F3F4A160BB2CFFB5528699F19CE6642C40085C \ | |
| -Dsources="${DIST_DIR}/${SOURCES}" \ | |
| -Durl="https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/" | |
| mvn gpg:sign-and-deploy-file \ | |
| -DgroupId="${GROUP_OSSRH}" \ | |
| -DartifactId="${ARTIFACT}" \ | |
| -Dversion="$VCSVER" \ | |
| -Dpackaging="${PACK}" \ | |
| -Dfile="${DIST_DIR}/${FOUTDBG}" \ | |
| -Dclassifier=${CLASSDBG} \ | |
| -DrepositoryId="${REPO_OSSRH}" \ | |
| -DgeneratePom=false \ | |
| -Dgpg.keyname=C3F3F4A160BB2CFFB5528699F19CE6642C40085C \ | |
| -Durl="https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/" | |
| # central.sonatype.org/publish/publish-portal-api/#authentication-authorization | |
| tok=$(printf "${MAVEN_USERNAME}:${MAVEN_PASSWORD}" | base64) | |
| # central.sonatype.org/publish/publish-portal-ossrh-staging-api/#1-modify-your-ci-script | |
| # central.sonatype.org/publish/publish-portal-ossrh-staging-api/#post-to-manualuploaddefaultrepositorynamespace | |
| # auth required for publishing_type=automatic | |
| curl -D - -X POST -H "Authorization: Bearer ${tok}" \ | |
| "https://ossrh-staging-api.central.sonatype.com/manual/upload/defaultRepository/${GROUP_OSSRH}?publishing_type=automatic" |