Skip to content

Add GitHub Action wrapper for GameCI CLI#43

Merged
frostebite merged 7 commits intomainfrom
feat/github-action-wrapper
May 6, 2026
Merged

Add GitHub Action wrapper for GameCI CLI#43
frostebite merged 7 commits intomainfrom
feat/github-action-wrapper

Conversation

@frostebite
Copy link
Copy Markdown
Member

@frostebite frostebite commented May 5, 2026

Summary

  • Add a composite GitHub Action that installs the released game-ci CLI binary on Linux, macOS, and Windows runners
  • Default the installed CLI version to the action version tag when possible, otherwise latest, with an explicit version override
  • Allow workflows to either install game-ci for later steps or run it immediately through the args input
  • Document GitHub Action usage in the README

Validation

  • bun install --no-save
  • bun test
  • node YAML parse check for action.yml
  • git diff --check

Summary by CodeRabbit

  • New Features

    • GameCI CLI is now available as a reusable GitHub Action with configurable version and custom arguments support.
    • Added automated Unity version detection and build artifact validation in smoke testing workflows.
  • Documentation

    • Added GitHub Action usage guide to README with example workflow configurations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Warning

Rate limit exceeded

@frostebite has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes and 56 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c5b39044-8a84-411e-91e1-1b4b9b9485b1

📥 Commits

Reviewing files that changed from the base of the PR and between 43e0c7f and 80d3651.

📒 Files selected for processing (3)
  • .github/workflows/engine-smoke-test.yml
  • src/command-options/build-options.test.ts
  • src/command-options/build-options.ts
📝 Walkthrough

Walkthrough

This PR introduces the repository as a reusable GitHub Action for installing and running the GameCI CLI, with accompanying workflow tests validating Unity version detection and Docker stub builds. It also refactors Docker and environment variable command generation from string templates to array-based construction for improved maintainability.

Changes

GitHub Action Implementation

Layer / File(s) Summary
Public Interface
action.yml
Composite action defines inputs (args, version, working-directory) and platform-specific installation steps with version resolution from tag patterns or GitHub API, checksum verification on Windows, and CLI execution when args are provided.
Documentation
README.md
Adds "GitHub Action" section with YAML examples showing action usage, version pinning, and how ref selection determines which CLI release is installed.
Workflow Integration & Tests
.github/workflows/engine-smoke-test.yml
Introduces unity-build job testing Unity version detection and CLI invocation with Docker stub image; updates godot-build export logic to attempt Linux/X11 before falling back to --import validation.

Docker Command Generation Refactoring

