{"id":50561817,"url":"https://github.com/simtabi/get-installer","last_synced_at":"2026-06-04T12:01:09.400Z","repository":{"id":357949072,"uuid":"1239241912","full_name":"simtabi/get-installer","owner":"simtabi","description":"Registry-driven curl-pipe-sh installer for OSS, enterprise, and domain-locked dev-tool distribution.","archived":false,"fork":false,"pushed_at":"2026-05-14T23:52:11.000Z","size":159,"stargazers_count":0,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T01:38:34.316Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://opensource.simtabi.com/products/get-installer","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simtabi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-14T22:46:38.000Z","updated_at":"2026-05-14T23:52:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/simtabi/get-installer","commit_stats":null,"previous_names":["simtabi/get-installer"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/simtabi/get-installer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simtabi%2Fget-installer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simtabi%2Fget-installer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simtabi%2Fget-installer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simtabi%2Fget-installer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simtabi","download_url":"https://codeload.github.com/simtabi/get-installer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simtabi%2Fget-installer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33903134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-04T12:01:08.351Z","updated_at":"2026-06-04T12:01:09.393Z","avatar_url":"https://github.com/simtabi.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# get-installer\n\n[![CI](https://github.com/simtabi/get-installer/actions/workflows/ci.yml/badge.svg)](https://github.com/simtabi/get-installer/actions/workflows/ci.yml)\n[![PyPI](https://img.shields.io/pypi/v/get-installer.svg)](https://pypi.org/project/get-installer/)\n[![Python](https://img.shields.io/pypi/pyversions/get-installer.svg)](https://pypi.org/project/get-installer/)\n[![License](https://img.shields.io/github/license/simtabi/get-installer.svg)](LICENSE)\n\nA reusable, **registry-driven `curl | sh`-style installer** for\ndistributing developer tools across public OSS, private enterprises,\nuniversities, and government / domain-locked contexts.\n\n\u003e Pronounced \"get installer\": same words as the URL `get.simtabi.com`.\n\u003e The technique is also called **one-line installer**, **bootstrap installer**,\n\u003e or **distribution channel** (see [`SPEC.md` §0](SPEC.md#0--project-identity-locked)).\n\n```bash\n# POSIX (macOS / Linux / WSL / Git-Bash)\nsh -c \"$(curl -fsSL https://get.simtabi.com/install.sh)\" -- --product claude-configurator\n\n# PowerShell (Windows)\nirm https://get.simtabi.com/install.ps1 | iex\n```\n\n---\n\n## Table of contents\n\n- [Why this exists](#why-this-exists)\n- [Quick start](#quick-start)\n- [What ships in the box](#what-ships-in-the-box)\n- [URL layout at `get.simtabi.com`](#url-layout-at-getsimtabicom)\n- [Project layout](#project-layout)\n- [Security posture](#security-posture)\n- [Documentation](#documentation)\n- [Run from source](#run-from-source)\n- [Tests](#tests)\n- [Roadmap](#roadmap)\n- [License](#license)\n\n---\n\n## Why this exists\n\nDistributing developer tools is a solved problem **only when the tool is\nalready on PyPI / Homebrew / apt / a package store**. For everything\nelse (fresh-machine bootstrap, mixed-OS install, on-prem enterprise\ncatalogues, university course toolkits, government-domain-locked\nsoftware) the de-facto pattern is `curl | sh`, hand-rolled per project.\n\nThis project gives you that pattern **once**, hardened and reusable:\n\n- **One Python core** that drives every install.\n- **JSON registry** (with optional REST-API source) declares products,\n  versions, install methods, prompts, post-install steps.\n- **Thin shell launchers** for the one-liner UX (`install.sh`,\n  `install.ps1`).\n- **Drop-in vendoring**: copy this folder + edit `registry.json` +\n  publish. Done.\n- **Hardened by default**: refuses root, HTTPS-only, origin allowlist,\n  rate-limited, journaled rollback on signal/error, 0600 modes on\n  every artefact.\n\nReference implementations this borrows patterns from: `rustup` (the\ngold-standard one-liner), `Homebrew` (prompt-before-privileged-step),\n`Docker get.docker.com` (distribution-aware), `uv` install (Python\nbootstrap fallback), `k3s` (service installer).\n\n## Quick start\n\n```bash\nget-installer --list                                # see what's available\nget-installer --product claude-configurator         # install latest default version\nget-installer --product claude-configurator --version 0.2.0 --yes\nget-installer --product claude-configurator --dry-run\n```\n\nWhen used via the one-liner, the bootstrap script downloads the\nPython core into a 0700-mode temp dir, verifies its SHA256 (when\npinned), and hands off to Python. Body bytes flow URL → disk; no\nshell-eval of fetched content.\n\n## What ships in the box\n\n| Capability | Provider |\n|---|---|\n| Multi-product registry (schema v2) | `registry.json` + `schemas/registry.schema.json` |\n| Per-version `status` enforcement (`current` / `deprecated` / `unsupported` / `yanked`) | `src/get_installer/config.py:Registry.resolve` |\n| 7-phase install flow with TTY output | `src/get_installer/installer.py:Installer.run` |\n| Garbage collector / rollback | `src/get_installer/journal.py:Journal` |\n| HTTPS-only origin-allowlisted fetches | `src/get_installer/verify.py:fetch_https` |\n| Rate-limit + DDoS protection | `src/get_installer/verify.py:fetch_https` |\n| Refuse-root + PATH-injection guard | `src/get_installer/verify.py` |\n| Optional `uv python install` bootstrap | `src/get_installer/python_setup.py` |\n| POSIX + PowerShell launchers | `bootstrap/install.{sh,ps1}` |\n| 43-case pytest suite | `tests/` |\n\n## URL layout at `get.simtabi.com`\n\n```\nhttps://get.simtabi.com/\n├── install.sh                         POSIX bootstrap\n├── install.ps1                        PowerShell bootstrap\n├── installer.py                       Python core (single-file bundle)\n├── installer.py.sha256                SHA256 of installer.py\n├── registry.json                      Static fallback registry\n├── api/v1/registry.json               Dynamic (DB-backed) registry\n├── api/v1/products                    List products\n├── api/v1/products/\u003cproduct\u003e/versions GET versions\n├── \u003cproduct\u003e/install.sh               Convenience alias (sets --product)\n├── \u003cproduct\u003e/\u003cversion\u003e/install.sh     Version-pinned alias\n└── orgs/\u003corg\u003e/...                     Multi-tenant subtrees (token-gated)\n```\n\nCustomer-mirror domains follow the same path layout, e.g.\n`https://get.\u003ccustomer\u003e.com/install.sh` resolves locally.\n\nFull URL contract in [`SPEC.md` §2](SPEC.md#2--url-layout-at-getsimtabicom).\n\n## Project layout\n\n```\nget-installer/\n├── README.md                          you are here\n├── SPEC.md                            design spec + standing agent prompt\n├── LICENSE                            MIT\n├── CHANGELOG.md\n├── pyproject.toml\n├── registry.json                      this project's registry (also dev fallback)\n├── bootstrap/                         OS-specific launchers\n│   ├── install.sh                     POSIX (sh-compatible)\n│   └── install.ps1                    PowerShell 5+\n├── src/\n│   └── get_installer/                 the Python package (stdlib only)\n│       ├── __init__.py\n│       ├── __main__.py                CLI entry\n│       ├── config.py                  Registry + version resolution\n│       ├── installer.py               7-phase flow\n│       ├── journal.py                 GC / rollback\n│       ├── ui.py                      prompts + colour\n│       ├── verify.py                  HTTPS + sha256 + rate limits + refuse-root\n│       └── python_setup.py            --with-python via uv\n├── schemas/\n│   └── registry.schema.json           JSON Schema (authoritative)\n├── tests/                             pytest suite\n└── docs/\n    ├── config-schema.md\n    ├── security.md\n    └── vendoring.md\n```\n\n## Security posture\n\nThe full threat model lives in [`docs/security.md`](docs/security.md).\nHeadline guarantees:\n\n- **HTTPS-only** for every Python-side download. Refuses URLs outside\n  the `access_control.allowed_origins` allowlist.\n- **TOCTOU-safe writes**: `O_CREAT | O_EXCL` + 0600 mode on every\n  installer-owned file.\n- **Rate-limited**: bounded retries, exponential backoff with jitter,\n  HTTP 429 Retry-After respect, wall-clock deadline.\n- **Refuse-root by default**: no installer is allowed to silently\n  elevate; `--allow-root` is the explicit override.\n- **Yanked-status hard-stop**: registry can declare a version `yanked`;\n  the installer refuses to proceed unconditionally.\n- **Journal + rollback**: every state-changing step records an undo\n  callback. Signal (SIGINT / SIGTERM) or unhandled exception triggers\n  reverse-order rollback.\n- **Per-product access controls** (Phase E foundation): registry can\n  declare `access.auth` (bearer-token, with custom env var + hint\n  URL) and `access.signed` (HMAC-SHA256 pre-signed URLs with local\n  expiry verification). Wired end-to-end through CLI, schema,\n  resolver, and the validate phase.\n\nPending hardening: SHA256-pinned bootstrap, sigstore signatures,\nreproducible bundle output, full org-scoped tenancy. See\n[`docs/SPEC.md` §4 Phase F + Phase H](docs/SPEC.md#phase-f--signed-releases)\nand [`docs/security.md`](docs/security.md) for the full threat model.\n\n## Documentation\n\n| Doc | Covers |\n|---|---|\n| [`docs/SPEC.md`](docs/SPEC.md) | **The spec + standing agent prompt.** Read this first if you're contributing. |\n| [`docs/config-schema.md`](docs/config-schema.md) | Registry shape: products, versions, prompts, post-install, rate limits, access control. |\n| [`docs/security.md`](docs/security.md) | Threat model + mitigations. |\n| [`docs/vendoring.md`](docs/vendoring.md) | How to drop this folder into another project. |\n| [`docs/distribution/homebrew.md`](docs/distribution/homebrew.md) | Homebrew tap as a complementary distribution channel. |\n| [`docs/distribution/docker.md`](docs/distribution/docker.md) | Docker image build + the PUID/PGID convention that fixes Linux volume-permission issues. |\n\n## Run from source\n\n```bash\ngit clone https://github.com/simtabi/get-installer\ncd get-installer\npip install -e \".[dev]\"\n\nget-installer --list\nget-installer --product claude-configurator --dry-run --yes\n```\n\n## Tests\n\n```bash\npytest -q                              # 43 cases\nruff check src tests\nmypy src/get_installer\n```\n\n## Roadmap\n\nPhase-by-phase plan lives in [`SPEC.md` §4](SPEC.md#4--required-features-by-phase).\nHeadline phases:\n\n| Phase | Topic | State |\n|---|---|---|\n| A | Hosting + URL contracts at `get.simtabi.com` | pending |\n| B | Single-file `installer.py` bundle script | pending |\n| C | Remote API registry source (DB-backed) | pending |\n| D | Forge-aware metadata (PyPI / git / tarball / binary) | pending |\n| E | Multi-tenant + domain-locked installs | pending |\n| F | Signed releases (sigstore / minisign) | pending |\n| G | Web admin UI (separate sibling repo) | out of scope here |\n| H | Hardening + audit + reproducible bundle | pending |\n| I | Catalogue mode (git package distribution) | pending |\n\n## License\n\nMIT. See [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimtabi%2Fget-installer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimtabi%2Fget-installer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimtabi%2Fget-installer/lists"}