5 Commits

28 changed files with 191 additions and 199 deletions

View File

@@ -1,11 +1,11 @@
---
name: add_installer
description: Add a new installer script to the bootstrap CLI project. Use this skill whenever the user asks to create a new installer, add a new tool/package to bootstrap, or register a new `b <name>` command.
name: add_tool
description: Add a new tool definition script to the bootstrap CLI project. Use this skill whenever the user asks to create a new tool, add a new tool/package to bootstrap, or register a new `b <name>` command.
---
# Add a New Installer to Bootstrap CLI
# Add a New Tool to Bootstrap CLI
This skill provides everything needed to add a new installer to the bootstrap project without reading the entire codebase.
This skill provides everything needed to add a new tool to the bootstrap project without reading the entire codebase.
## Project Overview
@@ -15,15 +15,15 @@ Bootstrap CLI (`b`) is a bash-based tool installer and system bootstrapper. User
```
bootstrap/
├── installers/ # Individual installer scripts (install_<name>.sh)
├── lib/ # Shared libraries and router sourced by all installers
├── tools/ # Individual tool directories (tools/<name>/tool.sh)
├── lib/ # Shared libraries and router sourced by all tools
│ ├── common.sh # Logging, confirm(), has_command(), make_temp_dir()
│ ├── platform.sh # detect_distro(), detect_arch(), pkg_install(), pkg_check(), pkg_remove()
│ ├── rollback.sh # Rollback tracking (track_file, track_dir, add_rollback_cmd)
│ ├── shell_config.sh # write_env_snippet, write_alias_snippet, write_completion_snippet
│ ├── registry.sh # Dynamically generated installer registry
│ ├── registry.sh # Dynamically generated tool registry
│ └── routes.sh # Central router script
├── commands/ # Non-installer commands (help, con, uninstall)
├── commands/ # Non-tool commands (help, con, uninstall)
├── assets/ # Assets (logo art, etc.)
│ └── pixel_art.ansi
├── bootstrap.sh # Metascript for environment setup + library loading
@@ -33,12 +33,12 @@ bootstrap/
## Step-by-Step Checklist
When adding a new installer named `<name>`:
When adding a new tool named `<name>`:
### Step 1: Analyze user request & gather details
When the user asks you to create an installer, they often provide either an official `curl` install script or a link to a `.tar.gz` release.
You MUST do the following before writing the script:
When the user asks you to add a tool, they often provide either an official `curl` install script or a link to a `.tar.gz` release.
You MUST do the following before writing the tool script:
If the user provides an official install or curl script in the prompt, or a link to one:
- Execute the `curl` command (or use `read_url_content` or `read_browser_page`) to fetch the script and analyze what it actually does under the hood.
@@ -51,13 +51,15 @@ If the user provides an official install or curl script in the prompt, or a link
**If the user provides a link to a `.tar.gz` (or `.zip`):**
- First, download the archive to a temporary directory and extract it to inspect its contents.
- Analyze the extracted folder structure to decide what needs to be installed (e.g., binaries, man pages, completions) and what should be ignored/deleted.
- Write the `install_<name>` function to download, extract, and copy only those essential files. (Use `download_file` and temporary directories, see "Resumable Download and Extraction" below).
- Write the `install_<name>` function to download, extract, and copy only those essential files. (Use `download_file` and temporary directories, see "GitHub Download and Extraction" below).
### Step 2: Create the installer script
### Step 2: Create the tool script
### Step 3: Add metadata comments to the top of your installer script
Create `tools/<name>/tool.sh` using the template below.
At the top of your new installer script, right below `#!/usr/bin/env bash`, add the following metadata headers:
### Step 3: Add metadata comments to the top of your tool script
At the top of your new tool script, right below `#!/usr/bin/env bash`, add the following metadata headers:
```bash
# Tool: <name>
# DisplayName: <displayName>
@@ -65,7 +67,7 @@ At the top of your new installer script, right below `#!/usr/bin/env bash`, add
# Strategy: <strategy> (binary | managed | system)
```
The central router `lib/routes.sh` and autocomplete function in `b.sh` will dynamically parse this metadata from all `install_*.sh` scripts to register the installer and keys automatically! No manual edits to `lib/routes.sh` or `b.sh` are required.
The central router `lib/routes.sh` and autocomplete function in `b.sh` will dynamically parse this metadata from all `tools/*/tool.sh` scripts to register the tool and keys automatically! No manual edits to `lib/routes.sh` or `b.sh` are required.
### Step 4: Implement Rollback Tracking (Crucial)
@@ -78,16 +80,16 @@ To ensure the user can seamlessly use `b rb <name>` to uninstall or rollback a t
### Step 5: Verify (optional)
Verify that the installer works and appears in the help output:
Verify that the tool works and appears in the help output:
- Run `b all` to confirm it appears in the help list.
- Run `b ware <name> -y` to test direct installation.
- Run `b ware <name>` to test the interactive editing flow.
---
## Installer Script Template
## Tool Script Template
Every installer follows this exact structure. Copy this and fill in the tool-specific logic (notice there are no standalone execution guards or curl checks):
Every tool follows this exact structure. Copy this and fill in the tool-specific logic (notice there are no standalone execution guards or curl checks):
```bash
#!/usr/bin/env bash
@@ -152,7 +154,7 @@ main "$@"
## Available Library Functions
These are pre-loaded by `bootstrap.sh` — no need to source them manually in installers.
These are pre-loaded by `bootstrap.sh` — no need to source them manually in tool scripts.
### From `lib/common.sh`
@@ -248,7 +250,7 @@ track_file "$BOOTSTRAP_BIN/binary"
## Rules & Conventions
1. **File naming**: Always `install_<name>.sh` in the `installers/` directory.
1. **File naming**: Always `tools/<name>/tool.sh`.
2. **Confirmation prompts**: Always ask before installing. Check if already installed first.
3. **Rollback Tracking**: NEVER omit rollback hooks. If you move a file to `$BOOTSTRAP_BIN`, you MUST call `track_file`. If you build/install manually (e.g. via `makepkg -si`), you MUST call `add_rollback_cmd "sudo pacman -R --noconfirm <pkg>"` or equivalent.
4. **Shell Drop-ins**: Always use `write_env_snippet`, `write_alias_snippet`, or `write_completion_snippet` instead of manually injecting code directly into `~/.bashrc`.

View File

@@ -20,11 +20,11 @@ When the user asks to "cut a release", "bump the version", or "tag a new version
git log $(git describe --tags --abbrev=0)..HEAD --oneline
```
2. **Determine the bump level** using semantic versioning rules:
- Skip any commits that only touch `installers/` or docs — those don't warrant a bump.
- Skip any commits that only touch `tools/` or docs — those don't warrant a bump.
- If any commit has `BREAKING CHANGE` or `!:` → **major**
- If any core-CLI commit has `feat:` → **minor**
- Otherwise (only `fix:`, `refactor:`, etc. in core-CLI) → **patch**
- If *all* commits are installer-only or docs-only → inform the user no release is needed.
- If *all* commits are tool-only or docs-only → inform the user no release is needed.
3. **Formulate a verbose, structured description of the changes** based on the analyzed commits. Group the changes into logical sections (such as "Breaking Changes & Major Features:" and "Other Updates:") and list the corresponding commit messages or summaries. Example format:
```text
Breaking Changes & Major Features:

8
b.sh
View File

@@ -93,8 +93,8 @@ _b_completion() {
local routes_dir="$HOME/.config/bootstrap"
local installer_keys=""
if [ -d "$routes_dir/installers" ]; then
for f in "$routes_dir/installers"/install_*.sh; do
if [ -d "$routes_dir/tools" ]; then
for f in "$routes_dir/tools"/*/tool.sh; do
if [ -f "$f" ]; then
local tool
tool=$(grep -E "^# Tool:" "$f" | head -n1 | sed -E 's/^# Tool:\s*//I')
@@ -135,8 +135,8 @@ _b_completion() {
if [ "$COMP_CWORD" -eq 2 ] && { [ "$prev" = "ware" ] || [ "$prev" = "bware" ]; }; then
local routes_dir="$HOME/.config/bootstrap"
local installer_keys=""
if [ -d "$routes_dir/installers" ]; then
for f in "$routes_dir/installers"/install_*.sh; do
if [ -d "$routes_dir/tools" ]; then
for f in "$routes_dir/tools"/*/tool.sh; do
if [ -f "$f" ]; then
local tool
tool=$(grep -E "^# Tool:" "$f" | head -n1 | sed -E 's/^# Tool:\s*//I')

View File

@@ -120,10 +120,10 @@ EOF
fi
done
# Also copy installers if they exist locally
if [ -d "$_SCRIPT_DIR/installers" ]; then
mkdir -p "$routes_dir/installers"
cp -r "$_SCRIPT_DIR/installers/"* "$routes_dir/installers/"
# Also copy tools if they exist locally
if [ -d "$_SCRIPT_DIR/tools" ]; then
mkdir -p "$routes_dir/tools"
cp -r "$_SCRIPT_DIR/tools/"* "$routes_dir/tools/"
fi
# Also copy plugins if they exist locally

View File

@@ -1,13 +1,13 @@
# shellcheck shell=bash
# Command: help
# Lists all available bootstrap commands and installers
# Lists all available bootstrap commands and tools
echo "Available bootstrap commands:"
# Non-installers first (aligned to 6 chars width)
# Non-tools first (aligned to 6 chars width)
printf " %-6s - %s\n" "all" "List all available commands"
printf " %-6s - %s\n" "con" "Edit config (e.g. b con nvim)"
printf " %-6s - %s\n" "up" "Check for updates and update Bootstrap CLI"
printf " %-6s - %s\n" "ware" "Edit and run an installer (e.g. b ware nvim)"
printf " %-6s - %s\n" "ware" "Edit and run a tool (e.g. b ware nvim)"
printf " %-6s - %s\n" "gone" "Uninstall Bootstrap CLI helper"

View File

@@ -1,162 +1,165 @@
# Client Authentication and Provisioning Specification
# Client Onboarding & Secrets Provisioning
This document defines the interface and protocol flow for the client application interacting with the bootstrap authentication server. It serves as a guide for implementing any client, particularly the dual mode bash script client.
## Core Concepts
The bootstrapping process establishes trust between a new client device, an existing administrator device, and the authentication server. The authentication server uses Ed25519 public key cryptography for authentication and `age` for secure payload encryption.
### Dual Mode Client
The client application operates in one of two modes:
1. **Requester Mode**: Used by a new, unprovisioned device to request access and receive secrets.
2. **Approver Mode**: Used by an already provisioned administrator device to authorize pending requests.
This wiki page describes the design, cryptography, and protocol flow of the **Bootstrap Client Onboarding and Secrets Provisioning System**. It explains how a new client device establishes secure trust with an authentication server through an existing administrator device.
---
## The Authentication and Provisioning Flow
## Overview & Architecture
The complete flow consists of five sequential phases.
The onboarding process leverages public-key cryptography to securely distribute configurations or secrets (encrypted using `age`) to newly registered nodes.
### Phase 1: Administrator Bootstrapping
1. The server starts up. If the `ADMIN_PUBLIC_KEY` environment variable is set, the server automatically registers and approves this public key as an administrator device in the database.
2. The administrator client on the admin machine is configured to use the corresponding private key.
The trust model consists of three entities:
1. **Requester Node (New Client)**: An unprovisioned machine requesting configuration secrets. It generates a local Ed25519 key pair for identification.
2. **Approver Node (Administrator)**: A trusted administrator machine that already possesses an approved Ed25519 private key.
3. **Authentication Server**: The central coordinator that manages pending requests, validates administrator signatures, and serves `age`-encrypted payloads. The backend server codebase is hosted in the [bootstrap-auth-server](https://github.com/sortedcord/bootstrap-auth-server) repository.
### Phase 2: Client Request Initiation (Requester Mode)
1. The new device runs the client in requester mode:
```bash
b me (optional: --server <server_url>) [default auth server is https://b.adityagupta.dev/auth]
```
2. The client script generates an Ed25519 key pair locally.
3. The client sends a `POST /api/register` request containing its generated public key.
4. The server registers the device in a `pending` state and returns:
- A short, human readable `user_code` (e.g. 4 to 8 characters).
- A unique `device_id`.
5. The client script displays the `user_code` to the operator and begins polling the challenge endpoint:
```
GET /api/challenge/poll?device_id=<device_id>
```
```mermaid
sequenceDiagram
autonumber
actor Admin
participant Requester as Requester Client (b me)
participant Server as Auth Server
participant Approver as Approver Client (b trust)
### Phase 3: Administrator Approval (Approver Mode)
1. The operator reads the `user_code` from the requesting device's terminal.
2. On the administrator device, the operator runs the client in approver mode:
```bash
b trust <user_code> [--server <server_url>]
```
3. The administrator client queries the server to retrieve the pending registration details:
```
GET /api/pending/<user_code>
```
4. The server returns the pending `device_id` and the requester's `public_key`.
5. The administrator client displays these details. The operator confirms the request.
6. The administrator client signs a payload containing the requester's `device_id` and the approval action using its Ed25519 administrator private key.
7. The administrator client submits the signature and its public key to the server:
```
POST /api/approve
```
8. The server verifies the administrator's signature against the registered administrator public keys. If valid, the server transitions the requester device state from `pending` to `approved`.
### Phase 4: Payload Provisioning
1. Once the requester device is approved, the server generates the secret payload (or retrieves it from a secure source).
2. The server encrypts the payload using the requester's public key via `age`.
3. The server stores this encrypted payload as a challenge response.
### Phase 5: Challenge Completion and Retrieval
1. The next poll from the requester client to `GET /api/challenge/poll?device_id=<device_id>` succeeds.
2. The server returns the `age` encrypted payload.
3. The requester client decrypts the payload using its local private key.
4. The secrets are successfully provisioned.
Requester->>Server: POST /api/register (Host, OS, Public Key)
Server-->>Requester: 200 OK (user_code, challenge_nonce)
Note over Requester: Displays user_code & begins polling...
Admin->>Approver: Exec: b trust <user_code>
Approver->>Server: GET /api/pending/<user_code>
Server-->>Approver: 200 OK (Requester Public Key)
Note over Approver: Admin confirms public key fingerprint
Approver->>Server: POST /api/approve (user_code, Admin Signature & Fingerprint)
Note over Server: Server verifies signature against admin list
Requester->>Server: POST /api/challenge/poll (user_code, Signature of Nonce)
Server-->>Requester: 200 OK (Encrypted Secrets Payload)
Note over Requester: Decrypts payload using local Ed25519 private key
```
---
## API Endpoints Reference
## Cryptographic Mechanics
### 1. Register Device
- **Endpoint**: `POST /api/register`
- **Request Body**:
To maintain security without complex dependencies, the system uses native Unix tools:
* **Authentication (Ed25519)**: SSH Ed25519 key pairs generated by `ssh-keygen` are used for signing. Payloads are signed using `ssh-keygen -Y sign` with a fixed namespace of `bootstrap`.
* **Encryption (`age`)**: Payloads are encrypted specifically to the requester's SSH Ed25519 public key. The client decrypts the payload using its private key:
```bash
age -d -i ~/.config/bootstrap-client/id_ed25519
```
---
## Step-by-Step Protocol Flow
### Phase 1: Administrator Registration
The server registers administrator public keys at startup (e.g., via the `ADMIN_PUBLIC_KEY` environment variable). The administrator client on the admin machine must be configured to use the corresponding private key.
### Phase 2: Client Request (`b me`)
1. The requester executes `b me`.
2. It generates an Ed25519 key pair (`id_ed25519`/`id_ed25519.pub`) in `~/.config/bootstrap-client/`.
3. It sends a registration request to the server containing its hostname, OS, and public key.
4. The server registers the device as `pending`, generating a short, human-readable `user_code` and a `challenge_nonce`.
5. The requester displays the `user_code` and begins polling `/api/challenge/poll`.
### Phase 3: Administrator Approval (`b trust`)
1. The operator reads the `user_code` from the requester's terminal and enters it on the administrator device: `b trust <user_code>`.
2. The administrator client fetches the pending public key from `/api/pending/<user_code>`.
3. The operator validates the public key fingerprint.
4. The administrator client signs the requester's public key using `ssh-keygen -Y sign` and submits the signature along with its fingerprint to `/api/approve`.
5. The server validates the signature. If valid, the client state transitions to `approved`.
### Phase 4: Secrets Retrieval & Decryption
1. During its next poll, the requester client signs the `challenge_nonce` and submits it to `/api/challenge/poll`.
2. The server verifies the signature. Since the client is now approved, it returns the secrets payload (which was encrypted with the requester's public key using `age`).
3. The requester client base64-decodes the payload, decrypts it using its local SSH private key, and saves it to `~/.config/bootstrap-client/secrets.decrypted`.
---
## API Reference
### Register Device
* **Endpoint**: `POST /api/register`
* **Content-Type**: `application/json`
* **Request**:
```json
{
"hostname": "my-client-hostname",
"os": "Linux",
"public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..."
}
```
* **Response (200 OK)**:
```json
{
"user_code": "G4J2N3",
"challenge_nonce": "a6f8b9...",
"expires_in": 300
}
```
### Get Pending Details
* **Endpoint**: `GET /api/pending/<user_code>`
* **Response (200 OK)**:
```json
{
"public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..."
}
```
- **Response Body (200 OK)**:
```json
{
"device_id": "uuid-string",
"user_code": "A3F9K2"
}
```
### 2. Get Pending Device Details
- **Endpoint**: `GET /api/pending/<user_code>`
- **Response Body (200 OK)**:
### Approve Device
* **Endpoint**: `POST /api/approve`
* **Content-Type**: `application/json`
* **Request**:
```json
{
"device_id": "uuid-string",
"public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..."
"user_code": "G4J2N3",
"approver_public_key_fingerprint": "SHA256:...",
"signature": "base64-encoded-sshsig-blob"
}
```
> [!NOTE]
> The `signature` is the base64-encoded binary content of the SSHSIG file (i.e. the raw base64 string inside the armor, excluding the `-----BEGIN/END SSH SIGNATURE-----` lines).
### 3. Approve Device
- **Endpoint**: `POST /api/approve`
- **Request Body**:
### Poll Challenge
* **Endpoint**: `POST /api/challenge/poll`
* **Content-Type**: `application/json`
* **Request**:
```json
{
"device_id": "uuid-string",
"admin_public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5...",
"signature": "hex-encoded-signature-bytes"
"user_code": "G4J2N3",
"signature": "base64-encoded-sshsig-blob-of-challenge-nonce"
}
```
- **Response Body (200 OK)**: Empty or success confirmation.
### 4. Poll Challenge
- **Endpoint**: `GET /api/challenge/poll?device_id=<device_id>`
- **Response Body (200 OK - Pending)**:
* **Response (200 OK)**:
```json
{
"status": "pending"
}
```
- **Response Body (200 OK - Approved & Encrypted)**:
```json
{
"status": "approved",
"payload": "-----BEGIN AGE ENCRYPTED FILE-----\n..."
"encrypted_secrets": "base64-encoded-age-encrypted-payload"
}
```
---
## Bash Client Commands and Usage
## Client Usage Guide
### Requirements
Ensure `ssh-keygen`, `curl`, `jq`, and `age` are installed. (The Bootstrap `auth` plugin resolves these automatically on start).
### Global Dependencies
- `curl` or `wget` for making HTTP requests.
- `jq` for parsing JSON payloads.
- `ssh-keygen` for Ed25519 key generation and signing.
- `age` and `age-keygen` for decrypting the final payload.
### Command Structure
#### 1. Device Registration Request
Generates local keys, registers with the server, and polls for the encrypted secret payload.
### 1. Requesting Access (`b me`)
Run the following on the client machine to initiate registration:
```bash
b me \
--server <server_url> \
[--key-dir <directory_to_save_keys>] \
[--poll-interval <seconds>]
b me [--server <server_url>] [--key-dir <dir>] [--poll-interval <seconds>]
```
- `--server`: Base URL of the bootstrap authentication server.
- `--key-dir`: Directory where the new Ed25519 and age keys will be saved (defaults to `~/.config/bootstrap-client/`).
- `--poll-interval`: Frequency of polling in seconds (defaults to `5`).
* Default `--server`: `https://b.adityagupta.dev/auth`
* Default `--key-dir`: `~/.config/bootstrap-client`
* Default `--poll-interval`: `5`
#### 2. Request Approval
Retrieves a pending request by its user code, requests user confirmation, signs the approval payload, and sends it to the server.
### 2. Approving Access (`b trust`)
Run the following on the administrator machine to approve a pending request:
```bash
b trust <user_code> \
--server <server_url> \
--admin-key <path_to_admin_private_key>
b trust <user_code> [--server <server_url>] [--admin-key <path_to_admin_private_key>]
```
- `--code`: The short human readable code displayed on the requesting device.
- `--server`: Base URL of the bootstrap authentication server.
- `--admin-key`: Path to the administrator's private key used to sign the approval.
* Default `--admin-key`: `~/.ssh/id_ed25519`

View File

@@ -1,6 +1,6 @@
# Plugin Development Guide
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike installers (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a sandboxed subshell**.
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike tools (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a sandboxed subshell**.
This means downloading and invoking a plugin makes no system modifications other than caching the `.sh` file itself. They are fetched only the very first time you invoke them.

View File

@@ -52,7 +52,7 @@ If the argument does not match an installed tool in the registry, it is treated
## 4. Required Abstractions & Helper Modifications
### A. Context Initialization
Before executing an installer script, the `b` CLI initializes the command list:
Before executing a tool script, the `b` CLI initializes the command list:
```bash
export BOOTSTRAP_UNINSTALLER_CMDS="$HOME/.local/state/bootstrap/uninstallers/nvim.cmds"
mkdir -p "$(dirname "$BOOTSTRAP_UNINSTALLER_CMDS")"
@@ -97,7 +97,7 @@ log_success "Rollback complete."
```
## 6. Resilience Against User Modifications
Because `b ware <tool>` allows users to modify installation scripts:
Because `b ware <tool>` allows users to modify tool scripts:
1. **Dynamic Adaptation:** The manifest is built *during* execution, adapting to whatever packages the user manually added.
2. **Fault Isolation:** The `eval` loop ensures that a syntax error in one custom rollback step doesn't crash the removal of other tracked packages.
@@ -113,7 +113,7 @@ When a tool is uninstalled:
To handle failures during installation (e.g., network drops, script errors, or user cancellation via `Ctrl+C`), the CLI incorporates a transactional approach that balances **automatic rollback** and **resumability**:
### A. The Interruption Trap & Prompt
When running an installer, the central router (`lib/routes.sh`) traps `SIGINT` and `SIGTERM` signals. If the installation fails or is interrupted:
When running a tool, the central router (`lib/routes.sh`) traps `SIGINT` and `SIGTERM` signals. If the installation fails or is interrupted:
1. The trap catches the event and stops execution.
2. The user is prompted interactively:
- **Rollback (r)**: Invokes `execute_rollback <tool>` immediately to clean up all partial modifications.
@@ -130,6 +130,6 @@ If the user chooses to **keep** the partial state and runs `b <tool>` again:
To make rerunning an interrupted script fast and efficient, installers use `download_file <url> <dest>` instead of raw `curl`:
1. It downloads the payload to a central cache directory: `~/.local/state/bootstrap/cache/`.
2. It uses `curl -C -` to continue the download from the byte offset where it was interrupted.
3. Once completed, it copies the cached file to the installer's temp directory.
3. Once completed, it copies the cached file to the tool's temp directory.
4. Distro package manager commands (`pkg_install`) and shell snippets (`write_env_snippet`) are naturally idempotent, allowing the script to breeze through already completed steps in milliseconds and resume exactly where the heavy work failed.

View File

@@ -6,7 +6,7 @@ The Bootstrap CLI uses a semantic, git-tag-driven versioning workflow.
- **Do not manually edit the `VERSION` file.**
- Develop normally using [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat: Add new tool`, `fix: Typo in script`).
- **Note on Installers:** Adding or modifying installers in the `installers/` directory **does not** require a version bump. They are fetched dynamically from the registry when a user runs `b ware <tool>`.
- **Note on Tools:** Adding or modifying tools in the `tools/` directory **does not** require a version bump. They are fetched dynamically from the registry when a user runs `b ware <tool>`.
## 2. When to Cut a Release

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# GitHub API helper functions for Bootstrap installers
# GitHub API helper functions for Bootstrap tools
# Usage: github_get_latest_release <owner/repo>
# Prints the tag_name of the latest release.

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Central routing script for bootstrap installers.
# Central routing script for bootstrap tools.
# This file is updated automatically by the 'b' command.
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd 2>/dev/null || pwd)"
@@ -69,8 +69,8 @@ run_ware() {
display_name="$(echo "${tool:0:1}" | tr '[:lower:]' '[:upper:]')${tool:1}"
fi
# Check for local installer first
local local_installer="$BOOTSTRAP_DIR/installers/install_${tool}.sh"
# Check for local tool definition first
local local_installer="$BOOTSTRAP_DIR/tools/${tool}/tool.sh"
if [ "$bypass_edit" = "true" ] && [ -f "$local_installer" ]; then
log_info "Running ${display_name} installer..."
@@ -86,7 +86,7 @@ run_ware() {
else
BOOTSTRAP_BASE_URL="${BOOTSTRAP_BASE_URL:-https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master}"
BOOTSTRAP_FALLBACK_URL="${BOOTSTRAP_FALLBACK_URL:-https://raw.githubusercontent.com/sortedcord/bootstrap/refs/heads/master}"
local installer_path="installers/install_${tool}.sh"
local installer_path="tools/${tool}/tool.sh"
local download_status=0
log_info "Downloading ${display_name} installer..."

View File

@@ -32,7 +32,7 @@ More scripts will be added over time.
To bootstrap a new machine and set up the `b` command tool, run the following:
```bash
curl -fsSL https://adityagupta.dev/b | bash
curl -fsSL https://b.adityagupta.dev | bash
```
Once bootstrapped, you list all commands available -
@@ -119,55 +119,42 @@ b up
b up --force
```
### Client Authentication and Provisioning (`b me` and `b trust`)
## Client Onboarding & Secrets Provisioning
Bootstrap CLI supports a secure, cryptographic client onboarding and secrets provisioning flow. This allows you to securely register new requester devices and authorize them via an administrator device.
Bootstrap CLI features a secure, cryptographic client onboarding and secrets provisioning flow. Driven by the lazy-loaded `auth` plugin, it allows you to register new requester devices and authorize them via a trusted administrator machine using SSH Ed25519 key signing and `age` encryption.
For the complete protocol specification, including the underlying REST API and cryptographic details, see the [Client Authentication and Provisioning Specification](docs/client_spec_auth.md).
The backend authentication and verification service is implemented in the [bootstrap-auth-server](https://github.com/sortedcord/bootstrap-auth-server) repository. For detailed client specifications, protocols, REST API endpoint specs, and cryptographic steps, refer to the [Client Onboarding & Secrets Provisioning Wiki](docs/client_spec_auth.md).
#### 1. Device Registration (`b me`)
To initiate registration on a new, unprovisioned machine, run:
### 1. Device Registration (`b me`)
To register a new, unprovisioned machine:
```bash
b me [--server <server_url>] [--key-dir <dir>] [--poll-interval <seconds>]
```
This generates a local SSH Ed25519 key pair, registers the device in a pending state, displays a short `user_code`, and polls the server. Once approved, it retrieves the secrets payload, decrypts it locally using `age`, and saves it to `<key-dir>/secrets.decrypted`.
This generates a local SSH Ed25519 key pair, registers your device in a pending state with the authentication server, displays a short `user_code`, and starts polling for administrator approval. Once approved, the encrypted payload containing secrets is retrieved, decrypted locally via `age`, and saved to `<key-dir>/secrets.decrypted`.
#### 2. Request Approval (`b trust`)
To authorize a pending device, run this command on an already provisioned administrator machine:
### 2. Request Approval (`b trust`)
To authorize a pending client from an administrator device:
```bash
b trust <user_code> [--server <server_url>] [--admin-key <path_to_admin_private_key>]
```
This retrieves the pending device's public key, prompts the administrator for confirmation, cryptographically signs the public key using the admin key, and submits the approval signature back to the authentication server.
This retrieves the client's public key, prompts the administrator for confirmation, signs the key using `ssh-keygen -Y sign` (under the `bootstrap` namespace), and submits the approval signature back to the server.
## Plugins (`b <plugin_name>`)
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike installers (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a subshell**.
Plugins are first-party or third-party applications written to work directly with `bootstrap`. Unlike tools (or packages) which modify your system by compiling code, downloading binaries, and altering shell configuration files, **plugins are lazy-loaded scripts that execute within a subshell**.
Downloading and invoking a plugin makes no system modifications other than caching the `.sh` file itself. They are fetched only the very first time you invoke them.
### Official Plugins
Bootstrap comes pre-configured with a set of official plugins ready to use out-of-the-box:
* **`auth`**: Handles client onboarding and secrets provisioning, exposing the `b me` and `b trust` CLI commands. See the [Client Onboarding & Secrets Provisioning](#client-onboarding--secrets-provisioning) section for detailed usage.
* **`weather`**: Fetches and displays a neat weather forecast using `wttr.in`.
```bash
b weather
b weather New York
```
* **`sysinfo`**: Displays a system resource dashboard showing CPU, memory, disk usage, and OS/kernel details.
```bash
b sysinfo
```
* **`todo`**: A command-line todo list manager. Tasks are persisted to a lightweight text file in your user directory.
```bash
b todo add "Write a new plugin"
b todo list
b todo done 1
```
* **`weather`**: Fetches weather forecasts via `wttr.in` (Usage: `b weather [location]`).
* **`sysinfo`**: Displays a system resource dashboard (Usage: `b sysinfo`).
* **`todo`**: A command-line todo manager (Usage: `b todo <add "task"|list|done <id>>`).
### Adding Third-Party Plugins
@@ -263,8 +250,8 @@ Running scripts directly from the internet is convenient but should always be ap
### Why Bootstrap is More Secure
Instead of blindly piping large, third-party installation scripts (often hundreds or thousands of lines of unscrutinized code) directly from the internet into your shell, Bootstrap uses a **scrutinized and simplified** approach:
1. **Audited & Minimised**: Every script in `installers/` has been scrutinized, refactored, and stripped of redundant compatibility layers (like Windows/macOS support or complex environment checks), leaving only the essential, readable logic required for your setup.
2. **Controlled Execution**: Since installer scripts are hosted locally in your cloned repository, you can review every line of code before executing it. You are never subject to silent, upstream changes to installers.
1. **Audited & Minimised**: Every script in `tools/` has been scrutinized, refactored, and stripped of redundant compatibility layers (like Windows/macOS support or complex environment checks), leaving only the essential, readable logic required for your setup.
2. **Controlled Execution**: Since tool scripts are hosted locally in your cloned repository, you can review every line of code before executing it. You are never subject to silent, upstream changes to tools.
3. **No Raw Pipes**: We download official binary releases directly to verified temporary locations rather than running arbitrary third-party script pipelines.
If you want to audit the core Bootstrap CLI itself before running it:

View File

@@ -5,7 +5,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$(dirname "$SCRIPT_DIR")"
INSTALLERS_DIR="$REPO_DIR/installers"
TOOLS_DIR="$REPO_DIR/tools"
REGISTRY_FILE="$REPO_DIR/lib/registry.sh"
echo "==> Generating registry.sh..."
@@ -16,7 +16,7 @@ declare -A tools_disp
declare -A tools_strat
keys=()
for f in "$INSTALLERS_DIR"/install_*.sh; do
for f in "$TOOLS_DIR"/*/tool.sh; do
[ -f "$f" ] || continue
tool=$(grep -E "^# Tool:" "$f" | head -n1 | sed -E 's/^# Tool:\s*//I')
disp_name=$(grep -E "^# DisplayName:" "$f" | head -n1 | sed -E 's/^# DisplayName:\s*//I')