Layer / File(s) Summary
Environment Variable Formatting
src/model/image-environment-factory.ts
getEnvVarString refactored from string concatenation to array-based builder with computed OS-specific line continuations (\ for Linux, ` for Windows).
Docker Command Construction
src/model/docker.ts
getLinuxCommand replaced with array-based argument building; normalizes environment variables and changes entrypoint from /bin/bash -c /entrypoint.sh to /bin/bash /entrypoint.sh.
Tests
src/model/docker.test.ts, src/model/image-environment-factory.test.ts
New test cases verify environment formatting with OS-specific continuations, Docker argument presence, and correct image/entrypoint references.

Sequence Diagram

sequenceDiagram
    participant Workflow as GitHub Workflow
    participant Action as GameCI Action
    participant Installer as Installation Logic
    participant CLI as GameCI CLI
    participant Docker as Docker Engine

    Workflow->>Action: Trigger with args & version
    Action->>Installer: Resolve version (tag/API)
    Installer->>Installer: Download/verify binary
    Installer->>CLI: Install & verify CLI
    Action->>CLI: Execute with arguments
    CLI->>Docker: Build with --engineVersion & --customImage
    Docker->>Docker: Run container & build
    Docker-->>Workflow: Output artifact
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A new action springs to life,
Refactored arrays, no template strife,
Docker commands now cleanly built,
GitHub workflows without guilt,
The CLI hops from branch to branch!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description covers the main objectives and validation steps, but is missing the Checklist section from the required template (contribution guide acceptance and specific checkbox items). Complete the description by adding the Checklist section from the template with appropriate checkbox selections for Readme updates and Tests additions.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add GitHub Action wrapper for GameCI CLI' clearly summarizes the main change—introducing a GitHub Action wrapper—which aligns with the substantial additions of action.yml and related documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/github-action-wrapper

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@frostebite frostebite requested a review from webbertakken May 5, 2026 15:23
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
action.yml (3)

80-80: 💤 Low value

-match treats the asset name as a regex.

$assetName = 'game-ci-windows-x64.exe' is passed directly to -match, where the dots and dashes are regex tokens. In practice this is benign because checksums.txt is unlikely to contain near-misses, but a literal-match (-like with wildcards or escape via [regex]::Escape) would be more robust and clearer about intent.

-          $expectedLine = $checksums -split "`n" | Where-Object { $_ -match $assetName } | Select-Object -First 1
+          $expectedLine = $checksums -split "`n" | Where-Object { $_ -match [regex]::Escape($assetName) } | Select-Object -First 1
🤖 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 `@action.yml` at line 80, The current search uses -match which treats
$assetName as a regex; change the lookup to perform a literal match by either
escaping $assetName with [regex]::Escape before using -match or by switching to
a wildcard literal comparison such as using -like with "*$assetName*" when
building $expectedLine (refer to the expression that assigns $expectedLine from
$checksums -split and the $assetName variable) so dots/dashes are matched
literally.

63-66: ⚡ Quick win

Unauthenticated GitHub API call may hit rate limits.

Invoke-RestMethod against api.github.com without an auth token shares the runner IP's 60 req/hour anonymous quota, which can be exhausted on busy org runners and cause the installer to fail before download. Passing ${{ github.token }} via an Authorization: Bearer ... header raises the limit substantially and is a no-op for the consumer.

Sketch
    - name: Install GameCI CLI
      if: runner.os == 'Windows'
      shell: pwsh
      env:
        GH_TOKEN: ${{ github.token }}
      run: |
        ...
        if (-not $version) {
          $headers = @{ 'Authorization' = "Bearer $env:GH_TOKEN"; 'X-GitHub-Api-Version' = '2022-11-28' }
          $release = Invoke-RestMethod "https://api.github.com/repos/$repo/releases/latest" -Headers $headers
          $version = $release.tag_name
        }
🤖 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 `@action.yml` around lines 63 - 66, The Invoke-RestMethod call that fetches
releases when $version is empty is unauthenticated and can hit anonymous GitHub
rate limits; modify the install step to accept a token via environment (e.g.
GH_TOKEN from ${{ github.token }}), build a headers hashtable including
'Authorization' = "Bearer $env:GH_TOKEN" and 'X-GitHub-Api-Version' =
'2022-11-28', and pass that hashtable to Invoke-RestMethod when calling
"https://api.github.com/repos/$repo/releases/latest" so $release and
subsequently $version are retrieved using an authenticated request.

98-108: 💤 Low value

Map inputs.args through env: instead of direct template substitution.

game-ci ${{ inputs.args }} injects user input directly into the shell script at YAML parse time. While this is conventional for a thin CLI wrapper, it creates a potential injection vector if a caller wires args to ${{ github.event.* }} (PR title, issue body, etc.). Mitigation is straightforward: define the arguments via env: and reference as $INPUT_ARGS in the script, following GitHub's documented composite action pattern. This avoids YAML/template-time interpretation of shell metacharacters while still expanding the flags correctly at runtime.

Example:

- name: Run GameCI CLI
  if: inputs.args != ''
  shell: bash
  working-directory: ${{ inputs.working-directory }}
  env:
    INPUT_ARGS: ${{ inputs.args }}
  run: game-ci $INPUT_ARGS

Low effort; currently the README only uses static flags, but this improves the pattern for future use.

🤖 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 `@action.yml` around lines 98 - 108, Replace direct template substitution of
inputs.args in the Run GameCI CLI steps with an env-bound variable to avoid
YAML/template-time injection: for both steps that reference "if: inputs.args !=
''" and the run lines "run: game-ci ${{ inputs.args }}" set env: INPUT_ARGS: ${{
inputs.args }} and change the run command to reference the env var (game-ci
$INPUT_ARGS or game-ci $env:INPUT_ARGS for pwsh) so the arguments are expanded
at runtime rather than at YAML parse time.
src/model/docker.ts (2)

61-61: ⚡ Quick win

Brittle coupling between consumer regex and producer formatting.

replace(/ \\\n/g, ' ') assumes getEnvVarString (Linux) emits exactly ' \\\n' between entries. That assumption holds today and is covered by image-environment-factory.test.ts, but it's not guaranteed by the producer's contract — any change to the join separator (e.g., dropping the leading space, or aligning Windows/Linux producers) silently leaves stray backslash-newlines in the final command. Consider exposing a helper from ImageEnvironmentFactory that returns either a continuation-joined string or a single-line string, so the consumer doesn't string-match the producer's internal format.

