name: cargo-frisk description: See what you are actually shipping to crates.io — diff the packaged .crate against what git tracks. author: Haidar Jbeily branding: icon: search color: orange inputs: version: description: Version of cargo-frisk to install, or "latest". required: false default: latest args: description: Extra arguments passed to `cargo frisk`. required: false default: "" fail-on: description: Severity at which to fail the job (low, medium, high, critical, none). required: false default: "" working-directory: description: Directory to run in. required: false default: "." upload-sarif: description: Upload results to GitHub Code Scanning so they annotate the PR diff. required: false default: "false" sarif-file: description: Where to write the SARIF report. required: false default: frisk.sarif outputs: exit-code: description: 0 nothing unexpected, 1 findings at or above the threshold, 2 tool error. value: ${{ steps.frisk.outputs.exit-code }} sarif-file: description: Path to the SARIF report, when one was produced. value: ${{ steps.frisk.outputs.sarif-file }} runs: using: composite steps: # `cargo package` needs the full working tree; a shallow checkout is fine, # but `git ls-files` needs the repository to actually be there. - name: Check out is present shell: bash run: | if [ ! -d "${{ inputs.working-directory }}/.git" ] && ! git -C "${{ inputs.working-directory }}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then echo "::warning::not inside a git work tree — cargo-frisk will degrade to a packaged-file listing" fi - name: Install cargo-binstall uses: cargo-bins/cargo-binstall@main - name: Install cargo-frisk shell: bash run: | if [ "${{ inputs.version }}" = "latest" ]; then cargo binstall --no-confirm cargo-frisk else cargo binstall --no-confirm "cargo-frisk@${{ inputs.version }}" fi - name: Run cargo frisk id: frisk shell: bash working-directory: ${{ inputs.working-directory }} run: | set +e EXTRA=() [ -n "${{ inputs.fail-on }}" ] && EXTRA+=(--fail-on "${{ inputs.fail-on }}") # Human output for the log, so the job is readable without leaving it. cargo frisk --color always ${{ inputs.args }} "${EXTRA[@]}" CODE=$? if [ "${{ inputs.upload-sarif }}" = "true" ]; then cargo frisk --sarif -o "${{ inputs.sarif-file }}" ${{ inputs.args }} "${EXTRA[@]}" SARIF_CODE=$? # A tool error while producing SARIF is worse than a finding. [ "$SARIF_CODE" -eq 2 ] && CODE=2 echo "sarif-file=${{ inputs.working-directory }}/${{ inputs.sarif-file }}" >> "$GITHUB_OUTPUT" fi echo "exit-code=$CODE" >> "$GITHUB_OUTPUT" exit 0 # Uploaded before the failure gate, so the annotations survive a red job. # # This needs `security-events: write` in the *calling* workflow — a # composite action cannot grant itself permissions. A pull request from a # fork gets a read-only token regardless, so skip rather than 403. - name: Check Code Scanning access id: can-upload shell: bash run: | if [ "${{ inputs.upload-sarif }}" != "true" ]; then echo "result=false" >> "$GITHUB_OUTPUT" elif [ -n "${{ github.event.pull_request.head.repo.full_name }}" ] \ && [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then echo "result=false" >> "$GITHUB_OUTPUT" echo "::notice::fork pull request — Code Scanning upload skipped (read-only token)" else echo "result=true" >> "$GITHUB_OUTPUT" fi - name: Upload SARIF if: ${{ steps.can-upload.outputs.result == 'true' }} uses: github/codeql-action/upload-sarif@v4 with: sarif_file: ${{ steps.frisk.outputs.sarif-file }} category: cargo-frisk - name: Fail the job on findings shell: bash run: | CODE="${{ steps.frisk.outputs.exit-code }}" case "$CODE" in 0) echo "cargo-frisk: nothing unexpected" ;; 1) echo "::error::cargo-frisk found issues at or above the fail threshold"; exit 1 ;; *) echo "::error::cargo-frisk failed to run (exit $CODE)"; exit "$CODE" ;; esac