Skip to content

feat(bashinst): define spec for bash installer - #621

Merged
twitchyliquid64 merged 1 commit into
mainfrom
tom/installer
Jul 3, 2026
Merged

feat(bashinst): define spec for bash installer#621
twitchyliquid64 merged 1 commit into
mainfrom
tom/installer

Conversation

@twitchyliquid64

@twitchyliquid64 twitchyliquid64 commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Documentation
    • Added a new POSIX sh installer specification for a “curl … | sh” fallback flow.
    • Covers runtime platform detection, stable version resolution, manifest parsing/filtering, TLS 1.2 + SHA-256 verification, and atomic install behavior.
    • Specifies safe destination handling (XDG paths), install-state tracking, and PATH guidance.
    • Includes security considerations, non-goals, and verification/portability expectations (e.g., POSIX awk, cleanup behavior).

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a new specification document for a POSIX sh fallback installer. It defines runtime tool detection, target and manifest resolution, manifest parsing, destination handling, download and verification flow, and verification expectations.

Changes

Installer Specification

Layer / File(s) Summary
Introduction and goals
docs/specs/07-spec-installer/07-spec-installer.md
Introduces the spec, frames the installer as a POSIX-sh fallback, and defines goals and user stories for fresh installs, reruns, and target selection.
Installer workflow units
docs/specs/07-spec-installer/07-spec-installer.md
Specifies runtime probing, target/version/manifest resolution, manifest parsing, destination path resolution, download and verification behavior, and post-install record writing plus PATH advisory.
Non-goals and design rationale
docs/specs/07-spec-installer/07-spec-installer.md
Lists non-goals and documents rationale for POSIX sh compatibility, manifest format, and script standards.
Technical, security, and verification considerations
docs/specs/07-spec-installer/07-spec-installer.md
Covers portability and cache technical considerations, HTTPS+SHA-256 trust model, input validation, and verification via shellcheck, dash conformance, and unit/end-to-end tests.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

A rabbit found a sh-script trail,
With hashes checked and downloadsייל?
No—turtles? no, just hop and sing,
Specs now hum in tidy spring.
🐇📜

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: adding an installer specification, and the bash/curl fallback wording is close enough to the POSIX sh installer focus.
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.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@docs/specs/07-spec-installer/07-spec-installer.md`:
- Around line 42-46: Update the installer portability contract in the spec to
list every runtime dependency the script actually uses. In the section that
describes the POSIX sh installer, revise the dependency list to include mktemp
and dirname, or explicitly document a fallback path if either is unavailable, so
the claims in the installer spec stay consistent with the tools referenced later
in the document.
- Around line 91-94: Make the architecture naming canonical across the installer
spec and examples. Update the manifest example and the field-matching rules that
still reference x86_64 so they use the same normalized arch value as R1.3, and
ensure the parser/spec logic in the installer sections matches on amd64 rather
than mixing aliases. Reference the R1.3 host-platform normalization rules and
the manifest matching rules in the spec so Linux x86_64 entries resolve
correctly end-to-end.
- Around line 202-218: The skip logic for installed components currently treats
a hash match as sufficient, which can leave `bin` artifacts non-executable on
reruns. Update the installer behavior in the component handling path so the
“already installed” check also verifies the executable mode for `bin`
destinations, or repairs the mode before skipping. Use the existing install flow
around the `R5.1`/`R5.4` behavior and the `bin` prefix token handling to locate
the logic, and ensure a hash-matching binary is not left in a broken state.
- Around line 131-135: The manifest example fence is missing a language tag,
which triggers markdownlint. Update the fenced code block in the installer spec
example to use a text-friendly language tag such as text or sh, keeping the
existing manifest content unchanged and preserving the formatting around the
example table.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5ee287a9-c952-4eb0-8681-e7507c3ff52c

📥 Commits

Reviewing files that changed from the base of the PR and between fb618f9 and 0db1220.

📒 Files selected for processing (1)
  • docs/specs/07-spec-installer/07-spec-installer.md

Comment thread docs/specs/07-spec-installer/07-spec-installer.md
Comment on lines +91 to +94
**R1.3** — The host platform is derived from `uname -s` (→ `linux`/`darwin`) and
`uname -m`, with arch normalized so the same CPU has one name across platforms:
`amd64|x86_64 → amd64`, `arm64|aarch64 → arm64`. An unrecognized OS or arch
exits with a clear error.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make the arch names canonical end-to-end.

R1.3 normalizes x86_64/amd64 to amd64, but the manifest example and field-matching rules still use x86_64. As written, Linux x86_64 rows will never match unless the manifest and parser agree on one canonical arch name.

Proposed fix
- minimald     linux   x86_64   1.4.2    3a7b…    file    bin/minimald      minimald/1.4.2/minimald-linux-x86_64
+ minimald     linux   amd64    1.4.2    3a7b…    file    bin/minimald      minimald/1.4.2/minimald-linux-amd64

Also applies to: 131-145

🤖 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 `@docs/specs/07-spec-installer/07-spec-installer.md` around lines 91 - 94, Make
the architecture naming canonical across the installer spec and examples. Update
the manifest example and the field-matching rules that still reference x86_64 so
they use the same normalized arch value as R1.3, and ensure the parser/spec
logic in the installer sections matches on amd64 rather than mixing aliases.
Reference the R1.3 host-platform normalization rules and the manifest matching
rules in the spec so Linux x86_64 entries resolve correctly end-to-end.

Comment on lines +131 to +135
```
# component os arch version sha256 kind dest src
minimald linux x86_64 1.4.2 3a7b… file bin/minimald minimald/1.4.2/minimald-linux-x86_64
minimald darwin arm64 1.4.2 2c26… file bin/minimald minimald/1.4.2/minimald-darwin-arm64
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language tag to the manifest example fence.

