Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions .github/workflows/homebrew-bump.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
name: Brew Bump

on:
# Fires only for non-prerelease publications, so `rc` tags never reach
# homebrew-core. Manual dispatch remains available for re-runs.
release:
types: [released]
workflow_dispatch:
inputs:
version:
type: string
required: true
description: "Release tag to use. e.g. refs/tags/2.2.4"
description: "Release tag to bump to, e.g. 3.0.0"

jobs:
update_brew_formula:
runs-on: ubuntu-latest

steps:
# - name: Update Homebrew tap
# uses: dawidd6/action-homebrew-bump-formula@v3
# with:
# token: ${{ secrets.HOMEBREW_BUMP_ACCESS_TOKEN }}
# org: XCTestHTMLReport
# tap: XCTestHTMLReport/homebrew-xchtmlreport
# formula: xchtmlreport
# tag: ${{ github.event.inputs.version }}
- name: Resolve tag
id: tag
run: |
if [[ -n "${{ github.event.inputs.version }}" ]]; then
TAG="${{ github.event.inputs.version }}"
else
TAG="${{ github.event.release.tag_name }}"
fi
# Tolerate a full ref being pasted into the manual input.
TAG="${TAG#refs/tags/}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
Comment on lines +20 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not interpolate tag values into shell source.

Lines 23-26 expand manual input and release metadata before Bash parses the script. A crafted value can terminate the quoted assignment and execute commands. Map both values through env, then use quoted shell variables. Validate the resolved tag before publishing it.

Proposed fix
     - name: Resolve tag
       id: tag
+      env:
+        INPUT_VERSION: ${{ inputs.version }}
+        RELEASE_TAG: ${{ github.event.release.tag_name }}
       run: |
-        if [[ -n "${{ github.event.inputs.version }}" ]]; then
-          TAG="${{ github.event.inputs.version }}"
+        if [[ -n "$INPUT_VERSION" ]]; then
+          TAG="$INPUT_VERSION"
         else
-          TAG="${{ github.event.release.tag_name }}"
+          TAG="$RELEASE_TAG"
         fi
🧰 Tools
🪛 zizmor (1.29.0)

[error] 23-23: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 24-24: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 26-26: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/homebrew-bump.yml around lines 20 - 30, Update the
“Resolve tag” step to pass the manual version and release tag through the
workflow step’s env mapping, then read them via quoted Bash variables instead of
interpolating expressions into shell source. Preserve the refs/tags
normalization, and validate the resolved TAG before writing it to GITHUB_OUTPUT
so invalid or empty values cannot proceed to publishing.

Source: Linters/SAST tools

echo "bumping to ${TAG}"

- name: Update Official Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@v3.10.1
uses: dawidd6/action-homebrew-bump-formula@v8

Check failure on line 34 in .github/workflows/homebrew-bump.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=XCTestHTMLReport_XCTestHTMLReport&issues=AZ_dvzqcYwCGQwzThDXZ&open=AZ_dvzqcYwCGQwzThDXZ&pullRequest=394
with:
token: ${{ secrets.HOMEBREW_BUMP_ACCESS_TOKEN }}
# org: XCTestHTMLReport
formula: xctesthtmlreport
tag: ${{ github.event.inputs.version }}
tag: ${{ steps.tag.outputs.tag }}
86 changes: 69 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,61 @@
tags:
- '[0-9]+.[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
# Lets the whole build/sign/package path be exercised without publishing
# anything. Before this existed the only way to test a release was to cut one.
workflow_dispatch:
inputs:
dry_run:
type: boolean
default: true
description: "Build, sign and package, but do not notarize or publish"

jobs:
build:
runs-on: macos-latest
outputs:
prerelease: ${{ steps.metadata.outputs.prerelease }}

steps:
- uses: actions/checkout@v4

- name: Configure Signing
uses: Apple-Actions/import-codesign-certs@v1
uses: Apple-Actions/import-codesign-certs@v7

Check failure on line 27 in .github/workflows/release.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=XCTestHTMLReport_XCTestHTMLReport&issues=AZ_dvzoLYwCGQwzThDXV&open=AZ_dvzoLYwCGQwzThDXV&pullRequest=394

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

printf '%s\n' '--- release workflow ---'
cat -n .github/workflows/release.yml | sed -n '1,180p'
printf '%s\n' '--- homebrew workflow ---'
cat -n .github/workflows/homebrew-bump.yml | sed -n '1,70p'
printf '%s\n' '--- changed workflow summary ---'
git diff --stat -- .github/workflows/release.yml .github/workflows/homebrew-bump.yml
printf '%s\n' '--- changed action references ---'
git diff --unified=3 -- .github/workflows/release.yml .github/workflows/homebrew-bump.yml | rg -n '^[+-].*uses:|^@@' || true

