Skip to content
Draft
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
30 changes: 30 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,33 @@ jobs:
version: pnpm run changeset:version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

deploy-installer:
name: Deploy Installer
needs: verify
if: github.repository == 'wevm/incur' && vars.INCUR_INSTALLER_DEPLOY_ENABLED == 'true'
permissions:
contents: read
runs-on: ubuntu-latest
timeout-minutes: 5
environment:
name: incur.app
url: https://incur.app

steps:
- name: Clone repository
uses: actions/checkout@v4

- name: Install dependencies
uses: ./.github/actions/install-dependencies

- name: Deploy installer Worker
run: pnpm --filter @incur/installer deploy
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

- name: Smoke-test installer Worker
run: pnpm --filter @incur/installer smoke
env:
INCUR_INSTALLER_SMOKE_REPOSITORY: ${{ vars.INCUR_INSTALLER_SMOKE_REPOSITORY }}
19 changes: 18 additions & 1 deletion .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,26 @@ jobs:
uses: ./.github/actions/install-dependencies

- name: Run tests
run: pnpm run test --bail=1 --coverage
run: pnpm run test --bail=1 --coverage --project core
env:
CI: true

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4

installer:
name: Installer Worker
runs-on: ubuntu-latest

steps:
- name: Clone repository
uses: actions/checkout@v4

- name: Install dependencies
uses: ./.github/actions/install-dependencies

- name: Test installer Worker
run: pnpm run test --run --bail=1 --project installer

