Skip to content

fix: terminal install works with curl alone by trusting the repository pin - #2081

Merged
hatayama merged 9 commits into
v3-betafrom
fix/issue-2080-curl-only-terminal-install
Jul 30, 2026
Merged

fix: terminal install works with curl alone by trusting the repository pin#2081
hatayama merged 9 commits into
v3-betafrom
fix/issue-2080-curl-only-terminal-install

Conversation

@hatayama

@hatayama hatayama commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Terminal install (curl | sh / irm | iex) now falls back to Packages/src/project-runner-pin.json when ULOOP_ARCHIVE_MANIFEST is unset, so first-time CLI install no longer requires gh + jq.
  • Explicit ULOOP_ARCHIVE_MANIFEST (Unity GUI / dispatcher self-update / manual attestation) still wins; pin fetch is skipped in that case.
  • New env ULOOP_REF (default main) selects the pin ref; pin parsing is fail-closed (escape residues, digest format, duplicates, CR).

Closes #2080

Design

  1. Non-empty ULOOP_ARCHIVE_MANIFEST → use it (no pin fetch).
  2. Empty → fetch pin at raw.githubusercontent.com/$REPOSITORY/$ULOOP_REF/Packages/src/project-runner-pin.json, take dispatcherArchiveManifest + dispatcherReleaseTag.
  3. ULOOP_VERSION of latest / latest-beta (or unset) is replaced by the pin tag; an explicit tag must match the pin or the install fails.
  4. Fetch/parse/validation failure exits with a message that mentions both the pin URL and ULOOP_ARCHIVE_MANIFEST.

Test plan

  • sh scripts/test-install-pin-manifest.sh (exit 0)
  • sh scripts/test-install-archive-manifest.sh (exit 0)
  • sh scripts/test-install-version-format.sh (exit 0)
  • sh scripts/test-install-release-filter.sh (exit 0, including new pin-fallback e2e cases)
  • scripts/check-go-cli.sh (exit 0)
  • Live smoke: ULOOP_REF=v3-beta ULOOP_INSTALL_DIR=$(mktemp -d) sh scripts/install.shUsing dispatcher release dispatcher-v3.1.0-beta.16 pinned at v3-beta, install succeeded, --version printed 3.1.0-beta.16
  • Windows PowerShell steps in CI (scripts/test-install-pin-resolution.ps1 + parse check) — no local pwsh/powershell on this machine
  • Full PR CI green (check-release-triggers, Linux shell tests, Git Bash release-filter, Windows PowerShell)

Review in cubic

hatayama and others added 5 commits July 30, 2026 22:31
…ll.sh

Co-authored-by: Cursor <cursoragent@cursor.com>
…nifest in install.sh

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…f-update

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • scripts/test-install-pin-resolution.ps1 is excluded by none and included by none

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b0c13b4d-740c-4f84-baf1-918d9dd4fb23

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The terminal installer now falls back to repository-pinned dispatcher metadata when no archive manifest is provided. It validates refs, manifests, and versions, adds shell and PowerShell coverage, updates CI execution, and documents the revised trust and installation flows.

Changes

Pinned terminal installation

Layer / File(s) Summary
Installer pin resolution
scripts/install.sh, cli/dispatcher/internal/dispatcher/update.go
The installer fetches and validates repository pin data, resolves the dispatcher manifest before downloads, and documents explicit attestation-manifest handling for updates.
Installer validation coverage
scripts/test-install-pin-manifest.sh, scripts/test-install-release-filter.sh, .github/workflows/build-and-test.yml
Tests cover parsing, escaping, ref validation, pin fallback, precedence, fetch failures, digest mismatches, and version mismatches across shell and Windows PowerShell.
Trust model and installation documentation
README.md, README_ja.md, SECURITY.md, docs/project-runner-pin.md, cli/dispatcher/shared-inputs-stamp.json
Documentation describes repository pin sourcing, manifest precedence, digest enforcement, environment variables, and shared Unity and terminal trust inputs; the shared-input hash is updated.

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

Sequence Diagram(s)

sequenceDiagram
  participant Installer as scripts/install.sh
  participant Repository as raw.githubusercontent.com
  participant Release as GitHub release assets
  Installer->>Repository: Fetch project-runner-pin.json for PIN_REF
  Repository-->>Installer: Return release tag and digest manifest
  Installer->>Installer: Validate pin data and selected version
  Installer->>Release: Download archive and checksum
  Release-->>Installer: Return release files
  Installer->>Installer: Verify checksum and attestation manifest
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: terminal installs now use the repository pin instead of requiring extra tooling.
Description check ✅ Passed The description is directly about the same installer fallback, precedence, and validation work in this PR.
Linked Issues check ✅ Passed The changes cover pin-based fallback, explicit manifest precedence, ref override, validation, docs, tests, and Windows coverage required by #2080.
Out of Scope Changes check ✅ Passed The docs, CI updates, and test additions all support the installer change set and do not look unrelated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-2080-curl-only-terminal-install

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
scripts/test-install-pin-manifest.sh (1)