Sketch
// in ImageEnvironmentFactory
public static getEnvVarArgs(options: Options): string {
  // produce single-line flat string for direct CLI use
}
public static getEnvVarStringMultiline(options: Options): string {
  // produce continuation-joined string for human-readable scripts
}
🤖 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 `@src/model/docker.ts` at line 61, The current code in src/model/docker.ts
relies on brittle string-munging of ImageEnvironmentFactory.getEnvVarString by
doing .replace(/ \\\n/g, ' '); instead, add a clear, stable API on
ImageEnvironmentFactory (e.g., getEnvVarSingleLine or getEnvVarArgs) that
returns the env vars formatted as a single-line/CLI-safe string (or an array of
args) and update the use site in docker.ts to call that new method (replace
references to ImageEnvironmentFactory.getEnvVarString and the .replace(...)
logic with the new helper) so consumers don’t rely on the producer’s internal
continuation-formatting.

87-112: ⚖️ Poor tradeoff

Consider mirroring the Linux array-based builder for getWindowsCommand.

getLinuxCommand is now a clean filter/join over an args array, while getWindowsCommand continues to use a String.dedent template with hard-coded continuations. The asymmetry makes future edits (adding/removing flags conditionally) error-prone on the Windows path — e.g., conditional gitPrivateToken / sshAgent injections would need to be retrofitted as inline ternaries inside the template. Aligning the two builders would also let getEnvVarString's windows output be normalized symmetrically (no need for divergent post-processing later).

Not blocking; safe to defer.

🤖 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 `@src/model/docker.ts` around lines 87 - 112, The Windows command builder
getWindowsCommand should be refactored to mirror getLinuxCommand: build an args
array (instead of a String.dedent template) and push each flag/volume/env entry
into that array, adding conditional entries (e.g., GIT_PRIVATE_TOKEN,
UNITY_SERIAL, sshAgent-related items) only when present; use
ImageEnvironmentFactory.getEnvVarString(options) as one array element and then
join the array into the final string with the proper PowerShell
continuations/backticks so behavior is identical to the Linux path while keeping
the same values for currentWorkDir, cliDistPath, cliStoragePath,
dockerWorkspacePath, homeDir, and image and preserving the final "powershell
c:/steps/entrypoint.ps1" execution item.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@action.yml`:
- Around line 77-93: Change the checksum logic from "fail-open" to
"fail-closed": make fetching and verifying checksums using
Invoke-WebRequest/$checksumUrl mandatory unless a new opt-in input (e.g.
inputs.skip_checksum) is set; if Invoke-WebRequest throws or no matching
$expectedLine is found, throw an error instead of only Write-Warning, and only
bypass this error when inputs.skip_checksum=true. Locate the block that sets
$expectedHash, the catch that currently Write-Warning, and the verification that
compares $expectedHash to (Get-FileHash -Path $binaryPath -Algorithm
SHA256).Hash; replace the silent fallback (empty $expectedHash) with an explicit
throw on fetch/missing checksum unless the new skip flag is enabled, and surface
a clear error message explaining how to opt out via the new input.
- Around line 28-47: The verify_checksum() in install.sh currently treats
missing sha256sum, failed fetch of checksums.txt, or missing matching checksum
as soft-success; change it to be strict: in verify_checksum() detect absence of
sha256sum, HTTP/fetch failures for checksums.txt, or no matching checksum and
log an explicit error via stderr and return non-zero so the script exits
non-zero; keep the existing mismatch comparison behavior but ensure any of these
earlier failures cause install.sh to fail (so the non-Windows path enforces
integrity comparable to the Windows path).

---

Nitpick comments:
In `@action.yml`:
- Line 80: The current search uses -match which treats $assetName as a regex;
change the lookup to perform a literal match by either escaping $assetName with
[regex]::Escape before using -match or by switching to a wildcard literal
comparison such as using -like with "*$assetName*" when building $expectedLine
(refer to the expression that assigns $expectedLine from $checksums -split and
the $assetName variable) so dots/dashes are matched literally.
- Around line 63-66: The Invoke-RestMethod call that fetches releases when
$version is empty is unauthenticated and can hit anonymous GitHub rate limits;
modify the install step to accept a token via environment (e.g. GH_TOKEN from
${{ github.token }}), build a headers hashtable including 'Authorization' =
"Bearer $env:GH_TOKEN" and 'X-GitHub-Api-Version' = '2022-11-28', and pass that
hashtable to Invoke-RestMethod when calling
"https://api.github.com/repos/$repo/releases/latest" so $release and
subsequently $version are retrieved using an authenticated request.
- Around line 98-108: Replace direct template substitution of inputs.args in the
Run GameCI CLI steps with an env-bound variable to avoid YAML/template-time
injection: for both steps that reference "if: inputs.args != ''" and the run
lines "run: game-ci ${{ inputs.args }}" set env: INPUT_ARGS: ${{ inputs.args }}
and change the run command to reference the env var (game-ci $INPUT_ARGS or
game-ci $env:INPUT_ARGS for pwsh) so the arguments are expanded at runtime
rather than at YAML parse time.