Repository: XCTestHTMLReport/XCTestHTMLReport

Length of output: 8891


🏁 Script executed:

python3 - <<'PY'
import re
from pathlib import Path

files = [
    Path(".github/workflows/release.yml"),
    Path(".github/workflows/homebrew-bump.yml"),
]
use_re = re.compile(r"^\s*uses:\s*([^#\s]+)")
sha_re = re.compile(r"^[0-9a-fA-F]{40}$")

for path in files:
    print(path)
    for number, line in enumerate(path.read_text().splitlines(), 1):
        match = use_re.match(line)
        if not match:
            continue
        ref = match.group(1).rsplit("@", 1)[-1]
        kind = "full commit SHA" if sha_re.fullmatch(ref) else "tag or branch ref"
        print(f"{number}: {match.group(1)} -> {kind}")
PY

Repository: XCTestHTMLReport/XCTestHTMLReport

Length of output: 714


Pin each changed action to a full commit SHA.

These version tags can change after review. The actions access signing credentials or release tokens. Retain the intended version in an inline comment.

  • .github/workflows/release.yml: lines 27, 33, 134–137, 156, and 166.
  • .github/workflows/homebrew-bump.yml: line 34.
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[failure] 27-27: Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=XCTestHTMLReport_XCTestHTMLReport&issues=AZ_dvzoLYwCGQwzThDXV&open=AZ_dvzoLYwCGQwzThDXV&pullRequest=394

📍 Affects 2 files
  • .github/workflows/release.yml#L27-L27 (this comment)
  • .github/workflows/release.yml#L33-L33
  • .github/workflows/release.yml#L134-L137
  • .github/workflows/release.yml#L156-L156
  • .github/workflows/release.yml#L166-L166
  • .github/workflows/homebrew-bump.yml#L34-L34
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml at line 27, Pin every changed GitHub Action to
its exact full commit SHA instead of a mutable version tag, while preserving the
currently intended action version in an inline comment. Apply this to
.github/workflows/release.yml at lines 27, 33, 134-137, 156, and 166, and to
.github/workflows/homebrew-bump.yml at line 34.

Source: Linters/SAST tools

with:
p12-file-base64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
p12-password: ${{ secrets.P12_PASSWORD }}

- name: Setup Xcode version
uses: maxim-lobanov/[email protected]
uses: maxim-lobanov/[email protected]
with:
xcode-version: ^16
xcode-version: latest-stable

