diff --git a/.github/workflows/e2e.maven.workflow_dispatch.main.default.slsa3.yml b/.github/workflows/e2e.maven.workflow_dispatch.main.default.slsa3.yml new file mode 100644 index 0000000000..0efacb9484 --- /dev/null +++ b/.github/workflows/e2e.maven.workflow_dispatch.main.default.slsa3.yml @@ -0,0 +1,106 @@ +on: + schedule: + - cron: "0 6 * * *" + workflow_dispatch: + inputs: + trigger_build: + description: "internal: do not check" + required: false + default: false + type: boolean + +permissions: read-all + +concurrency: "e2e-maven-workflow_dispatch-main-default-slsa3" + +env: + # TODO(#263): create dedicated token + GH_TOKEN: ${{ secrets.E2E_NODEJS_TOKEN }} + ISSUE_REPOSITORY: slsa-framework/slsa-github-generator + +jobs: + # Bootstrap + ################################################################################ + + bootstrap: + runs-on: ubuntu-latest + if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && !inputs.trigger_build) + permissions: + contents: write + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - env: + PACKAGE_DIR: ./e2e/maven/workflow_dispatch + run: ./.github/workflows/scripts/e2e-maven-push.sh + + if-bootstrap-failed: + runs-on: ubuntu-latest + needs: [bootstrap] + if: always() && (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && !inputs.trigger_build)) && needs.bootstrap.result != 'success' + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - run: ./.github/workflows/scripts/e2e-report-failure.sh + + # Main workflow + ################################################################################ + # Shim determines if the rest of the workflow should run. + # NOTE: it should only use the `if` to determine this and all downstream jobs + # should depend on this job. + shim: + # NOTE: this must be kept in sync with the if-failed job. + if: github.event_name == 'workflow_dispatch' && inputs.trigger_build + runs-on: ubuntu-latest + steps: + - run: | + echo "event: ${GITHUB_EVENT_NAME}" + echo "ref: ${GITHUB_REF}" + + build: + needs: [shim] + permissions: + id-token: write # For signing. + contents: read # For repo checkout of private repos. + actions: read # For getting workflow run on private repos. + uses: slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml@main + with: + directory: ./e2e/maven/workflow_dispatch + + verify: + runs-on: ubuntu-latest + needs: [build] + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - uses: slsa-framework/slsa-github-generator/actions/maven/secure-download-attestations@main + with: + name: "${{ needs.build.outputs.provenance-download-name }}" + sha256: "${{ needs.build.outputs.provenance-download-sha256 }}" + path: slsa-attestations + - uses: slsa-framework/slsa-github-generator/actions/maven/secure-download-target@main + with: + name: target + sha256: "${{ needs.build.outputs.target-download-sha256 }}" + path: ./ + # NOTE: To build slsa-verifier in e2e.maven.default.verify.sh + - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1 + with: + go-version: "1.18" + - env: + PROVENANCE_DIR: "slsa-attestations/${{ needs.build.outputs.provenance-download-name }}" + EXPECTED_ARTIFACT_OUTPUT: "Hello world!" + POMXML: "./e2e/maven/workflow_dispatch/pom.xml" + run: ./.github/workflows/scripts/e2e.maven.default.verify.sh + if-succeeded: + runs-on: ubuntu-latest + needs: [build, verify] + if: needs.build.result == 'success' && needs.verify.result == 'success' + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - run: ./.github/workflows/scripts/e2e-report-success.sh + + if-failed: + runs-on: ubuntu-latest + needs: [build, verify] + if: always() && github.event_name == 'workflow_dispatch' && inputs.trigger_build && (needs.build.result != 'success' || needs.verify.result != 'success') + steps: + - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 + - run: ./.github/workflows/scripts/e2e-report-failure.sh diff --git a/.github/workflows/scripts/e2e-maven-push.sh b/.github/workflows/scripts/e2e-maven-push.sh new file mode 100755 index 0000000000..5ff3f9daa1 --- /dev/null +++ b/.github/workflows/scripts/e2e-maven-push.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +set -euo pipefail + +# shellcheck source=/dev/null +source "./.github/workflows/scripts/e2e-utils.sh" + +# This script bumps the maven package's version number, commits it, and pushes to +# the repository. + +branch=$(e2e_this_branch) + +# Script Inputs +GITHUB_OUTPUT=${GITHUB_OUTPUT:-} +GITHUB_REPOSITORY=${GITHUB_REPOSITORY:-} +GITHUB_SHA=${GITHUB_SHA:-} +GITHUB_WORKFLOW=${GITHUB_WORKFLOW:-} +GH_TOKEN=${GH_TOKEN:-} +PACKAGE_DIR=${PACKAGE_DIR:-} # specified in the e2e test yaml + +# NOTE: We can't simply push from $branch because it is occaisonally reset to +# the main branch. We need to maintain the version number in pom.xml +# because you cannot overwrite a version in maven. Instead we commit to main, +# set the tag, reset $branch and push both main and $branch. +echo "GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}" +gh repo clone "${GITHUB_REPOSITORY}" -- -b main +repo_name=$(echo "$GITHUB_REPOSITORY" | cut -d '/' -f2) +cd ./"$repo_name" + +git config --global user.name github-actions +git config --global user.email github-actions@github.com + +# Set the remote url to authenticate using the token. +git remote set-url origin "https://github-actions:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" + +package_dir="${PACKAGE_DIR}" # specified in the e2e test yaml + +cd "${package_dir}" + +# Get the new version +artifact_tag=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + +# Bumps the version +new_version() { + current_tag=$1 + release_major=$(version_major "$current_tag") + release_minor=$(version_minor "$current_tag") + release_patch=$(version_patch "$current_tag") + + # These if-statements are sorted by likelihood + if [[ $release_patch != "99" ]]; then + # Only need to bump the patch + release_patch=$((release_patch+1)) + elif [[ $release_patch = "99" && $release_minor != "99" ]]; then + # Need to bump minor + release_minor=$(($release_minor+1)) + release_patch="0" + elif [[ $release_patch = "99" && $release_minor = "99" ]]; then + # Need to bump major + release_major=$(($release_major+1)) + release_minor="0" + release_patch="0" + fi + echo $release_major.$release_minor.$release_patch +} + +next_tag=$(new_version "${artifact_tag}") + +# Output the artifact name +echo "artifact-version=${artifact_tag}" >> "$GITHUB_OUTPUT" + +tag=$(mvn versions:set -DnewVersion="${next_tag}") +cd - + +# Commit the new version. +git commit -m "${GITHUB_WORKFLOW}" "${package_dir}/pom.xml" "${package_dir}/pom.xml" + +# If this is an e2e test for a tag, then tag the commit and push it. +this_event=$(e2e_this_event) +echo "this_event: ${this_event}" +if [ "${this_event}" == "tag" ] || [ "${this_event}" == "create" ]; then + git tag "${tag}" +fi + +git remote -v +git branch +pwd +if [ "${branch}" != "main" ]; then + # Reset branch1 and push the new version. + # git branch -D "$branch" + git checkout -b "${branch}" + if [ "${this_event}" == "tag" ] || [ "${this_event}" == "create" ]; then + git push --set-upstream origin "${branch}" "${tag}" -f + else + git push --set-upstream origin "${branch}" -f + fi + git checkout main + + # Update a dummy file to avoid https://github.com/slsa-framework/example-package/issues/44 + date >./e2e/dummy + git add ./e2e/dummy + git commit -m "sync'ing branch1 - $(cat ./e2e/dummy)" + git push origin main +else + if [ "${this_event}" == "tag" ] || [ "${this_event}" == "create" ]; then + # TODO(#213): push tag separately until bug is fixed. + # NOTE: If there is a concurrent update to main we want it to fail here + # without pushing the tag because we will lose the changes to main. + git push origin main + git push origin "${tag}" + else + git push origin main + fi +fi + +# If this is a test for a release event, create the release. +if [ "${this_event}" == "release" ]; then + this_file=$(e2e_this_file) + data_file=$(mktemp) + cat <"${data_file}" +**E2E release creation**: +Tag: ${tag} +Branch: ${branch} +Commit: ${GITHUB_SHA} +Caller file: ${this_file} +EOF + + gh release create "${tag}" --notes-file "${data_file}" --target "${branch}" +fi + +if [ "${this_event}" == "workflow_dispatch" ]; then + this_file=$(e2e_this_file) + curl -s -X POST -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/workflows/${this_file}/dispatches" \ + -d "{\"ref\":\"${branch}\",\"inputs\":{\"trigger_build\": true}}" \ + -H "Authorization: token ${GH_TOKEN}" +fi diff --git a/.github/workflows/scripts/e2e-utils.sh b/.github/workflows/scripts/e2e-utils.sh index 12ed3097ac..6fd63a9186 100755 --- a/.github/workflows/scripts/e2e-utils.sh +++ b/.github/workflows/scripts/e2e-utils.sh @@ -433,7 +433,7 @@ _e2e_verify_query() { local expected="$2" local query="$3" name=$(echo -n "${attestation}" | jq -c -r "${query}") - e2e_assert_eq "${name}" "${expected}" "${query} should be ${expected}" + e2e_assert_eq "${name}" "${expected}" "${query} should be ${expected} but was ${name}" } # Returns the first 2 asset in a release. diff --git a/.github/workflows/scripts/e2e.maven.default.verify.sh b/.github/workflows/scripts/e2e.maven.default.verify.sh new file mode 100755 index 0000000000..ef34fba007 --- /dev/null +++ b/.github/workflows/scripts/e2e.maven.default.verify.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# shellcheck source=/dev/null +source "./.github/workflows/scripts/e2e-verify.common.sh" + +# Input variables +EXPECTED_ARTIFACT_OUTPUT=${EXPECTED_ARTIFACT_OUTPUT:-} +PROVENANCE_DIR=${PROVENANCE_DIR:-} +GITHUB_REF_NAME=${GITHUB_REF_NAME:-} +GITHUB_REF=${GITHUB_REF:-} +GITHUB_REF_TYPE=${GITHUB_REF_TYPE:-} +POMXML=${POMXML:-} # specified in the e2e test yaml +RUNNER_DEBUG=${RUNNER_DEBUG:-} +if [[ -n "${RUNNER_DEBUG}" ]]; then + set -x +fi + +artifact_version=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -q -DforceStdout -f "${POMXML}") +artifact_id=$(mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.artifactId -q -DforceStdout -f "${POMXML}") +artifact_name="${artifact_id}-${artifact_version}.jar" +provenance="${PROVENANCE_DIR}/${artifact_name}.build.slsa" + +go env -w GOFLAGS=-mod=mod + +verify_provenance_content() { + local attestation + attestation=$(jq -r '.dsseEnvelope.payload' "${provenance}" | base64 -d) + + # Run the artifact and verify the output is correct + artifact_output=$(java -jar target/"${artifact_name}") + expected_artifact_output="${EXPECTED_ARTIFACT_OUTPUT}" + e2e_assert_eq "${artifact_output}" "${expected_artifact_output}" "The output from the artifact should be '${expected_artifact_output}' but was '${artifact_output}'" + + # Verify the content of the attestation + e2e_verify_predicate_subject_name "${attestation}" "${artifact_name}" + e2e_verify_predicate_v1_runDetails_builder_id "${attestation}" "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_maven_slsa3.yml@refs/heads/main" + e2e_verify_predicate_v1_buildDefinition_buildType "${attestation}" "https://github.com/slsa-framework/slsa-github-generator/delegator-generic@v0" +} + +this_file=$(e2e_this_file) +branch=$(echo "$this_file" | cut -d '.' -f4) +echo "branch is $branch" +echo "GITHUB_REF_NAME: $GITHUB_REF_NAME" +echo "GITHUB_REF_TYPE: $GITHUB_REF_TYPE" +echo "GITHUB_REF: $GITHUB_REF" +echo "DEBUG: file is $this_file" +echo "PROVENANCE is: ${provenance}" + +export SLSA_VERIFIER_TESTING="true" + +# Verify provenance content. +verify_provenance_content + +e2e_run_verifier_all_releases "HEAD" diff --git a/e2e/maven/workflow_dispatch/pom.xml b/e2e/maven/workflow_dispatch/pom.xml new file mode 100644 index 0000000000..082b2e5244 --- /dev/null +++ b/e2e/maven/workflow_dispatch/pom.xml @@ -0,0 +1,163 @@ + + + 4.0.0 + io.github.adamkorcz + test-java-project + v1.19.8 + jar + Adams test java project + A test java project. + https://github.com/AdamKorcz/test-java-project + + 1.8 + 1.8 + + + + ossrh + https://s01.oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + + + + + Adam K + Adam@adalogics.com + Ada Logics + http://www.adalogics.com + + + + scm:git:git://github.com/adamkorcz/test-java-project.git + scm:git:ssh://github.com:simpligility/test-java-project.git + http://github.com/adamkorcz/test-java-project/tree/main + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + ${java.home}/bin/javadoc + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + + hello.HelloWorld + + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://s01.oss.sonatype.org/ + false + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.1.0 + + + sign-artifacts + verify + + sign + + + + + + --pinentry-mode + loopback + + + + + org.apache.maven.plugins + maven-deploy-plugin + 3.1.1 + + + deploy-file + deploy + + deploy-file + + + textfile.txt + https://s01.oss.sonatype.org/ + io.github.adamkorcz + + + + + + io.github.slsa-framework.slsa-github-generator + hash-maven-plugin + 0.0.1 + + + + hash-jarfile + + + + + ${SLSA_OUTPUTS_ARTIFACTS_FILE} + + + + + diff --git a/e2e/maven/workflow_dispatch/src/main/java/hello/Greeter.java b/e2e/maven/workflow_dispatch/src/main/java/hello/Greeter.java new file mode 100644 index 0000000000..f92a442354 --- /dev/null +++ b/e2e/maven/workflow_dispatch/src/main/java/hello/Greeter.java @@ -0,0 +1,7 @@ +package hello; + +public class Greeter { + public String sayHello() { + return "Hello world!"; + } +} diff --git a/e2e/maven/workflow_dispatch/src/main/java/hello/HelloWorld.java b/e2e/maven/workflow_dispatch/src/main/java/hello/HelloWorld.java new file mode 100644 index 0000000000..1626b45cbd --- /dev/null +++ b/e2e/maven/workflow_dispatch/src/main/java/hello/HelloWorld.java @@ -0,0 +1,8 @@ +package hello; + +public class HelloWorld { + public static void main(String[] args) { + Greeter greeter = new Greeter(); + System.out.println(greeter.sayHello()); + } +}