In `@src/model/docker.ts`:
- Line 61: The current code in src/model/docker.ts relies on brittle
string-munging of ImageEnvironmentFactory.getEnvVarString by doing .replace(/
\\\n/g, ' '); instead, add a clear, stable API on ImageEnvironmentFactory (e.g.,
getEnvVarSingleLine or getEnvVarArgs) that returns the env vars formatted as a
single-line/CLI-safe string (or an array of args) and update the use site in
docker.ts to call that new method (replace references to
ImageEnvironmentFactory.getEnvVarString and the .replace(...) logic with the new
helper) so consumers don’t rely on the producer’s internal
continuation-formatting.
- Around line 87-112: The Windows command builder getWindowsCommand should be
refactored to mirror getLinuxCommand: build an args array (instead of a
String.dedent template) and push each flag/volume/env entry into that array,
adding conditional entries (e.g., GIT_PRIVATE_TOKEN, UNITY_SERIAL,
sshAgent-related items) only when present; use
ImageEnvironmentFactory.getEnvVarString(options) as one array element and then
join the array into the final string with the proper PowerShell
continuations/backticks so behavior is identical to the Linux path while keeping
the same values for currentWorkDir, cliDistPath, cliStoragePath,
dockerWorkspacePath, homeDir, and image and preserving the final "powershell
c:/steps/entrypoint.ps1" execution item.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6ef28687-8bd6-4965-824b-1d53be773fcd

📥 Commits

Reviewing files that changed from the base of the PR and between 753566e and 43e0c7f.

📒 Files selected for processing (7)
  • .github/workflows/engine-smoke-test.yml
  • README.md
  • action.yml
  • src/model/docker.test.ts
  • src/model/docker.ts
  • src/model/image-environment-factory.test.ts
  • src/model/image-environment-factory.ts

Comment thread action.yml
Comment on lines +28 to +47
- name: Install GameCI CLI
if: runner.os != 'Windows'
shell: bash
run: |
set -euo pipefail

version="${{ inputs.version }}"
action_ref="${{ github.action_ref }}"

if [ -z "$version" ] && printf '%s' "$action_ref" | grep -Eq '^v[0-9]'; then
version="$action_ref"
fi

export GAME_CI_INSTALL="${RUNNER_TEMP}/game-ci/bin"
if [ -n "$version" ]; then
export GAME_CI_VERSION="$version"
fi

"${GITHUB_ACTION_PATH}/install.sh"
echo "$GAME_CI_INSTALL" >> "$GITHUB_PATH"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect install.sh for checksum verification
fd -t f 'install\.sh$'
fd -t f 'install\.sh$' --exec cat {}

Repository: game-ci/cli

Length of output: 5240


Checksum verification is present in install.sh, but uses soft-failure logic that succeeds when tools/files are unavailable.

The install.sh script includes a verify_checksum() function that executes after the binary is installed. However, it returns success (exit 0) in several scenarios without actually verifying the checksum:

  • If sha256sum command is unavailable
  • If checksums.txt cannot be fetched from releases
  • If no matching checksum is found for the asset

The function only errors if a checksum is found and the comparison fails. This is more lenient than strict enforcement; while checksums are attempted, the verification is not guaranteed on every install. Confirm whether this soft-failure behavior is intentional or should be made more strict for consistency with the Windows path's integrity guarantees.

🤖 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 `@action.yml` around lines 28 - 47, The verify_checksum() in install.sh
currently treats missing sha256sum, failed fetch of checksums.txt, or missing
matching checksum as soft-success; change it to be strict: in verify_checksum()
detect absence of sha256sum, HTTP/fetch failures for checksums.txt, or no
matching checksum and log an explicit error via stderr and return non-zero so
the script exits non-zero; keep the existing mismatch comparison behavior but
ensure any of these earlier failures cause install.sh to fail (so the
non-Windows path enforces integrity comparable to the Windows path).

Comment thread action.yml
Comment on lines +77 to +93
$expectedHash = ''
try {
$checksums = Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing | Select-Object -ExpandProperty Content
$expectedLine = $checksums -split "`n" | Where-Object { $_ -match $assetName } | Select-Object -First 1
if ($expectedLine) {
$expectedHash = ($expectedLine -split '\s+')[0].ToLower()
}
} catch {
Write-Warning "Checksum verification skipped because checksum metadata could not be fetched: $_"
}