Markdownlint flags this fence, so text (or sh) will keep the spec lint-clean.

Proposed fix
- ```
+ ```text
📝 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
```
# component os arch version sha256 kind dest src
minimald linux x86_64 1.4.2 3a7b… file bin/minimald minimald/1.4.2/minimald-linux-x86_64
minimald darwin arm64 1.4.2 2c26… file bin/minimald minimald/1.4.2/minimald-darwin-arm64
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 131-131: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 `@docs/specs/07-spec-installer/07-spec-installer.md` around lines 131 - 135,
The manifest example fence is missing a language tag, which triggers
markdownlint. Update the fenced code block in the installer spec example to use
a text-friendly language tag such as text or sh, keeping the existing manifest
content unchanged and preserving the formatting around the example table.

Source: Linters/SAST tools

Comment on lines +202 to +218
**R5.1** — For each applicable component, if the resolved destination file
already exists **and** its on-disk SHA-256 equals the manifest `sha256`, the
component is skipped with no download. The on-disk file — not any recorded
state — is the source of truth for "already installed".

**R5.2** — Otherwise the artifact is downloaded from `<BUCKET>/<src>` to a
temp sibling **in the destination directory** (`<dest>.tmp.$$`), so the final
rename is same-filesystem and atomic.

**R5.3** — The downloaded temp file's SHA-256 is compared to the manifest
`sha256`; on mismatch the temp file is removed and the run exits non-zero
naming the component. The partially-written file is never installed.

**R5.4** — For files installed to a prefix token of `bin`, the temp file is
`chmod +x`ed **before** the rename, so it appears already-executable at its
final path. The install is completed with `mv -f <dest>.tmp.$$ <dest>`
(atomic within one filesystem).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Don’t skip executable-bit repair on matching binaries.

A bin file can hash-match yet still be non-executable, so reruns would silently leave a broken install in place. Make the skip condition include mode, or normalize the existing file before continuing.

Proposed fix
- if [ -f "$target" ] && [ "$(sha256 "$target")" = "$want" ]; then
-   continue                                   # up to date, no download
- fi
+ if [ -f "$target" ] && [ "$(sha256 "$target")" = "$want" ]; then
+   if [ "$kind" != bin ] || [ -x "$target" ]; then
+     continue                                   # up to date, no download
+   fi
+ fi
🤖 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 `@docs/specs/07-spec-installer/07-spec-installer.md` around lines 202 - 218,
The skip logic for installed components currently treats a hash match as
sufficient, which can leave `bin` artifacts non-executable on reruns. Update the
installer behavior in the component handling path so the “already installed”
check also verifies the executable mode for `bin` destinations, or repairs the
mode before skipping. Use the existing install flow around the `R5.1`/`R5.4`
behavior and the `bin` prefix token handling to locate the logic, and ensure a
hash-matching binary is not left in a broken state.

maximally portable and make as few assumptions about the host as possible.

Distribution artifacts are published to a public GCS bucket. Mutable pointer
files at the bucket root (`stable`, `nightly`, …) each contain a single version

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

do we want to use nightly vs the stable/main, next and unstable we are using for pkgs?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Down for whatever, happy to do unstable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if you wouldn't mind, I think that will create less confusion. "next" in pkgs is for short-lived review cycle we can forego for this one.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@docs/specs/07-spec-installer/07-spec-installer.md`:
- Around line 76-85: The wget path currently does not actually enforce the
no-downgrade guarantee claimed in the installer spec. Update the `R1.1`
downloader selection text and the `wget` wrapper so it either validates
redirects explicitly before downloading or removes the no-downgrade claim from
the wget case; keep the `curl` and `wget` behavior descriptions aligned with
what `curl --proto-redir` and `wget --https-only` באמת guarantee.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72a9b9db-bd18-48f3-8293-7830df5323d7