15-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Guard against a vacuous run when extraction yields nothing.

If a helper is renamed or reformatted (e.g. closing brace indented), extract_function returns empty output, eval succeeds, and every expect_fail then passes for the wrong reason (command not found → non-zero). A presence check keeps the "later refactor cannot silently drift" intent of the header comment.

Proposed hardening
-eval "$(extract_function extract_pin_string_field)"
-eval "$(extract_function unescape_pin_manifest)"
-eval "$(extract_function validate_pin_manifest)"
-eval "$(extract_function validate_uloop_ref)"
+for fn in extract_pin_string_field unescape_pin_manifest validate_pin_manifest validate_uloop_ref; do
+  body=$(extract_function "$fn")
+  if [ -z "$body" ]; then
+    echo "FAIL: could not extract $fn from $INSTALL_SCRIPT" >&2
+    exit 1
+  fi
+  eval "$body"
+done

Also applies to: 42-45

🤖 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 `@scripts/test-install-pin-manifest.sh` around lines 15 - 22, Update
extract_function to validate that the requested helper was actually found and
extracted, including when formatting changes prevent the current awk match from
locating it. Make the test fail explicitly on empty extraction before eval or
expect_fail runs, preserving the intent that renamed or reformatted helpers
cannot make the suite pass vacuously.

Source: Linters/SAST tools

scripts/install.sh (1)

385-400: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

extract_pin_string_field takes the key as $1 but reads the JSON from the global pin_json.

Mixed parameter/global contract is easy to break later (a caller that forgets to set pin_json silently gets an empty parse and the "missing field" error path). Passing both explicitly keeps it symmetric with unescape_pin_manifest/validate_pin_manifest.

Note the test harness (scripts/test-install-pin-manifest.sh) also sets pin_json as a global, so any change must be mirrored there.

🤖 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 `@scripts/install.sh` around lines 385 - 400, Update extract_pin_string_field
to accept the JSON input explicitly alongside the field key, and parse that
argument instead of the global pin_json. Update every caller to pass both
values, including the test harness scripts/test-install-pin-manifest.sh, while
preserving the existing missing-field and malformed-value behavior.
🤖 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 `@README.md`:
- Line 115: Change the manual attestation-install subsection heading from h4 to
h3 in README.md lines 115-115 and README_ja.md lines 132-132, preserving the
existing heading text while maintaining the correct hierarchy under the
surrounding h2 section.

In `@scripts/install.sh`:
- Around line 466-475: Update the VERSION selection logic around the
latest/latest-beta branch so an explicit ULOOP_VERSION=latest-beta request is
not silently treated as the pinned stable release. Either require ULOOP_REF or
ULOOP_ARCHIVE_MANIFEST for the beta channel, or emit a clear channel-override
message when assigning VERSION=$pin_tag; preserve the existing latest and exact
pin_tag behavior.

---

Nitpick comments:
In `@scripts/install.sh`:
- Around line 385-400: Update extract_pin_string_field to accept the JSON input
explicitly alongside the field key, and parse that argument instead of the
global pin_json. Update every caller to pass both values, including the test
harness scripts/test-install-pin-manifest.sh, while preserving the existing
missing-field and malformed-value behavior.

In `@scripts/test-install-pin-manifest.sh`:
- Around line 15-22: Update extract_function to validate that the requested
helper was actually found and extracted, including when formatting changes
prevent the current awk match from locating it. Make the test fail explicitly on
empty extraction before eval or expect_fail runs, preserving the intent that
renamed or reformatted helpers cannot make the suite pass vacuously.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5a504f7b-8308-421f-85c9-ec8245a25650

📥 Commits

Reviewing files that changed from the base of the PR and between 84f83b1 and 3e538ad.

⛔ Files ignored due to path filters (2)
  • scripts/install.ps1 is excluded by none and included by none
  • scripts/test-install-pin-resolution.ps1 is excluded by none and included by none
📒 Files selected for processing (10)
  • .github/workflows/build-and-test.yml
  • README.md
  • README_ja.md
  • SECURITY.md
  • cli/dispatcher/internal/dispatcher/update.go
  • cli/dispatcher/shared-inputs-stamp.json
  • docs/project-runner-pin.md
  • scripts/install.sh
  • scripts/test-install-pin-manifest.sh
  • scripts/test-install-release-filter.sh

Comment thread README.md Outdated
Comment thread scripts/install.sh
hatayama and others added 2 commits July 30, 2026 22:59
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
hatayama and others added 2 commits July 30, 2026 23:05
Co-authored-by: Cursor <cursoragent@cursor.com>
…ution

Co-authored-by: Cursor <cursoragent@cursor.com>
@hatayama
hatayama merged commit 58ec443 into v3-beta Jul 30, 2026
12 checks passed
@hatayama
hatayama deleted the fix/issue-2080-curl-only-terminal-install branch July 30, 2026 14:25
@github-actions github-actions Bot mentioned this pull request Jul 30, 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.

2 participants