diff --git a/.github/workflows/builder_gradle_slsa3.yml b/.github/workflows/builder_gradle_slsa3.yml index 9866c03b20..5480ce6db8 100644 --- a/.github/workflows/builder_gradle_slsa3.yml +++ b/.github/workflows/builder_gradle_slsa3.yml @@ -31,6 +31,11 @@ on: required: false default: 17 type: number + directory: + description: "Sub-directory to launch the build from. Must be under the workspace. Relative from the root of the file directory when invoking the builder." + required: false + type: string + default: "." outputs: provenance-name: description: "The file name of the attestation upload artifact." diff --git a/actions/gradle/secure-download-attestations/action.yml b/actions/gradle/secure-download-attestations/action.yml new file mode 100644 index 0000000000..71050579bc --- /dev/null +++ b/actions/gradle/secure-download-attestations/action.yml @@ -0,0 +1,36 @@ +# Copyright 2023 SLSA Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "Secure attestion download for maven builder" +description: "Download the attestations-directory produced by the Maven builder and verify its SHA256" +inputs: + name: + description: "Name of provenance directory. This is generated by the Maven builder." + required: true + path: + description: "The path to download the attestations directory into. (Must be under the GITHUB_WORKSPACE)" + required: true + sha256: + description: "SHA256 of the file for verification. This is generated by the Maven builder" + required: true + +runs: + using: "composite" + steps: + - name: Download the attestation directory + uses: slsa-framework/slsa-github-generator/.github/actions/secure-download-folder@main + with: + name: ${{ inputs.name }} + path: ${{ inputs.path }} + sha256: ${{ inputs.sha256 }} diff --git a/actions/gradle/secure-download-target/action.yml b/actions/gradle/secure-download-target/action.yml new file mode 100644 index 0000000000..7eb3e346a9 --- /dev/null +++ b/actions/gradle/secure-download-target/action.yml @@ -0,0 +1,36 @@ +# Copyright 2023 SLSA Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "Secure target directory download for maven builder" +description: "Download the 'target'-directory and verify its SHA256" +inputs: + name: + description: "Name of the target directory. The Maven builder makes this 'target'." + required: true + path: + description: "The path to download the target directory into. (Must be under the GITHUB_WORKSPACE)" + required: true + sha256: + description: "SHA256 of the file for verification." + required: true + +runs: + using: "composite" + steps: + - name: Download the target directory + uses: slsa-framework/slsa-github-generator/.github/actions/secure-download-folder@main + with: + name: ${{ inputs.name }} + path: ${{ inputs.path }} + sha256: ${{ inputs.sha256 }} diff --git a/internal/builders/gradle/action.yml b/internal/builders/gradle/action.yml index 72d262468b..057f1cc502 100644 --- a/internal/builders/gradle/action.yml +++ b/internal/builders/gradle/action.yml @@ -60,24 +60,59 @@ runs: java-version: ${{ fromJson(inputs.slsa-workflow-inputs).jdk-version }} - name: Setup Gradle uses: gradle/gradle-build-action@a4cf152f482c7ca97ef56ead29bf08bcd953284c # v2.7.0 - with: - arguments: build -x test + - name: Run gradle builder + shell: bash + env: + UNTRUSTED_PROJECT_ROOT: ${{ fromJson(inputs.slsa-workflow-inputs).directory }} + run: | + # Ensure no directory traversal. + # NOTE: the actions/download-artifact Action only creates files + # in the workspace directory, but this may change in the future. + # TODO(#1893): Consolidate directory traversal checks + validate_path() { + untrusted_path=$1 + resolved_dir=$(readlink -m "$untrusted_path") + wd=$(readlink -m "${GITHUB_WORKSPACE}") + if [[ "${resolved_dir}" != "${wd}"/* ]] && [[ "${resolved_dir}" != "${wd}" ]]; then + if [[ "${RUNNER_TEMP}" != "" ]] && [[ "${resolved_dir}" != "${RUNNER_TEMP}"/* ]] && [[ "${resolved_dir}" != "${RUNNER_TEMP}" ]]; then + if [[ "${resolved_dir}" != /tmp/* ]] && [[ "${resolved_dir}" != "/tmp" ]]; then + echo "Path is not in the workspace or temp directory: $untrusted_path" + exit 1 + fi + fi + fi + } + validate_path "${UNTRUSTED_PROJECT_ROOT}" + # remove trailing "/"'s with `realpath` + project_root=$(realpath "${UNTRUSTED_PROJECT_ROOT}") + + cd "${project_root}" \ + && ./gradlew build -x test + - name: Put release artifacts in one directory shell: bash env: SLSA_OUTPUTS_ARTIFACTS_FILE: ${{ inputs.slsa-layout-file }} - ARTIFACT_LIST: ${{ fromJson(inputs.slsa-workflow-inputs).artifact-list }} - run: ./../__TOOL_ACTION_DIR__/collect_release_artifacts.sh - - name: Upload built artifacts from gradlew build - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 - with: - path: ./release-files-for-slsa/* + UNTRUSTED_ARTIFACT_LIST: ${{ fromJson(inputs.slsa-workflow-inputs).artifact-list }} + PROJECT_ROOT: ${{ fromJson(inputs.slsa-workflow-inputs).directory }} + run: | + cd "${PROJECT_ROOT}" && "${GITHUB_WORKSPACE}"/../__TOOL_ACTION_DIR__/collect_release_artifacts.sh - name: Make outputs id: make-outputs shell: bash env: SLSA_OUTPUTS_ARTIFACTS_FILE: ${{ inputs.slsa-layout-file }} - run: ./../__TOOL_ACTION_DIR__/create_attestation.sh + PROJECT_ROOT: ${{ fromJson(inputs.slsa-workflow-inputs).directory }} + run: | + cd "${PROJECT_ROOT}" && "${GITHUB_WORKSPACE}"/../__TOOL_ACTION_DIR__/create_attestation.sh + - name: Move build dir to avoid making it a sub-dir when uploading + shell: bash + env: + # PROJECT_ROOT is generally untrusted, but the builder has validated + # it in the 'Run gradle builder' step and is therefore trusted now. + PROJECT_ROOT: ${{ fromJson(inputs.slsa-workflow-inputs).directory }} + run: | + mv "${PROJECT_ROOT}"/build "${GITHUB_WORKSPACE}"/ - name: Upload build dir id: upload-build-dir uses: slsa-framework/slsa-github-generator/.github/actions/secure-upload-folder@main diff --git a/internal/builders/gradle/collect_release_artifacts.sh b/internal/builders/gradle/collect_release_artifacts.sh index ce69d3c950..07014bb7fa 100755 --- a/internal/builders/gradle/collect_release_artifacts.sh +++ b/internal/builders/gradle/collect_release_artifacts.sh @@ -20,7 +20,7 @@ mkdir release-files-for-slsa GRADLE_VERSION=$(./gradlew properties -q | grep "version:" | awk '{print $2}') # Move artifacts from the user-supplied artifact list -IFS=',' read -ra artifact_array <<< "$ARTIFACT_LIST" +IFS=',' read -ra artifact_array <<< "$UNTRUSTED_ARTIFACT_LIST" for i in "${artifact_array[@]}" do i="${i#"${i%%[![:space:]]*}"}" # trim leading whitespace @@ -38,5 +38,5 @@ do # Move the file bn=$(basename -- "$path_with_version") - mv "$path_with_version" release-files-for-slsa/"$bn" + cp "$path_with_version" release-files-for-slsa/"$bn" done diff --git a/internal/builders/gradle/create_attestation.sh b/internal/builders/gradle/create_attestation.sh index aaa146360a..c788a09ccf 100755 --- a/internal/builders/gradle/create_attestation.sh +++ b/internal/builders/gradle/create_attestation.sh @@ -16,6 +16,8 @@ set -euo pipefail +SLSA_OUTPUTS_ARTIFACTS_FILE="${GITHUB_WORKSPACE}/${SLSA_OUTPUTS_ARTIFACTS_FILE}" + # "version" and "attestations" fields: echo -e -n "{\n \"version\": 1,\n \"attestations\": [" >> "$SLSA_OUTPUTS_ARTIFACTS_FILE"