Skip to content

fix: Verify installer script checksums before Unity Editor installs it - #1668

Merged
hatayama merged 2 commits into
v3-betafrom
security/unity-editor-installer-verify
Jul 10, 2026
Merged

hatayama merged 2 commits into
v3-betafrom
security/unity-editor-installer-verify

Conversation

@hatayama

@hatayama hatayama commented Jul 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Unity Editor no longer executes an unverified installer script fetched over the network. Both macOS and Windows fetch install.sh / install.ps1 from the same dispatcher release the CLI is being installed from, verify the shipped SHA-256, and only then run the script.

User Impact

  • Before: the editor install command downloaded the installer from raw.githubusercontent.com/<repo>/dispatcher-vX.Y.Z/scripts/install.{sh,ps1} (a git tag ref) and executed it with no checksum. Windows piped the fetched script straight into iex, so a tampered release could have run arbitrary code on the developer machine.
  • After: the editor install command mirrors what uloop update already did — it downloads the release-asset installer plus its .sha256, verifies the hash, and executes the on-disk script. On Windows, irm | iex is gone; the script is saved to a temp file, verified, and re-launched via powershell -NoProfile -ExecutionPolicy Bypass -File, with try / finally cleaning up the temp directory even when verification or execution fails.

Changes

  • Point the installer script URL at the release download URL (https://github.com/hatayama/unity-cli-loop/releases/download/<dispatcher-tag>/install.{sh,ps1}) and add a matching .sha256 sidecar URL. Both files are already produced by scripts/package-dispatcher.sh and uploaded by dispatcher-publish.yml.
  • POSIX remote command: mktemp -d + curl -fsSL for the script and its .sha256, sha256sum -c (with shasum -a 256 -c fallback) run inside the temp dir so the checksum file name matches, then ULOOP_VERSION=<tag> sh $tmp/install.sh. Every step is &&-chained because the command runs under a single /bin/sh -c and cannot rely on set -e.
  • Windows remote command: Invoke-WebRequest -OutFile into a per-run temp dir, compare Get-FileHash SHA256 case-insensitively against the leading whitespace-delimited token of the .sha256 (which contains <hash> <filename>), then & powershell -NoProfile -ExecutionPolicy Bypass -File $script_path. try / finally propagates $LASTEXITCODE and removes the temp dir on failure.
  • The local package-development install path (BuildPosixLocalInstallScriptCommand / BuildWindowsLocalInstallScriptCommand) is untouched because it never fetches over the network.
  • CliConstants.RAW_CONTENT_BASE_URL is removed because no C# call site remains. README bootstrap URLs still point at raw content from main and are unrelated. installer.go's ScriptURL (raw ref) is now referenced only by its own tests and is intentionally left alone per TODO 1 scope.

Verification

  • dist/darwin-arm64/uloop compile --project-path <repo> → 0 errors, 0 warnings.
  • dist/darwin-arm64/uloop run-tests --project-path <repo> --filter-type regex --filter-value io\.github\.hatayama\.UnityCliLoop\.Tests\.Editor\.NativeCliInstallerTests --test-mode EditMode → 30 passed, 0 failed.

Refs: Obsidian TODO 1 — Unity Editor 側インストール経路の検証強化.

Review in cubic

The Unity Editor's remote install path used to fetch `install.sh` /
`install.ps1` from `raw.githubusercontent.com` via a git tag and execute
them without verification. Git tags can be moved after they are
published, and `irm | iex` on Windows executes the fetched script
straight from memory, so a compromised release could ship an unverified
installer to any editor that runs the remote install command.

Switch both platforms to the same flow that `uloop update` already
uses:

- Fetch the installer script and its `.sha256` sidecar from the
  dispatcher release assets (same generation as `uloop update`).
- Verify SHA-256 with `sha256sum`/`shasum` on POSIX and `Get-FileHash`
  on Windows, comparing case-insensitively against the first token of
  the `.sha256` file (which contains `<hash>  <filename>`).
- On Windows, replace `irm | iex` with a temp-file download followed
  by `powershell -NoProfile -ExecutionPolicy Bypass -File $script`,
  wrapped in `try` / `finally` so the temp dir is removed on failure
  and `$LASTEXITCODE != 0` re-throws.
- Chain the POSIX steps with `&&` (the whole command runs under a
  single `/bin/sh -c` where `set -e` is not applied for us) so a curl
  or checksum failure aborts before the script runs.

The local script path used during package development is unchanged
because it never fetches over the network, and `RAW_CONTENT_BASE_URL`
in `CliConstants` is removed since it is no longer referenced from C#.
@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1b33a6ef-b458-4362-8927-3ca556862eb2

📥 Commits

Reviewing files that changed from the base of the PR and between a3bd402 and a1d0a8c.

📒 Files selected for processing (2)
  • Assets/Tests/Editor/NativeCliInstallerTests.cs
  • Packages/src/Editor/Infrastructure/CLI/NativeCliCommandBuilder.cs
🚧 Files skipped from review as they are similar to previous changes (2)
  • Packages/src/Editor/Infrastructure/CLI/NativeCliCommandBuilder.cs
  • Assets/Tests/Editor/NativeCliInstallerTests.cs

📝 Walkthrough

Walkthrough

Native CLI installer commands now use GitHub release assets for POSIX and Windows scripts, download matching .sha256 files, verify checksums before execution, and clean up temporary files. Tests cover URL generation, checksum handling, command execution, fallback behavior, and version normalization.

Changes

Native CLI installer verification

Layer / File(s) Summary
Release asset URL resolution
Packages/src/Editor/Domain/CliConstants.cs, Packages/src/Editor/Infrastructure/CLI/NativeCliCommandBuilder.cs
Installer script URLs now target release downloads, and checksum URLs append .sha256.
Verified installer command generation
Packages/src/Editor/Infrastructure/CLI/NativeCliCommandBuilder.cs
POSIX and Windows commands download installer and checksum files, validate SHA256 values, execute local scripts, handle failures, and clean up temporary files.
Installer command assertions
Assets/Tests/Editor/NativeCliInstallerTests.cs
Tests verify release asset URLs, checksum commands, PowerShell -File execution, fallback behavior, and normalized version URLs.

Estimated code review effort: 4 (Complex) | ~40 minutes

Sequence Diagram(s)

sequenceDiagram
  participant NativeCliCommandBuilder
  participant GitHubReleaseAssets
  participant TemporaryFiles
  participant Installer
  NativeCliCommandBuilder->>GitHubReleaseAssets: Download install script and .sha256 sidecar
  GitHubReleaseAssets-->>TemporaryFiles: Store installer files
  NativeCliCommandBuilder->>TemporaryFiles: Verify SHA256 checksum
  NativeCliCommandBuilder->>Installer: Execute verified local script
  Installer-->>NativeCliCommandBuilder: Return exit status
  NativeCliCommandBuilder->>TemporaryFiles: Remove temporary files
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: verifying installer script checksums before Unity Editor installs them.
Description check ✅ Passed The description is directly related to the checksum-verification installer changes and matches the implemented updates.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch security/unity-editor-installer-verify

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.

Set `$ErrorActionPreference = 'Stop'` inside the try block so that any
non-terminating cmdlet error (missing checksum file, unexpected
Get-FileHash result, etc.) throws immediately, instead of relying on a
downstream null dereference to eventually raise an exception. The
existing fail-close paths still work as before, but the intent is now
explicit and no longer coupled to incidental error semantics.
@hatayama
hatayama merged commit bf33af3 into v3-beta Jul 10, 2026
9 checks passed
@hatayama
hatayama deleted the security/unity-editor-installer-verify branch July 10, 2026 01:40
@github-actions github-actions Bot mentioned this pull request Jul 11, 2026
RyanXie123 pushed a commit to RyanXie123/unity-cli-loop that referenced this pull request Sep 22, 2026
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