- name: Build installer Worker
run: pnpm --filter @incur/installer exec wrangler deploy --dry-run --strict --outdir dist
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
coverage
dist
node_modules
.wrangler
clac.generated.ts
tasks
*.tsbuildinfo
*.tsbuildinfo
/installer/worker-configuration.d.ts
2 changes: 1 addition & 1 deletion .oxfmtrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"trailingComma": "all",
"tabWidth": 2,
"printWidth": 100,
"ignorePatterns": ["package.json"],
"ignorePatterns": ["package.json", "installer/worker-configuration.d.ts"],
"experimentalSortImports": {
"groups": [
["value-builtin", "value-external", "type-import", "value-internal", "type-internal"],
Expand Down
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -884,12 +884,38 @@ jobs:
uses: wevm/incur/release@v1
```

After the release is published, users can install without a package manager:
After the release is published and the `incur.app` service is enabled, users
can install without a package manager:

```sh
curl -fsSL https://github.com/example/my-cli/releases/latest/download/install.sh | sh
curl -fsSL https://incur.app/example/my-cli | bash
```

```powershell
irm https://incur.app/example/my-cli/install.ps1 | iex
```

Append a stable version to select its exact `v<version>` release:

```sh
curl -fsSL https://incur.app/example/my-cli@1.2.3 | bash
```

```powershell
irm https://incur.app/example/my-cli@1.2.3/install.ps1 | iex
```

The `@1.2.3` shorthand targets the conventional tag `v1.2.3`. Use the direct
GitHub release URL when a repository uses another tag format.

`incur.app` is an open convenience redirect to the named repository's latest or
exact installer asset. It does not verify that a repository uses Incur or
endorse its contents.

The direct GitHub URLs remain available when you want to inspect the source or
avoid the shortcut. The [standalone binary guide](./docs/binaries.md) explains
the trust boundary and download-inspect-execute alternatives.

Connect those assets to a public GitHub repository:

```ts
Expand Down
102 changes: 90 additions & 12 deletions docs/binaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,35 +101,113 @@ installer contains the exact release tag. A latest-release URL selects only the
installer. The installer downloads its executable and `SHA256SUMS` from the
tagged release.

After the release action appends the assets, users can install the latest stable
release:
After the release action appends the assets and the `incur.app` service is
enabled, users can install the latest stable release through the short URLs:

```sh
curl -fsSL https://github.com/wevm/frog/releases/latest/download/install.sh | sh
curl -fsSL https://incur.app/wevm/frog | bash
```

```powershell
irm https://incur.app/wevm/frog/install.ps1 | iex
```

For a repository whose release uses the conventional `v<version>` tag, append
an unprefixed stable semantic version to install that exact release:

```sh
curl -fsSL https://incur.app/example/my-cli@1.2.3 | bash
```

```powershell
irm https://incur.app/example/my-cli@1.2.3/install.ps1 | iex
```

The exact-version route accepts only `x.y.z`. Do not include the tag's `v`
prefix. It maps directly to `v<version>` and does not search releases by package
version. Prerelease versions, build metadata, and ranges are not supported.

`incur.app` returns a temporary redirect to the named repository's fixed
`install.sh` or `install.ps1` asset. A bare repository selects GitHub's latest
release; `@1.2.3` selects the exact `v1.2.3` release. The service does not proxy
or inspect the script.

When a repository uses another tag format, use that exact GitHub tag directly.
For example, the `frog@1.2.3` tag uses:

```sh
curl -fsSL https://github.com/wevm/frog/releases/download/frog@1.2.3/install.sh | bash
```

```powershell
irm https://github.com/wevm/frog/releases/download/frog@1.2.3/install.ps1 | iex
```

The redirect is open to any syntactically valid GitHub repository path. Incur
does not verify that the repository uses Incur, certify its publisher, or
endorse its contents.

Use the direct GitHub URLs if the shortcut is unavailable:

```sh
curl -fsSL https://github.com/wevm/frog/releases/latest/download/install.sh | bash
```

```powershell
irm https://github.com/wevm/frog/releases/latest/download/install.ps1 | iex
```

Use an exact tag URL if you do not want a newer release:
The equivalent direct exact-tag URLs are:

```sh
curl -fsSL https://github.com/wevm/frog/releases/download/v1.2.3/install.sh | sh
curl -fsSL https://github.com/example/my-cli/releases/download/v1.2.3/install.sh | bash
```

A repository owner can replace a tag, its assets, and its checksum file
together. Enable
```powershell
irm https://github.com/example/my-cli/releases/download/v1.2.3/install.ps1 | iex
```

An exact-version alias pins the tag name, not immutable bytes. A repository
owner can replace a tag, its assets, and its checksum file together. Enable
[GitHub immutable releases](https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases)
to prevent changes after publication. Without this setting, the checksum
verifies only the current release asset. It does not prove that the asset never
changed.

A project URL can make the install command shorter. For example, redirect
`https://frog.dev/install.sh` to
`https://github.com/wevm/frog/releases/latest/download/install.sh`. The
installer still uses its embedded tag for all later downloads. GitHub documents
the stable
Both latest and exact-version URLs select an installer script. That script is
not covered by `SHA256SUMS` before execution. The generated installer uses its
embedded exact tag and verifies the binary archive that it downloads afterward.

Download and inspect the shell installer before execution when the repository
or release is not already trusted:

```sh
(
installer="$(mktemp)"
trap 'rm -f "$installer"' EXIT
curl -fsSL https://incur.app/wevm/frog -o "$installer" &&
less "$installer" &&
bash "$installer"
)
```

Use the equivalent PowerShell flow on Windows:

```powershell
$installer = Join-Path ([IO.Path]::GetTempPath()) "frog-install-$([guid]::NewGuid()).ps1"
try {
irm https://incur.app/wevm/frog/install.ps1 -OutFile $installer -ErrorAction Stop
Get-Content $installer
& $installer
} finally {
Remove-Item $installer -ErrorAction SilentlyContinue
}
```

Do not use a piped installer command as a CI success check. A pipeline can hide
the downloader's failure status, and it executes network content before review.

GitHub documents the stable
[`/releases/latest/download/<asset>` URL](https://docs.github.com/en/repositories/releasing-projects-on-github/linking-to-releases).

The Unix installer supports macOS and Linux with glibc or musl. It supports
Expand Down
14 changes: 14 additions & 0 deletions installer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Installer Redirect

| URL | Redirect |
| ------------------------------------------------------ | -------------------------------------------------------------------------- |
| `https://incur.app/<org>/<repo>` | `https://github.com/<org>/<repo>/releases/latest/download/install.sh` |
| `https://incur.app/<org>/<repo>/install.ps1` | `https://github.com/<org>/<repo>/releases/latest/download/install.ps1` |
| `https://incur.app/<org>/<repo>@<version>` | `https://github.com/<org>/<repo>/releases/download/v<version>/install.sh` |
| `https://incur.app/<org>/<repo>@<version>/install.ps1` | `https://github.com/<org>/<repo>/releases/download/v<version>/install.ps1` |

## Development

```sh
pnpm dev
```
22 changes: 22 additions & 0 deletions installer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@incur/installer",
"private": true,
"type": "module",
"scripts": {
"check:types": "pnpm gen:types && tsc --noEmit",
"deploy": "wrangler deploy --strict",
"dev": "wrangler dev",
"gen:types": "wrangler types worker-configuration.d.ts",
"smoke": "node --import tsx scripts/smoke.ts"
},
"devDependencies": {
"@cloudflare/vitest-pool-workers": "0.19.0",
"@types/node": "25.5.0",
"@vitest/coverage-v8": "4.1.10",
"tsx": "4.21.0",
"typescript": "5.9.3",
"vite": "7.3.5",
"vitest": "4.1.10",
"wrangler": "4.115.0"
}
}
Loading
Loading