Skip to content

Publisher

Publisher #4

Workflow file for this run

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-*"
ARTIFACT_PREFIX: "firestack-aar-"
SBOM_PREFIX: "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
id: dlaar
uses: actions/download-artifact@v7
with:
pattern: ${{ env.ARTIFACT_PATTERN }}
run-id: ${{ env.RUN_ID }}
github-token: ${{ github.token }}
path: ${{ env.DIST_DIR }}
- name: ⬇️ Download SBOM artifact
id: dlsbom
uses: actions/download-artifact@v7
with:
pattern: ${{ env.SBOM_PATTERN }}
run-id: ${{ env.RUN_ID }}
github-token: ${{ github.token }}
path: ${{ env.DIST_DIR }}
- name: 🔐 Verify build provenance
env:
REPO: ${{ github.repository }}
ART_DIR: ${{ steps.dlaar.outputs.download-path }}
GH_TOKEN: ${{ github.token }}
SHA: ${{ steps.runmeta.outputs.sha }}
run: |
set -xeuo pipefail
ls -ltr "${ART_DIR}/"
ART_DIR="${ART_DIR}/${ARTIFACT_PREFIX}${SHA}"
ls -ltr "${ART_DIR}/"
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 }}
ART_DIR: ${{ steps.dlsbom.outputs.download-path }}
GH_TOKEN: ${{ github.token }}
SHA: ${{ steps.runmeta.outputs.sha }}
run: |
# andrewlock.net/creating-sbom-attestations-in-github-actions/
set -xeuo pipefail
ls -ltr "${ART_DIR}/"
ART_DIR="${ART_DIR}/${SBOM_PREFIX}${SHA}"
ls -ltr "${ART_DIR}/"
if [ -n "${SBOM_INFO:-}" ]; then
name=$(jq -r '.path' <<<"${SBOM_INFO}")
sbom_file="$ART_DIR/$(jq -r '.artifactName' <<<"${SBOM_INFO}")/${name}"
digest=$(jq -r '.digest' <<<"${SBOM_INFO}")
else
sbom_file=$(find "${ART_DIR}" -name "${SBOM_MANIFEST}" -print -quit)
digest=$(cat < $(find "${ART_DIR}" -name "${SBOM_MANIFEST}.sha256" -print -quit))
fi
if [ -z "$sbom_file" ]; then
echo "::error::SBOM file not found in ${ART_DIR}/" >&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
else
echo "No SBOM digest; skipping digest verification" >&2
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"