From 5c6304217c3c20e1723a31cd5f92c2d8aa24981a Mon Sep 17 00:00:00 2001 From: ffrancis Date: Thu, 30 Jul 2026 15:41:39 +0530 Subject: [PATCH 1/2] Normalize the S3 location prefix before building artifact paths Append a trailing slash only when the location input is provided. Reuse the normalized prefix for upload, download, and presign operations. Prevent creation of empty S3 path segments when location is unset. Signed-off-by: ffrancis --- .github/actions/aws-s3-exchanger/action.yml | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/.github/actions/aws-s3-exchanger/action.yml b/.github/actions/aws-s3-exchanger/action.yml index 868bf4a..bd96cb3 100644 --- a/.github/actions/aws-s3-exchanger/action.yml +++ b/.github/actions/aws-s3-exchanger/action.yml @@ -36,34 +36,49 @@ runs: shell: bash env: UPLOAD_LOCATION: ${{ inputs.upload_location }} + INPUT_LOCATION: ${{ inputs.location }} + INPUT_MODE: ${{ inputs.mode }} + INPUT_LOCAL_FILE: ${{ inputs.local_file }} + INPUT_S3_BUCKET: ${{ inputs.s3_bucket }} + INPUT_DOWNLOAD_FILENAME: ${{ inputs.download_filename }} + WORKSPACE_DIR: ${{ github.workspace }} + IMAGE_NAME: ${{ env.IMAGE_NAME }} run: | - case "${{ inputs.mode }}" in + set -euo pipefail + + location_prefix="${INPUT_LOCATION}" + if [ -n "$location_prefix" ]; then + location_prefix="${location_prefix%/}/" + fi + + case "${INPUT_MODE}" in upload) echo "::group::$(printf '__________ %-100s' 'Process' | tr ' ' _)" echo "Uploading file to S3 bucket..." - aws s3 cp "${{ inputs.local_file }}" s3://${{ inputs.s3_bucket }}/${{ inputs.location }}/${{ env.UPLOAD_LOCATION }}${{ env.IMAGE_NAME }}/ - echo "Uploaded ${{ inputs.local_file }} to s3://${{ inputs.s3_bucket }}/${{ inputs.location }}/${{ env.UPLOAD_LOCATION }}${{ env.IMAGE_NAME }}/" + aws s3 cp "${INPUT_LOCAL_FILE}" "s3://${INPUT_S3_BUCKET}/${location_prefix}${UPLOAD_LOCATION}${IMAGE_NAME}/" + echo "Uploaded ${INPUT_LOCAL_FILE} to s3://${INPUT_S3_BUCKET}/${location_prefix}${UPLOAD_LOCATION}${IMAGE_NAME}/" echo "::endgroup::" - echo "Creating Pre-signed URL for ${{ inputs.local_file }}..." - filename="$(basename "${{ inputs.local_file }}")" + echo "Creating Pre-signed URL for ${INPUT_LOCAL_FILE}..." + filename="$(basename "${INPUT_LOCAL_FILE}")" echo "Filename: $filename" - presigned_url="$(aws s3 presign s3://${{ inputs.s3_bucket }}/${{ inputs.location }}/${{ env.UPLOAD_LOCATION }}${{ env.IMAGE_NAME }}/$filename --expires-in 3600)" + presigned_url="$(aws s3 presign "s3://${INPUT_S3_BUCKET}/${location_prefix}${UPLOAD_LOCATION}${IMAGE_NAME}/$filename" --expires-in 3600)" echo "Pre-signed URL: $presigned_url" # Make URL available as a step output (fixed key) echo "presigned_url=${presigned_url}" >> "$GITHUB_OUTPUT" # Also write the URL into a uniquely named file for artifact download - echo "${presigned_url}" > "${{ github.workspace }}/presigned_urls/presigned_url_${{ env.IMAGE_NAME }}.txt" + mkdir -p "${WORKSPACE_DIR}/presigned_urls" + echo "${presigned_url}" > "${WORKSPACE_DIR}/presigned_urls/presigned_url_${IMAGE_NAME}.txt" ;; download) #Download The required file from s3 echo "::group::$(printf '__________ %-100s' 'Process' | tr ' ' _)" echo "Downloading files from S3 bucket..." - aws s3 cp s3://${{ inputs.s3_bucket }}/${{ inputs.location }}/${{ inputs.download_filename }} . + aws s3 cp "s3://${INPUT_S3_BUCKET}/${location_prefix}${INPUT_DOWNLOAD_FILENAME}" . echo "::endgroup::" - chmod 777 ${{ inputs.download_filename }} - echo "Downloaded ${{ inputs.download_filename }} from s3://${{ inputs.s3_bucket }}/${{ inputs.location }}" + chmod 0644 "${INPUT_DOWNLOAD_FILENAME}" + echo "Downloaded ${INPUT_DOWNLOAD_FILENAME} from s3://${INPUT_S3_BUCKET}/${INPUT_LOCATION}" ;; *) echo "Invalid mode. Use 'upload' or 'download'." From b8153ac7c3fbf3b15416d53561e085bf822c6770 Mon Sep 17 00:00:00 2001 From: ffrancis Date: Thu, 30 Jul 2026 17:44:59 +0530 Subject: [PATCH 2/2] Harden aws-s3-exchanger shell execution and file handling Move GitHub expressions out of shell blocks and consume inputs through environment variables. Normalize location prefixes, enable strict shell mode, create URL artifact directories, and apply safer file permissions while preserving SDK script executability. Signed-off-by: ffrancis --- .github/actions/aws-s3-exchanger/action.yml | 3 +- .github/actions/build/action.yml | 64 +++++++++++++++++---- .github/workflows/build.yml | 20 ++++++- .github/workflows/process_image.yml | 38 ++++++++---- .github/workflows/test.yml | 7 ++- 5 files changed, 103 insertions(+), 29 deletions(-) diff --git a/.github/actions/aws-s3-exchanger/action.yml b/.github/actions/aws-s3-exchanger/action.yml index bd96cb3..7f2614f 100644 --- a/.github/actions/aws-s3-exchanger/action.yml +++ b/.github/actions/aws-s3-exchanger/action.yml @@ -77,7 +77,7 @@ runs: echo "Downloading files from S3 bucket..." aws s3 cp "s3://${INPUT_S3_BUCKET}/${location_prefix}${INPUT_DOWNLOAD_FILENAME}" . echo "::endgroup::" - chmod 0644 "${INPUT_DOWNLOAD_FILENAME}" + chmod 0755 "${INPUT_DOWNLOAD_FILENAME}" echo "Downloaded ${INPUT_DOWNLOAD_FILENAME} from s3://${INPUT_S3_BUCKET}/${INPUT_LOCATION}" ;; *) @@ -94,3 +94,4 @@ runs: name: presigned_url_${{ env.IMAGE_NAME }}.txt path: ${{ github.workspace }}/presigned_urls/presigned_url_${{ env.IMAGE_NAME }}.txt retention-days: 1 + diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index b35311d..624d63b 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -22,14 +22,48 @@ runs: env: IMAGE_NAME: ${{ env.IMAGE_NAME }} + CONFIG_SCRIPT_VALUE: ${{ env.CONFIG_SCRIPT }} + SYNC_SCRIPT_VALUE: ${{ env.SYNC_SCRIPT }} + APPLY_PATCH_SCRIPT_VALUE: ${{ env.APPLY_PATCH_SCRIPT }} + BUILD_ARGS_VALUE: ${{ env.BUILD_ARGS }} + BUILD_SCRIPT_VALUE: ${{ env.BUILD_SCRIPT }} + DOCKER_IMAGE_VALUE: ${{ inputs.docker_image }} run: | # Load the build arguments + set -euo pipefail set +x - export GITHUB_WORKSPACE="${{ github.workspace }}" - [ -f "./${{ env.CONFIG_SCRIPT }}" ] && export CONFIG_SCRIPT="${{ env.CONFIG_SCRIPT }}" - [ -f "./${{ env.SYNC_SCRIPT }}" ] && source "./${{ env.SYNC_SCRIPT }}" - [ -f "./${{ env.APPLY_PATCH_SCRIPT }}" ] && source "./${{ env.APPLY_PATCH_SCRIPT }}" + + is_safe_relative_path() { + local p="$1" + [[ "$p" =~ ^[A-Za-z0-9._/-]+$ ]] && [[ "$p" != /* ]] && [[ "$p" != *".."* ]] + } + + maybe_source_script() { + local script_path="$1" + if [ -z "${script_path}" ]; then + return 0 + fi + if ! is_safe_relative_path "${script_path}"; then + echo "Unsafe script path: ${script_path}" >&2 + exit 1 + fi + if [ -f "./${script_path}" ]; then + # shellcheck disable=SC1090 + source "./${script_path}" + fi + } + + if [ -n "${CONFIG_SCRIPT_VALUE}" ]; then + if ! is_safe_relative_path "${CONFIG_SCRIPT_VALUE}"; then + echo "Unsafe script path: ${CONFIG_SCRIPT_VALUE}" >&2 + exit 1 + fi + [ -f "./${CONFIG_SCRIPT_VALUE}" ] && export CONFIG_SCRIPT="${CONFIG_SCRIPT_VALUE}" + fi + + maybe_source_script "${SYNC_SCRIPT_VALUE}" + maybe_source_script "${APPLY_PATCH_SCRIPT_VALUE}" # Build inside a docker container docker run \ @@ -37,24 +71,32 @@ runs: --user $(id -u):$(id -g) \ -v $PWD/..:$PWD/.. \ -w $PWD \ - -e GITHUB_WORKSPACE="${{ github.workspace }}" \ - -e BUILD_ARGS="${{ env.BUILD_ARGS }}" \ - -e BUILD_SCRIPT="${{ env.BUILD_SCRIPT }}" \ + -e GITHUB_WORKSPACE="${GITHUB_WORKSPACE}" \ + -e BUILD_ARGS="${BUILD_ARGS_VALUE}" \ + -e BUILD_SCRIPT="${BUILD_SCRIPT_VALUE}" \ --privileged \ - ${{ inputs.docker_image }} \ + "${DOCKER_IMAGE_VALUE}" \ bash -c ' + set -euo pipefail echo "Running build script... : ${BUILD_SCRIPT}" ls -l "${BUILD_SCRIPT}" || (echo "Build script not found!" && exit 1) - source ./${BUILD_SCRIPT} + case "${BUILD_SCRIPT}" in + ""|/*|*..*|*[!A-Za-z0-9._/-]*) + echo "Unsafe build script path: ${BUILD_SCRIPT}" && exit 1 + ;; + esac + source "./${BUILD_SCRIPT}" ' - name: Create build.tar id: create_build_tar shell: bash + env: + IMAGE_NAME_VALUE: ${{ env.IMAGE_NAME }} run: | # Create a tarball of the build directory - tar -czf build_${{ env.IMAGE_NAME }}.tar -C ${{ github.workspace }}/build . - echo "Build tar created at ${{ github.workspace }}/build_${{ env.IMAGE_NAME }}.tar" + tar -czf "build_${IMAGE_NAME_VALUE}.tar" -C "${GITHUB_WORKSPACE}/build" . + echo "Build tar created at ${GITHUB_WORKSPACE}/build_${IMAGE_NAME_VALUE}.tar" - name: Upload build.tar id: upload_build_tar diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 06923b1..e3e512d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,9 +112,18 @@ jobs: - name: Run SDK Script id: run_sdk shell: bash + env: + SDK_NAME_VALUE: ${{ env.SDK_NAME }} run: | + set -euo pipefail echo "Running SDK Script" - echo "./install" | ./${{ env.SDK_NAME }} + case "${SDK_NAME_VALUE}" in + ""|/*|*..*|*[!A-Za-z0-9._/-]*) + echo "Unsafe SDK script path: ${SDK_NAME_VALUE}" >&2 + exit 1 + ;; + esac + echo "./install" | "./${SDK_NAME_VALUE}" echo "SDK Script ran successfully" - name: Build @@ -122,6 +131,7 @@ jobs: uses: AudioReach/audioreach-workflows/.github/actions/build@master with: docker_image: ${{ steps.get-docker-image.outputs.image_name }} + build_matrix: ${{ inputs.build_matrix }} env: BUILD_ARGS: ${{ matrix.build_matrix.build_args }} BUILD_SCRIPT: ${{ matrix.build_matrix.build_script }} @@ -132,8 +142,12 @@ jobs: - name: Clean Up Workspace if: always() shell: bash + env: + SDK_NAME_VALUE: ${{ env.SDK_NAME }} + IMAGE_NAME_VALUE: ${{ env.IMAGE_NAME }} run: | + set -euo pipefail echo "Cleaning Up Workspace" - rm -rf install/ ${{ env.SDK_NAME }} - rm -rf build/ ${{ github.workspace }}/build_${{ env.IMAGE_NAME }}.tar + rm -rf "install/" "${SDK_NAME_VALUE}" + rm -rf "build/" "${GITHUB_WORKSPACE}/build_${IMAGE_NAME_VALUE}.tar" echo "Workspace cleaned up successfully" diff --git a/.github/workflows/process_image.yml b/.github/workflows/process_image.yml index db75928..0c130b9 100644 --- a/.github/workflows/process_image.yml +++ b/.github/workflows/process_image.yml @@ -79,13 +79,16 @@ jobs: - name: Extract build artifact id: extract_build_artifact shell: bash + env: + WORKSPACE_DIR: ${{ github.workspace }} + IMAGE_NAME_LOCAL: ${{ env.IMAGE_NAME }} run: | #!/bin/bash set -e - mkdir -p ${{ github.workspace }}/build + mkdir -p "${WORKSPACE_DIR}/build" echo "Extracting the build artifact" - tar -xvf ${{ github.workspace }}/build_${{ env.IMAGE_NAME }}.tar -C ${{ github.workspace }}/build + tar -xvf "${WORKSPACE_DIR}/build_${IMAGE_NAME_LOCAL}.tar" -C "${WORKSPACE_DIR}/build" echo "Build artifact extracted successfully" - name: Pull meta-audioreach pre compiled image @@ -103,15 +106,20 @@ jobs: id: extract_image if: ${{ env.IMAGE_NAME != 'raspberrypi4' }} shell: bash + env: + IMAGE_NAME_LOCAL: ${{ env.IMAGE_NAME }} + FILES_TO_COPY: ${{ inputs.files_to_copy }} + DOCKER_IMAGE: ${{ steps.get-docker-image.outputs.image_name }} run: | #!/bin/bash set -e + IMAGE_ARCHIVE="qcom-multimedia-proprietary-image-${IMAGE_NAME_LOCAL}.rootfs.qcomflash.tar.gz" echo "Extracting the image" - tar -xvf qcom-multimedia-proprietary-image-${{ env.IMAGE_NAME }}.rootfs.qcomflash.tar.gz - ROOTFS_IMG=$(tar -tf qcom-multimedia-proprietary-image-${{ env.IMAGE_NAME }}.rootfs.qcomflash.tar.gz | grep 'rootfs.img$') + tar -xvf "$IMAGE_ARCHIVE" + ROOTFS_IMG=$(tar -tf "$IMAGE_ARCHIVE" | grep 'rootfs.img$') ROOTFS_DIR=$(dirname "$ROOTFS_IMG") - EXPECTED_ROOTFS_DIR="qcom-multimedia-proprietary-image-${{ env.IMAGE_NAME }}" + EXPECTED_ROOTFS_DIR="qcom-multimedia-proprietary-image-${IMAGE_NAME_LOCAL}" if [ "$ROOTFS_DIR" != "$EXPECTED_ROOTFS_DIR" ] && [ -d "$ROOTFS_DIR" ]; then rm -rf "$EXPECTED_ROOTFS_DIR" mv "$ROOTFS_DIR" "$EXPECTED_ROOTFS_DIR" @@ -121,7 +129,7 @@ jobs: # Export as GitHub Actions environment variables echo "ROOTFS_IMG=$ROOTFS_IMG" >> $GITHUB_ENV echo "ROOTFS_DIR=$ROOTFS_DIR" >> $GITHUB_ENV - rm -rf qcom-multimedia-proprietary-image-${{ env.IMAGE_NAME }}.rootfs.qcomflash.tar.gz + rm -rf "$IMAGE_ARCHIVE" echo "Image extracted successfully" ls -l "$ROOTFS_DIR/rootfs.img" @@ -162,8 +170,8 @@ jobs: -v $PWD:/workspace \ -v /tmp/rootfs:/tmp/rootfs \ -w /workspace \ - -e "FILES_TO_COPY=${{ inputs.files_to_copy }}" \ - ${{ steps.get-docker-image.outputs.image_name }} \ + -e "FILES_TO_COPY=${FILES_TO_COPY}" \ + "${DOCKER_IMAGE}" \ bash -c ' set -xe set +e @@ -191,22 +199,28 @@ jobs: id: create_tar_image if: ${{ env.IMAGE_NAME != 'raspberrypi4' }} shell: bash + env: + IMAGE_NAME_LOCAL: ${{ env.IMAGE_NAME }} + ROOTFS_DIR_LOCAL: ${{ env.ROOTFS_DIR }} run: | #!/bin/bash set -e echo $PWD echo "Creating tar image for qcomflash directory" - tar -czvf qcom-multimedia-proprietary-image-${{ env.IMAGE_NAME }}.rootfs.qcomflash.tar.gz ${{ env.ROOTFS_DIR }}/ + tar -czvf "qcom-multimedia-proprietary-image-${IMAGE_NAME_LOCAL}.rootfs.qcomflash.tar.gz" "${ROOTFS_DIR_LOCAL}/" # ✅ Moving newly created tar files into presigned_urls path - name: Move tar to presigned_urls directory if: ${{ env.IMAGE_NAME != 'raspberrypi4' }} shell: bash + env: + WORKSPACE_DIR: ${{ github.workspace }} + IMAGE_NAME_LOCAL: ${{ env.IMAGE_NAME }} run: | set -e - mkdir -p ${{ github.workspace }}/presigned_urls + mkdir -p "${WORKSPACE_DIR}/presigned_urls" - FILE="qcom-multimedia-proprietary-image-${{ env.IMAGE_NAME }}.rootfs.qcomflash.tar.gz" + FILE="qcom-multimedia-proprietary-image-${IMAGE_NAME_LOCAL}.rootfs.qcomflash.tar.gz" if [ ! -f "$FILE" ]; then @@ -214,7 +228,7 @@ jobs: exit 1 fi - mv "$FILE" ${{ github.workspace }}/presigned_urls/ + mv "$FILE" "${WORKSPACE_DIR}/presigned_urls/" echo "Moved $FILE to presigned_urls/" - name: Upload tar image diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9fc7488..fe750b7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -81,10 +81,13 @@ jobs: - name: Get build URL id: get_build_url uses: actions/github-script@v8 + env: + BUILD_URLS_JSON: ${{ inputs.build_urls }} + IMAGE_NAME: ${{ matrix.build_matrix.image_name }} with: script: | - const urls = JSON.parse('${{ inputs.build_urls }}') - const image = '${{ matrix.build_matrix.image_name }}' + const urls = JSON.parse(process.env.BUILD_URLS_JSON) + const image = process.env.IMAGE_NAME const key = `presigned_url_${image}.txt` const matched = urls[key]