📥 Commits

Reviewing files that changed from the base of the PR and between 0db1220 and 551518b.

📒 Files selected for processing (1)
  • docs/specs/07-spec-installer/07-spec-installer.md

Comment on lines +76 to +85
**R1.1** — The script selects a downloader at runtime: prefer `curl`, else
`wget`, else exit with a clear error. Both wrappers enforce HTTPS and a TLS 1.2
floor and refuse redirect downgrades:

```sh
# curl
curl --proto '=https' --proto-redir '=https' --tlsv1.2 -fsSL "$url" -o "$out"
# wget
wget --https-only --secure-protocol=TLSv1_2 -qO "$out" "$url"
```

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:

#!/bin/bash
set -euo pipefail

# Inspect the spec around the cited lines.
sed -n '60,100p' docs/specs/07-spec-installer/07-spec-installer.md

# Search for any other mentions of wget/curl redirect handling in this spec.
rg -n "wget|curl|https-only|proto-redir|TLSv1_2|redirect" docs/specs/07-spec-installer/07-spec-installer.md

Repository: gominimal/minimal

Length of output: 2966


🌐 Web query:

GNU Wget manual --https-only recursive mode redirect downgrade protection

💡 Result:

In GNU Wget, the --https-only option is designed to restrict recursive downloads to HTTPS links only [1][2]. When this option is enabled, Wget will only follow links that use the HTTPS protocol during recursive retrieval [1][3]. Regarding redirect downgrade protection: The --https-only option specifically limits the links Wget follows recursively, but it does not inherently guarantee that Wget will abort or reject a redirect from an HTTPS URL to an HTTP URL if that redirection occurs for a request already in progress. While --https-only ensures that discovered links are HTTPS, it is primarily a filter for the recursion engine rather than a protocol-level enforcement mechanism for redirects [1][2]. If strict protection against protocol downgrades is required, relying solely on --https-only may be insufficient if a server issues a 3xx redirect from HTTPS to HTTP. Users seeking to prevent such behavior should be aware that Wget will typically follow redirects automatically (up to the --max-redirect limit) [4][5]. There is no native flag in the standard GNU Wget manual that explicitly disables "HTTPS to HTTP" redirects while allowing "HTTPS to HTTPS" redirects for a single request sequence. {https://www.gnu.org/software/wget/manual/html_node/HTTPS-_0028SSL_002fTLS_0029-Options.html, 1}, {https://www.gnu.org/software/wget/manual/html_node/HTTP-Options.html, 6}

Citations:


Wget path doesn't satisfy the no-downgrade claim. --https-only only filters recursive link following, so this single-file installer fetch can still accept an HTTPS→HTTP redirect. Add explicit redirect validation for the wget path or limit the claim to the curl wrapper.

🤖 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 `@docs/specs/07-spec-installer/07-spec-installer.md` around lines 76 - 85, The
wget path currently does not actually enforce the no-downgrade guarantee claimed
in the installer spec. Update the `R1.1` downloader selection text and the
`wget` wrapper so it either validates redirects explicitly before downloading or
removes the no-downgrade claim from the wget case; keep the `curl` and `wget`
behavior descriptions aligned with what `curl --proto-redir` and `wget
--https-only` באמת guarantee.

@msample msample left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice work.

@twitchyliquid64
twitchyliquid64 merged commit ee58089 into main Jul 3, 2026
92 checks passed
@twitchyliquid64
twitchyliquid64 deleted the tom/installer branch July 3, 2026 00:18
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