- name: Generate Metadata
id: metadata
run: |
[[ "$GITHUB_REF" =~ refs/tags ]] && VERSION=${GITHUB_REF/refs\/tags\//} || exit
echo ::set-output name=version::${VERSION}
echo ::set-output name=bin_path::.build/universal/release/xchtmlreport
echo ::set-output name=archive_name::xchtmlreport-${VERSION}.zip
if [[ "$GITHUB_REF" =~ ^refs/tags/ ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
VERSION="0.0.0-dryrun"
fi
# `rc` tags carry no hyphen, so a `contains(github.ref, '-')` test
# never fired for them and release candidates shipped as full releases.
if [[ "$VERSION" == *rc* ]]; then PRERELEASE=true; else PRERELEASE=false; fi
{
echo "version=${VERSION}"
echo "prerelease=${PRERELEASE}"
echo "bin_path=.build/universal/release/xchtmlreport"
echo "archive_name=xchtmlreport-${VERSION}.zip"
} >> "$GITHUB_OUTPUT"

- name: Stamp version into the binary
# Version.swift was only ever written by the post-release bump job, so the
# released binary reported whatever happened to be on main rather than the
# tag it was built from. Stamping here makes `--version` match the tag.
run: |
echo "let version = \"${{ steps.metadata.outputs.version }}\"" \
Comment on lines +40 to +60

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Validate release tags before reuse.

Line 60 interpolates a tag-derived output into shell source. A tag containing a quote or shell syntax can alter the generated command. Validate VERSION against the repository release-tag grammar in Generate Metadata. Pass the validated value through env and use "$VERSION" in shell steps.

Proposed fix
     - name: Stamp version into the binary
+      env:
+        VERSION: ${{ steps.metadata.outputs.version }}
       run: |
-        echo "let version = \"${{ steps.metadata.outputs.version }}\"" \
+        printf 'let version = "%s"\n' "$VERSION" \
           > Sources/XCTestHTMLReport/Version.swift
🧰 Tools
🪛 zizmor (1.29.0)

[info] 60-60: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 40 - 60, Validate VERSION in
Generate Metadata against the repository’s release-tag grammar before writing or
reusing it, rejecting invalid tag values. Pass the validated version through the
workflow step’s env and update the Stamp version into the binary shell command
to consume "$VERSION" rather than interpolating steps.metadata.outputs.version
directly into shell source.

Source: Linters/SAST tools

> Sources/XCTestHTMLReport/Version.swift
cat Sources/XCTestHTMLReport/Version.swift

- name: Build (arm64)
run: swift build -v -c release --triple arm64-apple-macosx
Expand All @@ -44,16 +73,28 @@
lipo -create -output ${{ steps.metadata.outputs.bin_path }} \
.build/arm64-apple-macosx/release/xchtmlreport \
.build/x86_64-apple-macosx/release/xchtmlreport
lipo -info ${{ steps.metadata.outputs.bin_path }}

- name: Verify the built binary reports the tagged version
run: |
REPORTED=$(${{ steps.metadata.outputs.bin_path }} --version)
echo "reported: ${REPORTED}"
if [[ "${REPORTED}" != "${{ steps.metadata.outputs.version }}" ]]; then
echo "::error::binary reports '${REPORTED}' but this is release '${{ steps.metadata.outputs.version }}'"
exit 1
fi

- name: Sign
run: |
codesign --verbose --verify --options=runtime -f \
-s "Developer ID Application: Tyler Vick (${{ secrets.AC_TEAM_ID }})" \
${{ steps.metadata.outputs.bin_path }}

- name: Verify
# --deep is deprecated by Apple and is not the right check for a lone
# executable; --strict on the binary itself is.
run: |
codesign -vvv --deep --strict ${{ steps.metadata.outputs.bin_path }}
codesign -vvv --strict ${{ steps.metadata.outputs.bin_path }}

- name: Package
run: |
Expand All @@ -62,6 +103,7 @@
${{ steps.metadata.outputs.archive_name }}

- name: Notarize
if: github.event_name == 'push'
run: |
xcrun notarytool submit ${{ steps.metadata.outputs.archive_name }} \
--apple-id ${{ secrets.AC_USERNAME }} \
Expand All @@ -75,19 +117,26 @@
name: application
path: ${{ steps.metadata.outputs.archive_name }}

- name: Dry run summary
if: github.event_name == 'workflow_dispatch'
run: |
echo "### Dry run complete" >> "$GITHUB_STEP_SUMMARY"
echo "Built, signed and packaged \`${{ steps.metadata.outputs.archive_name }}\`." >> "$GITHUB_STEP_SUMMARY"
echo "Notarization and publishing were skipped." >> "$GITHUB_STEP_SUMMARY"

release:
runs-on: ubuntu-latest

needs: build

if: github.event_name == 'push'

steps:
- name: Download
uses: actions/download-artifact@v4.1.7
uses: actions/download-artifact@v4

- name: Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3

Check failure on line 137 in .github/workflows/release.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=XCTestHTMLReport_XCTestHTMLReport&issues=AZ_dvzoLYwCGQwzThDXW&open=AZ_dvzoLYwCGQwzThDXW&pullRequest=394
with:
prerelease: ${{ contains(github.ref, '-') }}
prerelease: ${{ needs.build.outputs.prerelease == 'true' }}
generate_release_notes: true
files: |
application/xchtmlreport-*
Expand All @@ -97,11 +146,14 @@
bump_version:
runs-on: ubuntu-latest
needs: release
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4

# Bumps the patch component only. Major and minor bumps are deliberate
# decisions and are made by hand before tagging.
- name: Get next version
uses: reecetech/version-increment@2022.5.1
uses: reecetech/version-increment@2024.10.1

Check failure on line 156 in .github/workflows/release.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=XCTestHTMLReport_XCTestHTMLReport&issues=AZ_dvzoLYwCGQwzThDXX&open=AZ_dvzoLYwCGQwzThDXX&pullRequest=394
id: version
with:
scheme: semver
Expand All @@ -111,7 +163,7 @@
run: echo 'let version = "${{ steps.version.outputs.version }}"' > Sources/XCTestHTMLReport/Version.swift

- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
uses: peter-evans/create-pull-request@v8

Check failure on line 166 in .github/workflows/release.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use full commit SHA hash for this dependency.

See more on https://sonarcloud.io/project/issues?id=XCTestHTMLReport_XCTestHTMLReport&issues=AZ_dvzoLYwCGQwzThDXY&open=AZ_dvzoLYwCGQwzThDXY&pullRequest=394
with:
title: "${{ steps.version.outputs.version }} Version Bump"
body: "Bumping version from ${{ steps.version.outputs.current-version }} to ${{ steps.version.outputs.version }}"
Expand Down
2 changes: 1 addition & 1 deletion Sources/XCTestHTMLReport/Version.swift
Original file line number Diff line number Diff line change
@@ -1 +1 @@
let version = "2.5.2-pre.bc4e30e"
let version = "3.0.0-pre"
Loading