if ($expectedHash) {
$actualHash = (Get-FileHash -Path $binaryPath -Algorithm SHA256).Hash.ToLower()
if ($expectedHash -ne $actualHash) {
throw "Checksum verification failed. Expected $expectedHash, got $actualHash"
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Failing open on checksum verification weakens supply-chain integrity guarantees.

If Invoke-WebRequest to checksums.txt throws for any reason (transient 404, network blip, GitHub outage, asset not yet uploaded for a fresh release), $expectedHash stays empty, the if ($expectedHash) guard at line 88 is false, and the binary is installed and added to PATH with no integrity check — only a Write-Warning that is easy to miss in workflow logs. This is the opposite of fail-closed behavior expected from an installer.

Suggest making the failure mode explicit: fail by default, allow opt-in skip via input.

Proposed fix
         $expectedHash = ''
         try {
           $checksums = Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing | Select-Object -ExpandProperty Content
           $expectedLine = $checksums -split "`n" | Where-Object { $_ -match $assetName } | Select-Object -First 1
           if ($expectedLine) {
             $expectedHash = ($expectedLine -split '\s+')[0].ToLower()
           }
         } catch {
-          Write-Warning "Checksum verification skipped because checksum metadata could not be fetched: $_"
+          throw "Checksum verification failed: could not fetch $checksumUrl ($_)"
         }

-        if ($expectedHash) {
-          $actualHash = (Get-FileHash -Path $binaryPath -Algorithm SHA256).Hash.ToLower()
-          if ($expectedHash -ne $actualHash) {
-            throw "Checksum verification failed. Expected $expectedHash, got $actualHash"
-          }
+        if (-not $expectedHash) {
+          throw "Checksum verification failed: no entry for $assetName in $checksumUrl"
+        }
+        $actualHash = (Get-FileHash -Path $binaryPath -Algorithm SHA256).Hash.ToLower()
+        if ($expectedHash -ne $actualHash) {
+          throw "Checksum verification failed. Expected $expectedHash, got $actualHash"
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$expectedHash = ''
try {
$checksums = Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing | Select-Object -ExpandProperty Content
$expectedLine = $checksums -split "`n" | Where-Object { $_ -match $assetName } | Select-Object -First 1
if ($expectedLine) {
$expectedHash = ($expectedLine -split '\s+')[0].ToLower()
}
} catch {
Write-Warning "Checksum verification skipped because checksum metadata could not be fetched: $_"
}
if ($expectedHash) {
$actualHash = (Get-FileHash -Path $binaryPath -Algorithm SHA256).Hash.ToLower()
if ($expectedHash -ne $actualHash) {
throw "Checksum verification failed. Expected $expectedHash, got $actualHash"
}
}
$expectedHash = ''
try {
$checksums = Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing | Select-Object -ExpandProperty Content
$expectedLine = $checksums -split "`n" | Where-Object { $_ -match $assetName } | Select-Object -First 1
if ($expectedLine) {
$expectedHash = ($expectedLine -split '\s+')[0].ToLower()
}
} catch {
throw "Checksum verification failed: could not fetch $checksumUrl ($_)"
}
if (-not $expectedHash) {
throw "Checksum verification failed: no entry for $assetName in $checksumUrl"
}
$actualHash = (Get-FileHash -Path $binaryPath -Algorithm SHA256).Hash.ToLower()
if ($expectedHash -ne $actualHash) {
throw "Checksum verification failed. Expected $expectedHash, got $actualHash"
}
🤖 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 `@action.yml` around lines 77 - 93, Change the checksum logic from "fail-open"
to "fail-closed": make fetching and verifying checksums using
Invoke-WebRequest/$checksumUrl mandatory unless a new opt-in input (e.g.
inputs.skip_checksum) is set; if Invoke-WebRequest throws or no matching
$expectedLine is found, throw an error instead of only Write-Warning, and only
bypass this error when inputs.skip_checksum=true. Locate the block that sets
$expectedHash, the catch that currently Write-Warning, and the verification that
compares $expectedHash to (Get-FileHash -Path $binaryPath -Algorithm
SHA256).Hash; replace the silent fallback (empty $expectedHash) with an explicit
throw on fetch/missing checksum unless the new skip flag is enabled, and surface
a clear error message explaining how to opt out via the new input.

@frostebite frostebite merged commit 857dac1 into main May 6, 2026
13 checks passed
@frostebite frostebite deleted the feat/github-action-wrapper branch May 6, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant