docs: prepare declarative apps release as v3 (#287)
* docs(urls): update Gordon public links * docs(version): rename declarative apps release to v3 * docs(upgrade): clarify v3 migration guidance
- commit
- 6fdddb823ae6ec7dc05fd9afa4a85fc0a7062223
- author
- bnema · · 2026-09-15 16:07 UTC
- committer
- GitHub · · 2026-09-15 16:07 UTC
- parent
- 574ac67
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown - refs
- tag: v3.0.0-alpha.1
26 files · +66 -86
M README.md +5 -5
| @@ -5,7 +5,7 @@ | |||
| 5 | 5 | Self-hosted container deployment. Push an image, declare an app, deploy it. | |
| 6 | 6 | ||
| 7 | 7 | - Website: https://bnema.dev/gordon | |
| 8 | - | - Documentation: [Docs](https://gordon.bnema.dev/docs) | [Wiki](https://gordon.bnema.dev/wiki) | |
| 8 | + | - Documentation: [Docs](https://bnema.dev/gordon/docs) | [Wiki](https://bnema.dev/gordon/wiki) | |
| 9 | 9 | - Discuss: [GitHub Discussions](https://github.com/bnema/gordon/discussions) | |
| 10 | 10 | ||
| 11 | 11 | --- | |
| @@ -20,7 +20,7 @@ The flow is explicit: build and push an image, declare the app in a standalone T | |||
| 20 | 20 | ||
| 21 | 21 | ```bash | |
| 22 | 22 | # Install the latest stable release to ~/.local/bin | |
| 23 | - | curl -fsSL https://gordon.bnema.dev/install.sh | sh | |
| 23 | + | curl -fsSL https://bnema.dev/gordon/install | sh | |
| 24 | 24 | ||
| 25 | 25 | # Start the server (restart your shell first if the installer updated PATH) | |
| 26 | 26 | gordon serve | |
| @@ -28,9 +28,9 @@ gordon serve | |||
| 28 | 28 | ||
| 29 | 29 | The installer uses `~/.local/bin` without `sudo` and can add the effective install directory to Fish, Bash, or Zsh PATH configuration. Set `GORDON_UPDATE_PATH=1` to update PATH without prompting or `GORDON_UPDATE_PATH=0` to leave configuration unchanged. Override the destination with an absolute path such as `GORDON_INSTALL_DIR="$HOME/bin"`, `GORDON_INSTALL_DIR="$HOME/.local/bin"`, or `GORDON_INSTALL_DIR=/usr/local/bin`. | |
| 30 | 30 | ||
| 31 | - | To build the current `next` branch commit locally, use `GORDON_CHANNEL=next`. This is an unverified development source build, not a checksum-verified release, and requires a compatible Go toolchain. See the [installation guide](https://gordon.bnema.dev/docs/installation#choosing-an-install-channel). | |
| 31 | + | To build the current `next` branch commit locally, use `GORDON_CHANNEL=next`. This is an unverified development source build, not a checksum-verified release, and requires a compatible Go toolchain. See the [installation guide](https://bnema.dev/gordon/docs/installation#choosing-an-install-channel). | |
| 32 | 32 | ||
| 33 | - | Config is created at `~/.config/gordon/gordon.toml`. See the [Getting Started guide](https://gordon.bnema.dev/docs/getting-started) for full setup. | |
| 33 | + | Config is created at `~/.config/gordon/gordon.toml`. See the [Getting Started guide](https://bnema.dev/gordon/docs/getting-started) for full setup. | |
| 34 | 34 | ||
| 35 | 35 | ## Deploy with the CLI | |
| 36 | 36 | ||
| @@ -169,7 +169,7 @@ gordon apps deploy blog --remote prod | |||
| 169 | 169 | ||
| 170 | 170 | ## Documentation | |
| 171 | 171 | ||
| 172 | - | Full documentation at **[gordon.bnema.dev](https://bnema.dev/gordon)** | |
| 172 | + | Full documentation at **[bnema.dev/gordon](https://bnema.dev/gordon)** | |
| 173 | 173 | ||
| 174 | 174 | - [Docs](https://bnema.dev/gordon/docs) — Installation, configuration, CLI reference | |
| 175 | 175 | - [Wiki](https://bnema.dev/gordon/wiki) — Tutorials, guides, and examples | |
| @@ -5,7 +5,7 @@ | |||||
| 5 | Self-hosted container deployment. Push an image, declare an app, deploy it. | 5 | Self-hosted container deployment. Push an image, declare an app, deploy it. | ||
| 6 | 6 | ||||
| 7 | - Website: https://bnema.dev/gordon | 7 | - Website: https://bnema.dev/gordon | ||
| 8 | - | - Documentation: [Docs](https://gordon.bnema.dev/docs) | [Wiki](https://gordon.bnema.dev/wiki) | 8 | + | - Documentation: [Docs](https://bnema.dev/gordon/docs) | [Wiki](https://bnema.dev/gordon/wiki) |
| 9 | - Discuss: [GitHub Discussions](https://github.com/bnema/gordon/discussions) | 9 | - Discuss: [GitHub Discussions](https://github.com/bnema/gordon/discussions) | ||
| 10 | 10 | ||||
| 11 | --- | 11 | --- | ||
| @@ -20,7 +20,7 @@ The flow is explicit: build and push an image, declare the app in a standalone T | |||||
| 20 | 20 | ||||
| 21 | ```bash | 21 | ```bash | ||
| 22 | # Install the latest stable release to ~/.local/bin | 22 | # Install the latest stable release to ~/.local/bin | ||
| 23 | - | curl -fsSL https://gordon.bnema.dev/install.sh | sh | 23 | + | curl -fsSL https://bnema.dev/gordon/install | sh |
| 24 | 24 | ||||
| 25 | # Start the server (restart your shell first if the installer updated PATH) | 25 | # Start the server (restart your shell first if the installer updated PATH) | ||
| 26 | gordon serve | 26 | gordon serve | ||
| @@ -28,9 +28,9 @@ gordon serve | |||||
| 28 | 28 | ||||
| 29 | The installer uses `~/.local/bin` without `sudo` and can add the effective install directory to Fish, Bash, or Zsh PATH configuration. Set `GORDON_UPDATE_PATH=1` to update PATH without prompting or `GORDON_UPDATE_PATH=0` to leave configuration unchanged. Override the destination with an absolute path such as `GORDON_INSTALL_DIR="$HOME/bin"`, `GORDON_INSTALL_DIR="$HOME/.local/bin"`, or `GORDON_INSTALL_DIR=/usr/local/bin`. | 29 | The installer uses `~/.local/bin` without `sudo` and can add the effective install directory to Fish, Bash, or Zsh PATH configuration. Set `GORDON_UPDATE_PATH=1` to update PATH without prompting or `GORDON_UPDATE_PATH=0` to leave configuration unchanged. Override the destination with an absolute path such as `GORDON_INSTALL_DIR="$HOME/bin"`, `GORDON_INSTALL_DIR="$HOME/.local/bin"`, or `GORDON_INSTALL_DIR=/usr/local/bin`. | ||
| 30 | 30 | ||||
| 31 | - | To build the current `next` branch commit locally, use `GORDON_CHANNEL=next`. This is an unverified development source build, not a checksum-verified release, and requires a compatible Go toolchain. See the [installation guide](https://gordon.bnema.dev/docs/installation#choosing-an-install-channel). | 31 | + | To build the current `next` branch commit locally, use `GORDON_CHANNEL=next`. This is an unverified development source build, not a checksum-verified release, and requires a compatible Go toolchain. See the [installation guide](https://bnema.dev/gordon/docs/installation#choosing-an-install-channel). |
| 32 | 32 | ||||
| 33 | - | Config is created at `~/.config/gordon/gordon.toml`. See the [Getting Started guide](https://gordon.bnema.dev/docs/getting-started) for full setup. | 33 | + | Config is created at `~/.config/gordon/gordon.toml`. See the [Getting Started guide](https://bnema.dev/gordon/docs/getting-started) for full setup. |
| 34 | 34 | ||||
| 35 | ## Deploy with the CLI | 35 | ## Deploy with the CLI | ||
| 36 | 36 | ||||
| @@ -169,7 +169,7 @@ gordon apps deploy blog --remote prod | |||||
| 169 | 169 | ||||
| 170 | ## Documentation | 170 | ## Documentation | ||
| 171 | 171 | ||||
| 172 | - | Full documentation at **[gordon.bnema.dev](https://bnema.dev/gordon)** | 172 | + | Full documentation at **[bnema.dev/gordon](https://bnema.dev/gordon)** |
| 173 | 173 | ||||
| 174 | - [Docs](https://bnema.dev/gordon/docs) — Installation, configuration, CLI reference | 174 | - [Docs](https://bnema.dev/gordon/docs) — Installation, configuration, CLI reference | ||
| 175 | - [Wiki](https://bnema.dev/gordon/wiki) — Tutorials, guides, and examples | 175 | - [Wiki](https://bnema.dev/gordon/wiki) — Tutorials, guides, and examples | ||
M docs/config/index.md +1 -1
| @@ -105,7 +105,7 @@ enabled = true # Gordon-managed network policy | |||
| 105 | 105 | network_prefix = "gordon" # Network name prefix | |
| 106 | 106 | internal = false # Set true to block direct egress from isolated networks | |
| 107 | 107 | ||
| 108 | - | # REMOVED in v2.50 (declare apps in standalone files, see ./apps.md): | |
| 108 | + | # REMOVED in v3 (declare apps in standalone files, see ./apps.md): | |
| 109 | 109 | # [routes], [attachments], [network_groups], [[services]]-as-apps, | |
| 110 | 110 | # [service_routes], [auto_route], [previews] | |
| 111 | 111 | ||
| @@ -105,7 +105,7 @@ enabled = true # Gordon-managed network policy | |||||
| 105 | network_prefix = "gordon" # Network name prefix | 105 | network_prefix = "gordon" # Network name prefix | ||
| 106 | internal = false # Set true to block direct egress from isolated networks | 106 | internal = false # Set true to block direct egress from isolated networks | ||
| 107 | 107 | ||||
| 108 | - | # REMOVED in v2.50 (declare apps in standalone files, see ./apps.md): | 108 | + | # REMOVED in v3 (declare apps in standalone files, see ./apps.md): |
| 109 | # [routes], [attachments], [network_groups], [[services]]-as-apps, | 109 | # [routes], [attachments], [network_groups], [[services]]-as-apps, | ||
| 110 | # [service_routes], [auto_route], [previews] | 110 | # [service_routes], [auto_route], [previews] | ||
| 111 | 111 | ||||
M docs/config/reference.md +1 -1
| @@ -167,7 +167,7 @@ preserve = true # Keep volumes when containers are | |||
| 167 | 167 | # allowed_apps = ["video"] # Required; exact, non-empty | |
| 168 | 168 | # allowed_services = ["transcoder"] # Required; exact, non-empty | |
| 169 | 169 | ||
| 170 | - | # REMOVED in v2.50: [routes], [attachments], [network_groups], | |
| 170 | + | # REMOVED in v3: [routes], [attachments], [network_groups], | |
| 171 | 171 | # [[services]]-as-apps, [service_routes], [auto_route], [previews]. | |
| 172 | 172 | # Declare apps in standalone files (see ./apps.md). | |
| 173 | 173 | ||
| @@ -167,7 +167,7 @@ preserve = true # Keep volumes when containers are | |||||
| 167 | # allowed_apps = ["video"] # Required; exact, non-empty | 167 | # allowed_apps = ["video"] # Required; exact, non-empty | ||
| 168 | # allowed_services = ["transcoder"] # Required; exact, non-empty | 168 | # allowed_services = ["transcoder"] # Required; exact, non-empty | ||
| 169 | 169 | ||||
| 170 | - | # REMOVED in v2.50: [routes], [attachments], [network_groups], | 170 | + | # REMOVED in v3: [routes], [attachments], [network_groups], |
| 171 | # [[services]]-as-apps, [service_routes], [auto_route], [previews]. | 171 | # [[services]]-as-apps, [service_routes], [auto_route], [previews]. | ||
| 172 | # Declare apps in standalone files (see ./apps.md). | 172 | # Declare apps in standalone files (see ./apps.md). | ||
| 173 | 173 | ||||
M docs/deployment/rollback.md +1 -1
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | # Rollback | |
| 2 | 2 | ||
| 3 | - | Roll forward to a previous version when a deploy misbehaves. There is no historical rollback command in v2.50: rolling back means applying and deploying a previous manifest or image reference. Redeploying a mutable tag (for example `latest`) does not guarantee the previous image bytes; keep immutable versioned tags. | |
| 3 | + | Roll forward to a previous version when a deploy misbehaves. There is no historical rollback command in v3: rolling back means applying and deploying a previous manifest or image reference. Redeploying a mutable tag (for example `latest`) does not guarantee the previous image bytes; keep immutable versioned tags. | |
| 4 | 4 | ||
| 5 | 5 | ## Roll Forward to a Previous Tag | |
| 6 | 6 | ||
| @@ -1,6 +1,6 @@ | |||||
| 1 | # Rollback | 1 | # Rollback | ||
| 2 | 2 | ||||
| 3 | - | Roll forward to a previous version when a deploy misbehaves. There is no historical rollback command in v2.50: rolling back means applying and deploying a previous manifest or image reference. Redeploying a mutable tag (for example `latest`) does not guarantee the previous image bytes; keep immutable versioned tags. | 3 | + | Roll forward to a previous version when a deploy misbehaves. There is no historical rollback command in v3: rolling back means applying and deploying a previous manifest or image reference. Redeploying a mutable tag (for example `latest`) does not guarantee the previous image bytes; keep immutable versioned tags. |
| 4 | 4 | ||||
| 5 | ## Roll Forward to a Previous Tag | 5 | ## Roll Forward to a Previous Tag | ||
| 6 | 6 | ||||
M docs/getting-started.md +2 -2
| @@ -12,7 +12,7 @@ Deploy your first app with Gordon in under 5 minutes. | |||
| 12 | 12 | ## 1. Install Gordon | |
| 13 | 13 | ||
| 14 | 14 | ```bash | |
| 15 | - | curl -fsSL https://gordon.bnema.dev/install | bash | |
| 15 | + | curl -fsSL https://bnema.dev/gordon/install | bash | |
| 16 | 16 | ``` | |
| 17 | 17 | ||
| 18 | 18 | This script automatically detects your OS and architecture, downloads the appropriate binary, and installs it to `/usr/local/bin`. | |
| @@ -81,7 +81,7 @@ address = ":443" # Public smart TCP edge (choose your bi | |||
| 81 | 81 | protocol = "smart_tcp" | |
| 82 | 82 | ``` | |
| 83 | 83 | ||
| 84 | - | Application workloads are NOT declared in `gordon.toml`. Each app lives in its own standalone TOML file (see step 8). The old `[routes]`, `[attachments]`, `[network_groups]`, `[[services]]`-as-apps, `[service_routes]`, `[auto_route]`, and `[previews]` keys were removed in v2.50 — Gordon refuses to start when any of them is present. | |
| 84 | + | Application workloads are NOT declared in `gordon.toml`. Each app lives in its own standalone TOML file (see step 8). The old `[routes]`, `[attachments]`, `[network_groups]`, `[[services]]`-as-apps, `[service_routes]`, `[auto_route]`, and `[previews]` keys were removed in v3 — Gordon refuses to start when any of them is present. | |
| 85 | 85 | ||
| 86 | 86 | ## 5. Set Up DNS (Including Wildcard) | |
| 87 | 87 | ||
| @@ -12,7 +12,7 @@ Deploy your first app with Gordon in under 5 minutes. | |||||
| 12 | ## 1. Install Gordon | 12 | ## 1. Install Gordon | ||
| 13 | 13 | ||||
| 14 | ```bash | 14 | ```bash | ||
| 15 | - | curl -fsSL https://gordon.bnema.dev/install | bash | 15 | + | curl -fsSL https://bnema.dev/gordon/install | bash |
| 16 | ``` | 16 | ``` | ||
| 17 | 17 | ||||
| 18 | This script automatically detects your OS and architecture, downloads the appropriate binary, and installs it to `/usr/local/bin`. | 18 | This script automatically detects your OS and architecture, downloads the appropriate binary, and installs it to `/usr/local/bin`. | ||
| @@ -81,7 +81,7 @@ address = ":443" # Public smart TCP edge (choose your bi | |||||
| 81 | protocol = "smart_tcp" | 81 | protocol = "smart_tcp" | ||
| 82 | ``` | 82 | ``` | ||
| 83 | 83 | ||||
| 84 | - | Application workloads are NOT declared in `gordon.toml`. Each app lives in its own standalone TOML file (see step 8). The old `[routes]`, `[attachments]`, `[network_groups]`, `[[services]]`-as-apps, `[service_routes]`, `[auto_route]`, and `[previews]` keys were removed in v2.50 — Gordon refuses to start when any of them is present. | 84 | + | Application workloads are NOT declared in `gordon.toml`. Each app lives in its own standalone TOML file (see step 8). The old `[routes]`, `[attachments]`, `[network_groups]`, `[[services]]`-as-apps, `[service_routes]`, `[auto_route]`, and `[previews]` keys were removed in v3 — Gordon refuses to start when any of them is present. |
| 85 | 85 | ||||
| 86 | ## 5. Set Up DNS (Including Wildcard) | 86 | ## 5. Set Up DNS (Including Wildcard) | ||
| 87 | 87 | ||||
M docs/index.md +1 -1
| @@ -48,7 +48,7 @@ Gordon runs on your VPS and provides: | |||
| 48 | 48 | - [Configuration Overview](./config/index.md) - All configuration options | |
| 49 | 49 | - [Server Settings](./config/server.md) - Ports, domains, and runtime | |
| 50 | 50 | - [App Manifest](./config/apps.md) - Declarative app files (services, hosts, secrets, volumes) | |
| 51 | - | - [Migrate to Gordon v2.50](./migrate-to-v2.50.md) - Breaking upgrade and explicit secret migration | |
| 51 | + | - [Migrate to Gordon v3](./migrate-to-v3.md) - Breaking upgrade and explicit secret migration | |
| 52 | 52 | - [Traffic Plane](./config/traffic.md) - TCP, UDP, and TLS passthrough entrypoints | |
| 53 | 53 | - [Authentication](./config/auth.md) - Registry auth plus remote CLI login/token workflows | |
| 54 | 54 | - [Secrets](./config/secrets.md) - Installation secrets and app secret values | |
| @@ -48,7 +48,7 @@ Gordon runs on your VPS and provides: | |||||
| 48 | - [Configuration Overview](./config/index.md) - All configuration options | 48 | - [Configuration Overview](./config/index.md) - All configuration options | ||
| 49 | - [Server Settings](./config/server.md) - Ports, domains, and runtime | 49 | - [Server Settings](./config/server.md) - Ports, domains, and runtime | ||
| 50 | - [App Manifest](./config/apps.md) - Declarative app files (services, hosts, secrets, volumes) | 50 | - [App Manifest](./config/apps.md) - Declarative app files (services, hosts, secrets, volumes) | ||
| 51 | - | - [Migrate to Gordon v2.50](./migrate-to-v2.50.md) - Breaking upgrade and explicit secret migration | 51 | + | - [Migrate to Gordon v3](./migrate-to-v3.md) - Breaking upgrade and explicit secret migration |
| 52 | - [Traffic Plane](./config/traffic.md) - TCP, UDP, and TLS passthrough entrypoints | 52 | - [Traffic Plane](./config/traffic.md) - TCP, UDP, and TLS passthrough entrypoints | ||
| 53 | - [Authentication](./config/auth.md) - Registry auth plus remote CLI login/token workflows | 53 | - [Authentication](./config/auth.md) - Registry auth plus remote CLI login/token workflows | ||
| 54 | - [Secrets](./config/secrets.md) - Installation secrets and app secret values | 54 | - [Secrets](./config/secrets.md) - Installation secrets and app secret values | ||
M docs/installation.md +8 -8
| @@ -19,7 +19,7 @@ Detailed installation guide for production environments. | |||
| 19 | 19 | set -euo pipefail | |
| 20 | 20 | installer="$(mktemp)" | |
| 21 | 21 | trap 'rm -f "$installer"' EXIT | |
| 22 | - | curl -fsSL --output "$installer" https://gordon.bnema.dev/install | |
| 22 | + | curl -fsSL --output "$installer" https://bnema.dev/gordon/install | |
| 23 | 23 | if command -v less >/dev/null 2>&1; then | |
| 24 | 24 | less "$installer" | |
| 25 | 25 | else | |
| @@ -35,16 +35,16 @@ For unattended installs, control PATH configuration explicitly: | |||
| 35 | 35 | ||
| 36 | 36 | ```bash | |
| 37 | 37 | # Update supported shell configuration without prompting | |
| 38 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_UPDATE_PATH=1 sh | |
| 38 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=1 sh | |
| 39 | 39 | ||
| 40 | 40 | # Never modify shell configuration | |
| 41 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_UPDATE_PATH=0 sh | |
| 41 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=0 sh | |
| 42 | 42 | ||
| 43 | 43 | # Use another user-local directory | |
| 44 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_INSTALL_DIR="$HOME/bin" GORDON_UPDATE_PATH=1 sh | |
| 44 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR="$HOME/bin" GORDON_UPDATE_PATH=1 sh | |
| 45 | 45 | ||
| 46 | 46 | # Explicit global installation (may request sudo) | |
| 47 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_INSTALL_DIR=/usr/local/bin GORDON_UPDATE_PATH=0 sh | |
| 47 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR=/usr/local/bin GORDON_UPDATE_PATH=0 sh | |
| 48 | 48 | ``` | |
| 49 | 49 | ||
| 50 | 50 | `GORDON_INSTALL_DIR` accepts arbitrary safe absolute destinations, including `"$HOME/bin"`, `"$HOME/.local/bin"`, and `/usr/local/bin`. PATH detection and shell configuration use that effective directory. Relative paths, PATH separators, and control characters are rejected. `GORDON_UPDATE_PATH` accepts only `0` or `1`. Do not run the default installer through `sudo`: it refuses to infer a user home and install silently under `/root`. | |
| @@ -341,13 +341,13 @@ Without this setting, Cloudflare traffic receives `403 Forbidden: Only certifica | |||
| 341 | 341 | ||
| 342 | 342 | ```bash | |
| 343 | 343 | # Install an exact release | |
| 344 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_VERSION=v2.30.1 sh | |
| 344 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_VERSION=v2.30.1 sh | |
| 345 | 345 | ||
| 346 | 346 | # Install the latest pre-release | |
| 347 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_PRERELEASE=1 sh | |
| 347 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_PRERELEASE=1 sh | |
| 348 | 348 | ||
| 349 | 349 | # Build the current next branch commit from source | |
| 350 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_CHANNEL=next sh | |
| 350 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_CHANNEL=next sh | |
| 351 | 351 | ``` | |
| 352 | 352 | ||
| 353 | 353 | Stable, exact-version, and pre-release installs download release binaries and verify their published checksums. The `next` channel is an **unverified development source build**: it resolves the branch through the GitHub API, pins the resulting commit SHA, downloads that exact source snapshot, and builds it locally for the detected platform. It requires the Go version declared by that commit's `go.mod`, is not covered by release checksums, and may be unstable. Do not combine `GORDON_CHANNEL=next` with `GORDON_VERSION` or `GORDON_PRERELEASE`. | |
| @@ -19,7 +19,7 @@ Detailed installation guide for production environments. | |||||
| 19 | set -euo pipefail | 19 | set -euo pipefail | ||
| 20 | installer="$(mktemp)" | 20 | installer="$(mktemp)" | ||
| 21 | trap 'rm -f "$installer"' EXIT | 21 | trap 'rm -f "$installer"' EXIT | ||
| 22 | - | curl -fsSL --output "$installer" https://gordon.bnema.dev/install | 22 | + | curl -fsSL --output "$installer" https://bnema.dev/gordon/install |
| 23 | if command -v less >/dev/null 2>&1; then | 23 | if command -v less >/dev/null 2>&1; then | ||
| 24 | less "$installer" | 24 | less "$installer" | ||
| 25 | else | 25 | else | ||
| @@ -35,16 +35,16 @@ For unattended installs, control PATH configuration explicitly: | |||||
| 35 | 35 | ||||
| 36 | ```bash | 36 | ```bash | ||
| 37 | # Update supported shell configuration without prompting | 37 | # Update supported shell configuration without prompting | ||
| 38 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_UPDATE_PATH=1 sh | 38 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=1 sh |
| 39 | 39 | ||||
| 40 | # Never modify shell configuration | 40 | # Never modify shell configuration | ||
| 41 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_UPDATE_PATH=0 sh | 41 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=0 sh |
| 42 | 42 | ||||
| 43 | # Use another user-local directory | 43 | # Use another user-local directory | ||
| 44 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_INSTALL_DIR="$HOME/bin" GORDON_UPDATE_PATH=1 sh | 44 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR="$HOME/bin" GORDON_UPDATE_PATH=1 sh |
| 45 | 45 | ||||
| 46 | # Explicit global installation (may request sudo) | 46 | # Explicit global installation (may request sudo) | ||
| 47 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_INSTALL_DIR=/usr/local/bin GORDON_UPDATE_PATH=0 sh | 47 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR=/usr/local/bin GORDON_UPDATE_PATH=0 sh |
| 48 | ``` | 48 | ``` | ||
| 49 | 49 | ||||
| 50 | `GORDON_INSTALL_DIR` accepts arbitrary safe absolute destinations, including `"$HOME/bin"`, `"$HOME/.local/bin"`, and `/usr/local/bin`. PATH detection and shell configuration use that effective directory. Relative paths, PATH separators, and control characters are rejected. `GORDON_UPDATE_PATH` accepts only `0` or `1`. Do not run the default installer through `sudo`: it refuses to infer a user home and install silently under `/root`. | 50 | `GORDON_INSTALL_DIR` accepts arbitrary safe absolute destinations, including `"$HOME/bin"`, `"$HOME/.local/bin"`, and `/usr/local/bin`. PATH detection and shell configuration use that effective directory. Relative paths, PATH separators, and control characters are rejected. `GORDON_UPDATE_PATH` accepts only `0` or `1`. Do not run the default installer through `sudo`: it refuses to infer a user home and install silently under `/root`. | ||
| @@ -341,13 +341,13 @@ Without this setting, Cloudflare traffic receives `403 Forbidden: Only certifica | |||||
| 341 | 341 | ||||
| 342 | ```bash | 342 | ```bash | ||
| 343 | # Install an exact release | 343 | # Install an exact release | ||
| 344 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_VERSION=v2.30.1 sh | 344 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_VERSION=v2.30.1 sh |
| 345 | 345 | ||||
| 346 | # Install the latest pre-release | 346 | # Install the latest pre-release | ||
| 347 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_PRERELEASE=1 sh | 347 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_PRERELEASE=1 sh |
| 348 | 348 | ||||
| 349 | # Build the current next branch commit from source | 349 | # Build the current next branch commit from source | ||
| 350 | - | curl -fsSL https://gordon.bnema.dev/install | GORDON_CHANNEL=next sh | 350 | + | curl -fsSL https://bnema.dev/gordon/install | GORDON_CHANNEL=next sh |
| 351 | ``` | 351 | ``` | ||
| 352 | 352 | ||||
| 353 | Stable, exact-version, and pre-release installs download release binaries and verify their published checksums. The `next` channel is an **unverified development source build**: it resolves the branch through the GitHub API, pins the resulting commit SHA, downloads that exact source snapshot, and builds it locally for the detected platform. It requires the Go version declared by that commit's `go.mod`, is not covered by release checksums, and may be unstable. Do not combine `GORDON_CHANNEL=next` with `GORDON_VERSION` or `GORDON_PRERELEASE`. | 353 | Stable, exact-version, and pre-release installs download release binaries and verify their published checksums. The `next` channel is an **unverified development source build**: it resolves the branch through the GitHub API, pins the resulting commit SHA, downloads that exact source snapshot, and builds it locally for the detected platform. It requires the Go version declared by that commit's `go.mod`, is not covered by release checksums, and may be unstable. Do not combine `GORDON_CHANNEL=next` with `GORDON_VERSION` or `GORDON_PRERELEASE`. | ||
R docs/migrate-to-v2.50.md → docs/migrate-to-v3.md +11 -11 renamed, 86% similar
| @@ -1,8 +1,8 @@ | |||
| 1 | - | # Migrate to Gordon v2.50 | |
| 1 | + | # Migrate to Gordon v3 | |
| 2 | 2 | ||
| 3 | - | Gordon v2.50 replaces domain-based route workloads with declarative apps. The upgrade is intentionally explicit: Gordon does not infer app ownership from domains, does not adopt existing volumes, and does not copy domain secrets into app secrets automatically. | |
| 3 | + | Gordon v3 replaces domain-based route workloads with declarative apps. The upgrade is intentionally explicit: Gordon does not infer app ownership from domains, does not adopt existing volumes, and does not copy domain secrets into app secrets automatically. | |
| 4 | 4 | ||
| 5 | - | Use this guide before starting the v2.50 daemon with production traffic. | |
| 5 | + | Use this guide before starting the v3 daemon with production traffic. | |
| 6 | 6 | ||
| 7 | 7 | ## Before the upgrade | |
| 8 | 8 | ||
| @@ -15,7 +15,7 @@ Do not delete old containers, volumes, pass entries, or registry tags during the | |||
| 15 | 15 | ||
| 16 | 16 | ## 1. Update the installation configuration | |
| 17 | 17 | ||
| 18 | - | Remove workload declarations that v2.50 no longer accepts from `gordon.toml`: | |
| 18 | + | Remove workload declarations that v3 no longer accepts from `gordon.toml`: | |
| 19 | 19 | ||
| 20 | 20 | - `[routes]`; | |
| 21 | 21 | - `[attachments]`; | |
| @@ -26,7 +26,7 @@ Remove workload declarations that v2.50 no longer accepts from `gordon.toml`: | |||
| 26 | 26 | ||
| 27 | 27 | Keep installation-level settings such as entrypoints, TLS, limits, registry policy, external routes, backup destinations, logging, and authentication. | |
| 28 | 28 | ||
| 29 | - | Review every app image registry before applying manifests. v2.50 allows Docker Hub (`docker.io`, including its canonical pull host `registry-1.docker.io`), `ghcr.io`, `quay.io`, and Gordon's configured registry by default. Add each other registry, including private registries, as an exact hostname and optional non-default port: | |
| 29 | + | Review every app image registry before applying manifests. v3 allows Docker Hub (`docker.io`, including its canonical pull host `registry-1.docker.io`), `ghcr.io`, `quay.io`, and Gordon's configured registry by default. Add each other registry, including private registries, as an exact hostname and optional non-default port: | |
| 30 | 30 | ||
| 31 | 31 | ```toml | |
| 32 | 32 | [images] | |
| @@ -42,7 +42,7 @@ name = "example-app" | |||
| 42 | 42 | ||
| 43 | 43 | [[service]] | |
| 44 | 44 | name = "web" | |
| 45 | - | image = "registry.example.com/example-app:v2.50.0" | |
| 45 | + | image = "registry.example.com/example-app:1.2.3" | |
| 46 | 46 | ||
| 47 | 47 | [service.secrets] | |
| 48 | 48 | DATABASE_URL = "database-url" | |
| @@ -85,7 +85,7 @@ gordon apps deploy example-app --remote production | |||
| 85 | 85 | gordon apps status example-app --json --remote production | |
| 86 | 86 | ``` | |
| 87 | 87 | ||
| 88 | - | Push only uploads OCI content in v2.50; it does not deploy. Apply and deploy explicitly. | |
| 88 | + | Push only uploads OCI content in v3; it does not deploy. Apply and deploy explicitly. | |
| 89 | 89 | ||
| 90 | 90 | ## 5. Replace tokens and automation | |
| 91 | 91 | ||
| @@ -96,7 +96,7 @@ Replace removed route scopes with app scopes: | |||
| 96 | 96 | ||
| 97 | 97 | Generate replacement CI and operator tokens with the minimum required scopes. Update automation that expected push-to-deploy, route mutation commands, previews, attachments, bootstrap, autoroute, pin, or rollback commands. | |
| 98 | 98 | ||
| 99 | - | To roll back an application release in v2.50, apply a manifest containing the previous image tag and deploy it. | |
| 99 | + | To roll back an application release in v3, apply a manifest containing the previous image tag and deploy it. | |
| 100 | 100 | ||
| 101 | 101 | ## 6. Validate before opening traffic | |
| 102 | 102 | ||
| @@ -125,16 +125,16 @@ Run destructive prune commands only after their dry-run candidate list matches t | |||
| 125 | 125 | ||
| 126 | 126 | ## Rollback | |
| 127 | 127 | ||
| 128 | - | A binary downgrade against v2.50 app state is unsupported. To roll back: | |
| 128 | + | A binary downgrade against v3 app state is unsupported. To roll back: | |
| 129 | 129 | ||
| 130 | - | 1. stop the v2.50 daemon; | |
| 130 | + | 1. stop the v3 daemon; | |
| 131 | 131 | 2. restore the previous signed binary; | |
| 132 | 132 | 3. restore its matching configuration and state backup as one set; | |
| 133 | 133 | 4. restore secret-store entries if any were removed; | |
| 134 | 134 | 5. restart with automatic pruning disabled; | |
| 135 | 135 | 6. verify workloads and data before reopening traffic. | |
| 136 | 136 | ||
| 137 | - | Do not attempt rollback by adopting unknown containers or volumes into v2.50 state. | |
| 137 | + | Do not attempt rollback by adopting unknown containers or volumes into v3 state. | |
| 138 | 138 | ||
| 139 | 139 | ## Related | |
| 140 | 140 | ||
| @@ -1,8 +1,8 @@ | |||||
| 1 | - | # Migrate to Gordon v2.50 | 1 | + | # Migrate to Gordon v3 |
| 2 | 2 | ||||
| 3 | - | Gordon v2.50 replaces domain-based route workloads with declarative apps. The upgrade is intentionally explicit: Gordon does not infer app ownership from domains, does not adopt existing volumes, and does not copy domain secrets into app secrets automatically. | 3 | + | Gordon v3 replaces domain-based route workloads with declarative apps. The upgrade is intentionally explicit: Gordon does not infer app ownership from domains, does not adopt existing volumes, and does not copy domain secrets into app secrets automatically. |
| 4 | 4 | ||||
| 5 | - | Use this guide before starting the v2.50 daemon with production traffic. | 5 | + | Use this guide before starting the v3 daemon with production traffic. |
| 6 | 6 | ||||
| 7 | ## Before the upgrade | 7 | ## Before the upgrade | ||
| 8 | 8 | ||||
| @@ -15,7 +15,7 @@ Do not delete old containers, volumes, pass entries, or registry tags during the | |||||
| 15 | 15 | ||||
| 16 | ## 1. Update the installation configuration | 16 | ## 1. Update the installation configuration | ||
| 17 | 17 | ||||
| 18 | - | Remove workload declarations that v2.50 no longer accepts from `gordon.toml`: | 18 | + | Remove workload declarations that v3 no longer accepts from `gordon.toml`: |
| 19 | 19 | ||||
| 20 | - `[routes]`; | 20 | - `[routes]`; | ||
| 21 | - `[attachments]`; | 21 | - `[attachments]`; | ||
| @@ -26,7 +26,7 @@ Remove workload declarations that v2.50 no longer accepts from `gordon.toml`: | |||||
| 26 | 26 | ||||
| 27 | Keep installation-level settings such as entrypoints, TLS, limits, registry policy, external routes, backup destinations, logging, and authentication. | 27 | Keep installation-level settings such as entrypoints, TLS, limits, registry policy, external routes, backup destinations, logging, and authentication. | ||
| 28 | 28 | ||||
| 29 | - | Review every app image registry before applying manifests. v2.50 allows Docker Hub (`docker.io`, including its canonical pull host `registry-1.docker.io`), `ghcr.io`, `quay.io`, and Gordon's configured registry by default. Add each other registry, including private registries, as an exact hostname and optional non-default port: | 29 | + | Review every app image registry before applying manifests. v3 allows Docker Hub (`docker.io`, including its canonical pull host `registry-1.docker.io`), `ghcr.io`, `quay.io`, and Gordon's configured registry by default. Add each other registry, including private registries, as an exact hostname and optional non-default port: |
| 30 | 30 | ||||
| 31 | ```toml | 31 | ```toml | ||
| 32 | [images] | 32 | [images] | ||
| @@ -42,7 +42,7 @@ name = "example-app" | |||||
| 42 | 42 | ||||
| 43 | [[service]] | 43 | [[service]] | ||
| 44 | name = "web" | 44 | name = "web" | ||
| 45 | - | image = "registry.example.com/example-app:v2.50.0" | 45 | + | image = "registry.example.com/example-app:1.2.3" |
| 46 | 46 | ||||
| 47 | [service.secrets] | 47 | [service.secrets] | ||
| 48 | DATABASE_URL = "database-url" | 48 | DATABASE_URL = "database-url" | ||
| @@ -85,7 +85,7 @@ gordon apps deploy example-app --remote production | |||||
| 85 | gordon apps status example-app --json --remote production | 85 | gordon apps status example-app --json --remote production | ||
| 86 | ``` | 86 | ``` | ||
| 87 | 87 | ||||
| 88 | - | Push only uploads OCI content in v2.50; it does not deploy. Apply and deploy explicitly. | 88 | + | Push only uploads OCI content in v3; it does not deploy. Apply and deploy explicitly. |
| 89 | 89 | ||||
| 90 | ## 5. Replace tokens and automation | 90 | ## 5. Replace tokens and automation | ||
| 91 | 91 | ||||
| @@ -96,7 +96,7 @@ Replace removed route scopes with app scopes: | |||||
| 96 | 96 | ||||
| 97 | Generate replacement CI and operator tokens with the minimum required scopes. Update automation that expected push-to-deploy, route mutation commands, previews, attachments, bootstrap, autoroute, pin, or rollback commands. | 97 | Generate replacement CI and operator tokens with the minimum required scopes. Update automation that expected push-to-deploy, route mutation commands, previews, attachments, bootstrap, autoroute, pin, or rollback commands. | ||
| 98 | 98 | ||||
| 99 | - | To roll back an application release in v2.50, apply a manifest containing the previous image tag and deploy it. | 99 | + | To roll back an application release in v3, apply a manifest containing the previous image tag and deploy it. |
| 100 | 100 | ||||
| 101 | ## 6. Validate before opening traffic | 101 | ## 6. Validate before opening traffic | ||
| 102 | 102 | ||||
| @@ -125,16 +125,16 @@ Run destructive prune commands only after their dry-run candidate list matches t | |||||
| 125 | 125 | ||||
| 126 | ## Rollback | 126 | ## Rollback | ||
| 127 | 127 | ||||
| 128 | - | A binary downgrade against v2.50 app state is unsupported. To roll back: | 128 | + | A binary downgrade against v3 app state is unsupported. To roll back: |
| 129 | 129 | ||||
| 130 | - | 1. stop the v2.50 daemon; | 130 | + | 1. stop the v3 daemon; |
| 131 | 2. restore the previous signed binary; | 131 | 2. restore the previous signed binary; | ||
| 132 | 3. restore its matching configuration and state backup as one set; | 132 | 3. restore its matching configuration and state backup as one set; | ||
| 133 | 4. restore secret-store entries if any were removed; | 133 | 4. restore secret-store entries if any were removed; | ||
| 134 | 5. restart with automatic pruning disabled; | 134 | 5. restart with automatic pruning disabled; | ||
| 135 | 6. verify workloads and data before reopening traffic. | 135 | 6. verify workloads and data before reopening traffic. | ||
| 136 | 136 | ||||
| 137 | - | Do not attempt rollback by adopting unknown containers or volumes into v2.50 state. | 137 | + | Do not attempt rollback by adopting unknown containers or volumes into v3 state. |
| 138 | 138 | ||||
| 139 | ## Related | 139 | ## Related | ||
| 140 | 140 | ||||
M docs/reference/docker-labels.md +4 -4
| @@ -18,13 +18,13 @@ Queries by logical identity use labels, never name parsing. Resources without th | |||
| 18 | 18 | ||
| 19 | 19 | ### Legacy Labels | |
| 20 | 20 | ||
| 21 | - | Containers created before v2.50 may carry these labels. They are read-only provenance hints for prune guards — Gordon never infers app state from them: | |
| 21 | + | Containers created before v3 may carry these labels. They are read-only provenance hints for prune guards — Gordon never infers app state from them: | |
| 22 | 22 | ||
| 23 | 23 | | Label | Value | Description | | |
| 24 | 24 | |-------|-------|-------------| | |
| 25 | - | | `gordon.domain` | Domain name | Pre-v2.50 domain this container served | | |
| 25 | + | | `gordon.domain` | Domain name | Pre-v3 domain this container served | | |
| 26 | 26 | | `gordon.image` | Image:tag | Original image from configuration | | |
| 27 | - | | `gordon.route` | Domain name | Pre-v2.50 route this container handled | | |
| 27 | + | | `gordon.route` | Domain name | Pre-v3 route this container handled | | |
| 28 | 28 | ||
| 29 | 29 | ### Backup Metadata | |
| 30 | 30 | ||
| @@ -32,7 +32,7 @@ Backups are declarative rather than label-driven. App manifests declare database | |||
| 32 | 32 | ||
| 33 | 33 | ## Image Labels | |
| 34 | 34 | ||
| 35 | - | No image-label inference exists in v2.50: Gordon never creates routes, deploys, or resolves image names from Dockerfile labels. Push with a domain-like name or a `gordon.domain` label is treated as an ordinary image name. Readiness and proxy ports come from the app manifest (`[service.readiness]`, `[[service.http]]`), not from image labels. | |
| 35 | + | No image-label inference exists in v3: Gordon never creates routes, deploys, or resolves image names from Dockerfile labels. Push with a domain-like name or a `gordon.domain` label is treated as an ordinary image name. Readiness and proxy ports come from the app manifest (`[service.readiness]`, `[[service.http]]`), not from image labels. | |
| 36 | 36 | ||
| 37 | 37 | ## Container Naming | |
| 38 | 38 | ||
| @@ -18,13 +18,13 @@ Queries by logical identity use labels, never name parsing. Resources without th | |||||
| 18 | 18 | ||||
| 19 | ### Legacy Labels | 19 | ### Legacy Labels | ||
| 20 | 20 | ||||
| 21 | - | Containers created before v2.50 may carry these labels. They are read-only provenance hints for prune guards — Gordon never infers app state from them: | 21 | + | Containers created before v3 may carry these labels. They are read-only provenance hints for prune guards — Gordon never infers app state from them: |
| 22 | 22 | ||||
| 23 | | Label | Value | Description | | 23 | | Label | Value | Description | | ||
| 24 | |-------|-------|-------------| | 24 | |-------|-------|-------------| | ||
| 25 | - | | `gordon.domain` | Domain name | Pre-v2.50 domain this container served | | 25 | + | | `gordon.domain` | Domain name | Pre-v3 domain this container served | |
| 26 | | `gordon.image` | Image:tag | Original image from configuration | | 26 | | `gordon.image` | Image:tag | Original image from configuration | | ||
| 27 | - | | `gordon.route` | Domain name | Pre-v2.50 route this container handled | | 27 | + | | `gordon.route` | Domain name | Pre-v3 route this container handled | |
| 28 | 28 | ||||
| 29 | ### Backup Metadata | 29 | ### Backup Metadata | ||
| 30 | 30 | ||||
| @@ -32,7 +32,7 @@ Backups are declarative rather than label-driven. App manifests declare database | |||||
| 32 | 32 | ||||
| 33 | ## Image Labels | 33 | ## Image Labels | ||
| 34 | 34 | ||||
| 35 | - | No image-label inference exists in v2.50: Gordon never creates routes, deploys, or resolves image names from Dockerfile labels. Push with a domain-like name or a `gordon.domain` label is treated as an ordinary image name. Readiness and proxy ports come from the app manifest (`[service.readiness]`, `[[service.http]]`), not from image labels. | 35 | + | No image-label inference exists in v3: Gordon never creates routes, deploys, or resolves image names from Dockerfile labels. Push with a domain-like name or a `gordon.domain` label is treated as an ordinary image name. Readiness and proxy ports come from the app manifest (`[service.readiness]`, `[[service.http]]`), not from image labels. |
| 36 | 36 | ||||
| 37 | ## Container Naming | 37 | ## Container Naming | ||
| 38 | 38 | ||||
M docs/upgrading.md +8 -28
| @@ -2,11 +2,11 @@ | |||
| 2 | 2 | ||
| 3 | 3 | This guide covers breaking changes and migration steps between major versions. | |
| 4 | 4 | ||
| 5 | - | ## v2.50.0: Declarative Apps (breaking) | |
| 5 | + | ## v3.0.0: Declarative Apps (breaking) | |
| 6 | 6 | ||
| 7 | - | v2.50 replaces route-container management with declarative apps. One standalone TOML file defines one app; `gordon apps apply` persists desired state and `gordon apps deploy` activates it. Push transfers OCI content only and never deploys. | |
| 7 | + | Gordon v3 replaces route-container management with declarative apps. One standalone TOML file defines one app; `gordon apps apply` persists desired state and `gordon apps deploy` activates it. Push transfers OCI content only and never deploys. | |
| 8 | 8 | ||
| 9 | - | Follow [Migrate to Gordon v2.50](./migrate-to-v2.50.md) for the complete cutover procedure, including explicit migration from domain-scoped secrets to app- and service-scoped secrets. | |
| 9 | + | Follow [Migrate to Gordon v3](./migrate-to-v3.md) for the complete cutover procedure, including explicit migration from domain-scoped secrets to app- and service-scoped secrets. | |
| 10 | 10 | ||
| 11 | 11 | ### Removed | |
| 12 | 12 | ||
| @@ -20,7 +20,7 @@ Follow [Migrate to Gordon v2.50](./migrate-to-v2.50.md) for the complete cutover | |||
| 20 | 20 | 1. Back up databases/volumes and pass entries with the existing procedures. Record original ownership and image versions. No update hook deletes volumes: unknown resources are preserved, never adopted. | |
| 21 | 21 | 2. Delete the removed keys from `gordon.toml` (installation settings only: entrypoints, TLS, limits, external routes, images policy, backups destinations stay). | |
| 22 | 22 | 3. Write one `<app>.toml` per app (see [App Manifest](./config/apps.md)): services, `[[service.http]]` hosts, `[service.secrets]` names, volumes, `[[network.shared]]`, backup declarations. | |
| 23 | - | 4. Migrate secret values explicitly with `gordon apps secrets set` after applying each manifest. Gordon does not copy `gordon/env/<domain>/...` entries into `gordon/apps/<uuid>/<service>/...`; follow the [v2.50 secrets migration procedure](./migrate-to-v2.50.md#2-migrate-domain-secrets). | |
| 23 | + | 4. Migrate secret values explicitly with `gordon apps secrets set` after applying each manifest. Gordon does not copy `gordon/env/<domain>/...` entries into `gordon/apps/<uuid>/<service>/...`; follow the [v3 secrets migration procedure](./migrate-to-v3.md#2-migrate-domain-secrets). | |
| 24 | 24 | 5. `gordon apps apply --file <app>.toml`, then `gordon apps deploy <app>`. | |
| 25 | 25 | 6. Staging is an ordinary app in another file. A binary downgrade against the new app-state format is unsupported: restore the old installation/config/state and backups through an operator-approved procedure. | |
| 26 | 26 | ||
| @@ -28,7 +28,7 @@ Follow [Migrate to Gordon v2.50](./migrate-to-v2.50.md) for the complete cutover | |||
| 28 | 28 | ||
| 29 | 29 | Route keys must be plain hostnames. Use inline tables like `"app.example.com" = { image = "myapp:latest" }`. Gordon still reads legacy `http://...` route entries for backward compatibility and rewrites them on the next save. Update `[routes]`, CLI commands, and automation that reference the old values. | |
| 30 | 30 | ||
| 31 | - | ## Next major: Unified smart TCP entrypoints | |
| 31 | + | ## v2.31.0: Unified smart TCP entrypoints | |
| 32 | 32 | ||
| 33 | 33 | ### Breaking: `server.port` / `server.tls_port` no longer define public listeners | |
| 34 | 34 | ||
| @@ -81,26 +81,6 @@ Keep `server.registry_port` for Docker/Podman push and pull traffic; it is separ | |||
| 81 | 81 | - TLS-ALPN-01 is unsupported. | |
| 82 | 82 | - Normal HTTPS fallback certificate priority is static certificates, then public ACME certificates, then Gordon's internal CA. | |
| 83 | 83 | ||
| 84 | - | ## v2.30.0 to v2.31.0 | |
| 85 | - | ||
| 86 | - | ### Breaking: Public listener migration | |
| 87 | - | ||
| 88 | - | `server.port` and `server.tls_port` no longer create public listeners. Gordon refuses to start when either legacy key is present without an `[entrypoints]` entry, preventing routes from silently becoming unavailable. | |
| 89 | - | ||
| 90 | - | Replace the legacy listener settings with a route-capable entrypoint: | |
| 91 | - | ||
| 92 | - | ```toml | |
| 93 | - | [server] | |
| 94 | - | registry_port = 5000 | |
| 95 | - | gordon_domain = "gordon.example.com" | |
| 96 | - | ||
| 97 | - | [entrypoints.edge] | |
| 98 | - | address = ":443" | |
| 99 | - | protocol = "smart_tcp" | |
| 100 | - | ``` | |
| 101 | - | ||
| 102 | - | Keep `server.registry_port` for Docker and Podman registry traffic. For public TLS, configure `[tls.acme]` or static certificates; do not use `server.tls_port`. | |
| 103 | - | ||
| 104 | 84 | ### Required for Cloudflare/Proxy Setups: `proxy_allowed_ips` | |
| 105 | 85 | ||
| 106 | 86 | The internal CA's HTTP onboarding gate rejects non-localhost HTTP requests by default. If Gordon sits behind Cloudflare or another reverse proxy, add the proxy's edge IPs to `proxy_allowed_ips`: | |
| @@ -284,7 +264,7 @@ Gordon v2.30.0 removes password-based authentication entirely. Only token-based | |||
| 284 | 264 | 5. **Upgrade the binary** and restart: | |
| 285 | 265 | ||
| 286 | 266 | ```bash | |
| 287 | - | curl -fsSL https://gordon.bnema.dev/install | bash | |
| 267 | + | curl -fsSL https://bnema.dev/gordon/install | bash | |
| 288 | 268 | systemctl --user restart gordon | |
| 289 | 269 | ``` | |
| 290 | 270 | ||
| @@ -455,7 +435,7 @@ If using pass or sops, update your secret paths: | |||
| 455 | 435 | 3. **Test in staging** if possible | |
| 456 | 436 | 4. **Upgrade the binary**: | |
| 457 | 437 | ```bash | |
| 458 | - | curl -fsSL https://gordon.bnema.dev/install | bash | |
| 438 | + | curl -fsSL https://bnema.dev/gordon/install | bash | |
| 459 | 439 | ``` | |
| 460 | 440 | 5. **Restart Gordon**: | |
| 461 | 441 | ```bash | |
| @@ -469,4 +449,4 @@ If using pass or sops, update your secret paths: | |||
| 469 | 449 | ## Getting Help | |
| 470 | 450 | ||
| 471 | 451 | - [GitHub Issues](https://github.com/bnema/gordon/issues) | |
| 472 | - | - [Documentation](https://gordon.bnema.dev/docs) | |
| 452 | + | - [Documentation](https://bnema.dev/gordon/docs) | |
| @@ -2,11 +2,11 @@ | |||||
| 2 | 2 | ||||
| 3 | This guide covers breaking changes and migration steps between major versions. | 3 | This guide covers breaking changes and migration steps between major versions. | ||
| 4 | 4 | ||||
| 5 | - | ## v2.50.0: Declarative Apps (breaking) | 5 | + | ## v3.0.0: Declarative Apps (breaking) |
| 6 | 6 | ||||
| 7 | - | v2.50 replaces route-container management with declarative apps. One standalone TOML file defines one app; `gordon apps apply` persists desired state and `gordon apps deploy` activates it. Push transfers OCI content only and never deploys. | 7 | + | Gordon v3 replaces route-container management with declarative apps. One standalone TOML file defines one app; `gordon apps apply` persists desired state and `gordon apps deploy` activates it. Push transfers OCI content only and never deploys. |
| 8 | 8 | ||||
| 9 | - | Follow [Migrate to Gordon v2.50](./migrate-to-v2.50.md) for the complete cutover procedure, including explicit migration from domain-scoped secrets to app- and service-scoped secrets. | 9 | + | Follow [Migrate to Gordon v3](./migrate-to-v3.md) for the complete cutover procedure, including explicit migration from domain-scoped secrets to app- and service-scoped secrets. |
| 10 | 10 | ||||
| 11 | ### Removed | 11 | ### Removed | ||
| 12 | 12 | ||||
| @@ -20,7 +20,7 @@ Follow [Migrate to Gordon v2.50](./migrate-to-v2.50.md) for the complete cutover | |||||
| 20 | 1. Back up databases/volumes and pass entries with the existing procedures. Record original ownership and image versions. No update hook deletes volumes: unknown resources are preserved, never adopted. | 20 | 1. Back up databases/volumes and pass entries with the existing procedures. Record original ownership and image versions. No update hook deletes volumes: unknown resources are preserved, never adopted. | ||
| 21 | 2. Delete the removed keys from `gordon.toml` (installation settings only: entrypoints, TLS, limits, external routes, images policy, backups destinations stay). | 21 | 2. Delete the removed keys from `gordon.toml` (installation settings only: entrypoints, TLS, limits, external routes, images policy, backups destinations stay). | ||
| 22 | 3. Write one `<app>.toml` per app (see [App Manifest](./config/apps.md)): services, `[[service.http]]` hosts, `[service.secrets]` names, volumes, `[[network.shared]]`, backup declarations. | 22 | 3. Write one `<app>.toml` per app (see [App Manifest](./config/apps.md)): services, `[[service.http]]` hosts, `[service.secrets]` names, volumes, `[[network.shared]]`, backup declarations. | ||
| 23 | - | 4. Migrate secret values explicitly with `gordon apps secrets set` after applying each manifest. Gordon does not copy `gordon/env/<domain>/...` entries into `gordon/apps/<uuid>/<service>/...`; follow the [v2.50 secrets migration procedure](./migrate-to-v2.50.md#2-migrate-domain-secrets). | 23 | + | 4. Migrate secret values explicitly with `gordon apps secrets set` after applying each manifest. Gordon does not copy `gordon/env/<domain>/...` entries into `gordon/apps/<uuid>/<service>/...`; follow the [v3 secrets migration procedure](./migrate-to-v3.md#2-migrate-domain-secrets). |
| 24 | 5. `gordon apps apply --file <app>.toml`, then `gordon apps deploy <app>`. | 24 | 5. `gordon apps apply --file <app>.toml`, then `gordon apps deploy <app>`. | ||
| 25 | 6. Staging is an ordinary app in another file. A binary downgrade against the new app-state format is unsupported: restore the old installation/config/state and backups through an operator-approved procedure. | 25 | 6. Staging is an ordinary app in another file. A binary downgrade against the new app-state format is unsupported: restore the old installation/config/state and backups through an operator-approved procedure. | ||
| 26 | 26 | ||||
| @@ -28,7 +28,7 @@ Follow [Migrate to Gordon v2.50](./migrate-to-v2.50.md) for the complete cutover | |||||
| 28 | 28 | ||||
| 29 | Route keys must be plain hostnames. Use inline tables like `"app.example.com" = { image = "myapp:latest" }`. Gordon still reads legacy `http://...` route entries for backward compatibility and rewrites them on the next save. Update `[routes]`, CLI commands, and automation that reference the old values. | 29 | Route keys must be plain hostnames. Use inline tables like `"app.example.com" = { image = "myapp:latest" }`. Gordon still reads legacy `http://...` route entries for backward compatibility and rewrites them on the next save. Update `[routes]`, CLI commands, and automation that reference the old values. | ||
| 30 | 30 | ||||
| 31 | - | ## Next major: Unified smart TCP entrypoints | 31 | + | ## v2.31.0: Unified smart TCP entrypoints |
| 32 | 32 | ||||
| 33 | ### Breaking: `server.port` / `server.tls_port` no longer define public listeners | 33 | ### Breaking: `server.port` / `server.tls_port` no longer define public listeners | ||
| 34 | 34 | ||||
| @@ -81,26 +81,6 @@ Keep `server.registry_port` for Docker/Podman push and pull traffic; it is separ | |||||
| 81 | - TLS-ALPN-01 is unsupported. | 81 | - TLS-ALPN-01 is unsupported. | ||
| 82 | - Normal HTTPS fallback certificate priority is static certificates, then public ACME certificates, then Gordon's internal CA. | 82 | - Normal HTTPS fallback certificate priority is static certificates, then public ACME certificates, then Gordon's internal CA. | ||
| 83 | 83 | ||||
| 84 | - | ## v2.30.0 to v2.31.0 | |||
| 85 | - | ||||
| 86 | - | ### Breaking: Public listener migration | |||
| 87 | - | ||||
| 88 | - | `server.port` and `server.tls_port` no longer create public listeners. Gordon refuses to start when either legacy key is present without an `[entrypoints]` entry, preventing routes from silently becoming unavailable. | |||
| 89 | - | ||||
| 90 | - | Replace the legacy listener settings with a route-capable entrypoint: | |||
| 91 | - | ||||
| 92 | - | ```toml | |||
| 93 | - | [server] | |||
| 94 | - | registry_port = 5000 | |||
| 95 | - | gordon_domain = "gordon.example.com" | |||
| 96 | - | ||||
| 97 | - | [entrypoints.edge] | |||
| 98 | - | address = ":443" | |||
| 99 | - | protocol = "smart_tcp" | |||
| 100 | - | ``` | |||
| 101 | - | ||||
| 102 | - | Keep `server.registry_port` for Docker and Podman registry traffic. For public TLS, configure `[tls.acme]` or static certificates; do not use `server.tls_port`. | |||
| 103 | - | ||||
| 104 | ### Required for Cloudflare/Proxy Setups: `proxy_allowed_ips` | 84 | ### Required for Cloudflare/Proxy Setups: `proxy_allowed_ips` | ||
| 105 | 85 | ||||
| 106 | The internal CA's HTTP onboarding gate rejects non-localhost HTTP requests by default. If Gordon sits behind Cloudflare or another reverse proxy, add the proxy's edge IPs to `proxy_allowed_ips`: | 86 | The internal CA's HTTP onboarding gate rejects non-localhost HTTP requests by default. If Gordon sits behind Cloudflare or another reverse proxy, add the proxy's edge IPs to `proxy_allowed_ips`: | ||
| @@ -284,7 +264,7 @@ Gordon v2.30.0 removes password-based authentication entirely. Only token-based | |||||
| 284 | 5. **Upgrade the binary** and restart: | 264 | 5. **Upgrade the binary** and restart: | ||
| 285 | 265 | ||||
| 286 | ```bash | 266 | ```bash | ||
| 287 | - | curl -fsSL https://gordon.bnema.dev/install | bash | 267 | + | curl -fsSL https://bnema.dev/gordon/install | bash |
| 288 | systemctl --user restart gordon | 268 | systemctl --user restart gordon | ||
| 289 | ``` | 269 | ``` | ||
| 290 | 270 | ||||
| @@ -455,7 +435,7 @@ If using pass or sops, update your secret paths: | |||||
| 455 | 3. **Test in staging** if possible | 435 | 3. **Test in staging** if possible | ||
| 456 | 4. **Upgrade the binary**: | 436 | 4. **Upgrade the binary**: | ||
| 457 | ```bash | 437 | ```bash | ||
| 458 | - | curl -fsSL https://gordon.bnema.dev/install | bash | 438 | + | curl -fsSL https://bnema.dev/gordon/install | bash |
| 459 | ``` | 439 | ``` | ||
| 460 | 5. **Restart Gordon**: | 440 | 5. **Restart Gordon**: | ||
| 461 | ```bash | 441 | ```bash | ||
| @@ -469,4 +449,4 @@ If using pass or sops, update your secret paths: | |||||
| 469 | ## Getting Help | 449 | ## Getting Help | ||
| 470 | 450 | ||||
| 471 | - [GitHub Issues](https://github.com/bnema/gordon/issues) | 451 | - [GitHub Issues](https://github.com/bnema/gordon/issues) | ||
| 472 | - | - [Documentation](https://gordon.bnema.dev/docs) | 452 | + | - [Documentation](https://bnema.dev/gordon/docs) |
M gordon.toml.example +1 -1
| @@ -192,7 +192,7 @@ keep = 14 | |||
| 192 | 192 | [external_routes] | |
| 193 | 193 | # "status.example.com" = "127.0.0.1:9000" | |
| 194 | 194 | # | |
| 195 | - | # NOTE: the pre-v2.50 application keys below were removed by the | |
| 195 | + | # NOTE: the pre-v3 application keys below were removed by the | |
| 196 | 196 | # declarative-apps cutover. Gordon fails boot/reload closed when any of | |
| 197 | 197 | # them is present (see validateRetiredAppConfig in internal/app/run.go). | |
| 198 | 198 | # Declare application workloads in standalone <app>.toml files instead: | |
| @@ -192,7 +192,7 @@ keep = 14 | |||||
| 192 | [external_routes] | 192 | [external_routes] | ||
| 193 | # "status.example.com" = "127.0.0.1:9000" | 193 | # "status.example.com" = "127.0.0.1:9000" | ||
| 194 | # | 194 | # | ||
| 195 | - | # NOTE: the pre-v2.50 application keys below were removed by the | 195 | + | # NOTE: the pre-v3 application keys below were removed by the |
| 196 | # declarative-apps cutover. Gordon fails boot/reload closed when any of | 196 | # declarative-apps cutover. Gordon fails boot/reload closed when any of | ||
| 197 | # them is present (see validateRetiredAppConfig in internal/app/run.go). | 197 | # them is present (see validateRetiredAppConfig in internal/app/run.go). | ||
| 198 | # Declare application workloads in standalone <app>.toml files instead: | 198 | # Declare application workloads in standalone <app>.toml files instead: | ||
M install.sh +3 -3
| @@ -2,9 +2,9 @@ | |||
| 2 | 2 | set -e | |
| 3 | 3 | ||
| 4 | 4 | # Gordon installer script | |
| 5 | - | # Usage: curl -fsSL https://gordon.bnema.dev/install | sh | |
| 6 | - | # Usage with pre-release: curl -fsSL https://gordon.bnema.dev/install | GORDON_PRERELEASE=1 sh | |
| 7 | - | # Usage with next source build: curl -fsSL https://gordon.bnema.dev/install | GORDON_CHANNEL=next sh | |
| 5 | + | # Usage: curl -fsSL https://bnema.dev/gordon/install | sh | |
| 6 | + | # Usage with pre-release: curl -fsSL https://bnema.dev/gordon/install | GORDON_PRERELEASE=1 sh | |
| 7 | + | # Usage with next source build: curl -fsSL https://bnema.dev/gordon/install | GORDON_CHANNEL=next sh | |
| 8 | 8 | ||
| 9 | 9 | REPO="bnema/gordon" | |
| 10 | 10 | VERSION="${GORDON_VERSION:-latest}" | |
| @@ -2,9 +2,9 @@ | |||||
| 2 | set -e | 2 | set -e | ||
| 3 | 3 | ||||
| 4 | # Gordon installer script | 4 | # Gordon installer script | ||
| 5 | - | # Usage: curl -fsSL https://gordon.bnema.dev/install | sh | 5 | + | # Usage: curl -fsSL https://bnema.dev/gordon/install | sh |
| 6 | - | # Usage with pre-release: curl -fsSL https://gordon.bnema.dev/install | GORDON_PRERELEASE=1 sh | 6 | + | # Usage with pre-release: curl -fsSL https://bnema.dev/gordon/install | GORDON_PRERELEASE=1 sh |
| 7 | - | # Usage with next source build: curl -fsSL https://gordon.bnema.dev/install | GORDON_CHANNEL=next sh | 7 | + | # Usage with next source build: curl -fsSL https://bnema.dev/gordon/install | GORDON_CHANNEL=next sh |
| 8 | 8 | ||||
| 9 | REPO="bnema/gordon" | 9 | REPO="bnema/gordon" | ||
| 10 | VERSION="${GORDON_VERSION:-latest}" | 10 | VERSION="${GORDON_VERSION:-latest}" | ||
M internal/adapters/dto/admin_apps.go +1 -1
| @@ -8,7 +8,7 @@ import "time" | |||
| 8 | 8 | // change from ErrorResponse for app mutations; clients accept both | |
| 9 | 9 | // during the mixed-version window. | |
| 10 | 10 | ||
| 11 | - | // AppError is the v2.50 app-mutation error envelope. Its stable fields are | |
| 11 | + | // AppError is the v3 app-mutation error envelope. Its stable fields are | |
| 12 | 12 | // error/message/cause/hint. | |
| 13 | 13 | // `logs` never appears on mutations. Clients accept the legacy | |
| 14 | 14 | // single-field ErrorResponse during the mixed-version window. | |
| @@ -8,7 +8,7 @@ import "time" | |||||
| 8 | // change from ErrorResponse for app mutations; clients accept both | 8 | // change from ErrorResponse for app mutations; clients accept both | ||
| 9 | // during the mixed-version window. | 9 | // during the mixed-version window. | ||
| 10 | 10 | ||||
| 11 | - | // AppError is the v2.50 app-mutation error envelope. Its stable fields are | 11 | + | // AppError is the v3 app-mutation error envelope. Its stable fields are |
| 12 | // error/message/cause/hint. | 12 | // error/message/cause/hint. | ||
| 13 | // `logs` never appears on mutations. Clients accept the legacy | 13 | // `logs` never appears on mutations. Clients accept the legacy | ||
| 14 | // single-field ErrorResponse during the mixed-version window. | 14 | // single-field ErrorResponse during the mixed-version window. | ||
M internal/adapters/dto/admin_apps_test.go +1 -1
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | package dto | |
| 2 | 2 | ||
| 3 | - | // Frozen-wire tests for the v2.50 app admin DTOs pin the exact JSON field | |
| 3 | + | // Frozen-wire tests for the v3 app admin DTOs pin the exact JSON field | |
| 4 | 4 | // names the daemon and the CLI exchange, and prove no response shape can | |
| 5 | 5 | // carry secret values. The single intentional exception is | |
| 6 | 6 | // AppSecretSetRequest: the write path must transport values. | |
| @@ -1,6 +1,6 @@ | |||||
| 1 | package dto | 1 | package dto | ||
| 2 | 2 | ||||
| 3 | - | // Frozen-wire tests for the v2.50 app admin DTOs pin the exact JSON field | 3 | + | // Frozen-wire tests for the v3 app admin DTOs pin the exact JSON field |
| 4 | // names the daemon and the CLI exchange, and prove no response shape can | 4 | // names the daemon and the CLI exchange, and prove no response shape can | ||
| 5 | // carry secret values. The single intentional exception is | 5 | // carry secret values. The single intentional exception is | ||
| 6 | // AppSecretSetRequest: the write path must transport values. | 6 | // AppSecretSetRequest: the write path must transport values. | ||
M internal/adapters/in/cli/remote/apps_test.go +1 -1
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | package remote | |
| 2 | 2 | ||
| 3 | - | // Tests for the v2.50 app mutation transport (apps.go): every mutation | |
| 3 | + | // Tests for the v3 app mutation transport (apps.go): every mutation | |
| 4 | 4 | // carries a client-generated Idempotency-Key, retryable gateway statuses | |
| 5 | 5 | // surface OutcomeUnknownError without replaying the mutation, and | |
| 6 | 6 | // ambiguous outcomes recover via the by-key endpoint. | |
| @@ -1,6 +1,6 @@ | |||||
| 1 | package remote | 1 | package remote | ||
| 2 | 2 | ||||
| 3 | - | // Tests for the v2.50 app mutation transport (apps.go): every mutation | 3 | + | // Tests for the v3 app mutation transport (apps.go): every mutation |
| 4 | // carries a client-generated Idempotency-Key, retryable gateway statuses | 4 | // carries a client-generated Idempotency-Key, retryable gateway statuses | ||
| 5 | // surface OutcomeUnknownError without replaying the mutation, and | 5 | // surface OutcomeUnknownError without replaying the mutation, and | ||
| 6 | // ambiguous outcomes recover via the by-key endpoint. | 6 | // ambiguous outcomes recover via the by-key endpoint. | ||
M internal/adapters/in/http/admin/handler_apps.go +1 -1
| @@ -497,7 +497,7 @@ func (h *Handler) handleAppSecretsDelete(w http.ResponseWriter, r *http.Request, | |||
| 497 | 497 | h.sendJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) | |
| 498 | 498 | } | |
| 499 | 499 | ||
| 500 | - | // sendAppError writes the v2.50 error envelope (never carries logs). | |
| 500 | + | // sendAppError writes the v3 error envelope (never carries logs). | |
| 501 | 501 | func (h *Handler) sendAppError(w http.ResponseWriter, status int, code, message, cause, hint string) { | |
| 502 | 502 | w.Header().Set("Content-Type", "application/json") | |
| 503 | 503 | w.WriteHeader(status) | |
| @@ -497,7 +497,7 @@ func (h *Handler) handleAppSecretsDelete(w http.ResponseWriter, r *http.Request, | |||||
| 497 | h.sendJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) | 497 | h.sendJSON(w, http.StatusOK, map[string]string{"status": "deleted"}) | ||
| 498 | } | 498 | } | ||
| 499 | 499 | ||||
| 500 | - | // sendAppError writes the v2.50 error envelope (never carries logs). | 500 | + | // sendAppError writes the v3 error envelope (never carries logs). |
| 501 | func (h *Handler) sendAppError(w http.ResponseWriter, status int, code, message, cause, hint string) { | 501 | func (h *Handler) sendAppError(w http.ResponseWriter, status int, code, message, cause, hint string) { | ||
| 502 | w.Header().Set("Content-Type", "application/json") | 502 | w.Header().Set("Content-Type", "application/json") | ||
| 503 | w.WriteHeader(status) | 503 | w.WriteHeader(status) | ||
M internal/adapters/in/http/admin/handler_retired.go +2 -2
| @@ -6,7 +6,7 @@ import ( | |||
| 6 | 6 | "github.com/bnema/gordon/internal/adapters/dto" | |
| 7 | 7 | ) | |
| 8 | 8 | ||
| 9 | - | // retiredMutationPaths are legacy mutation endpoints removed by the v2.50 | |
| 9 | + | // retiredMutationPaths are legacy mutation endpoints removed by the v3 | |
| 10 | 10 | // declarative-apps cutover. Only the 410 Gone rejection dispatcher below | |
| 11 | 11 | // remains; no old business handlers or compatibility behavior is kept. | |
| 12 | 12 | var retiredMutationPaths = []string{ | |
| @@ -42,7 +42,7 @@ func isRetiredMutation(path string) bool { | |||
| 42 | 42 | func (h *Handler) handleRetiredMutation(w http.ResponseWriter, _ *http.Request, _ string) { | |
| 43 | 43 | h.sendJSON(w, http.StatusGone, dto.AppError{ | |
| 44 | 44 | Error: "endpoint-retired", | |
| 45 | - | Message: "this endpoint was removed by the v2.50 declarative-apps cutover; use /admin/apps/* instead", | |
| 45 | + | Message: "this endpoint was removed by the v3 declarative-apps cutover; use /admin/apps/* instead", | |
| 46 | 46 | Hint: "see gordon apps --help", | |
| 47 | 47 | }) | |
| 48 | 48 | } | |
| @@ -6,7 +6,7 @@ import ( | |||||
| 6 | "github.com/bnema/gordon/internal/adapters/dto" | 6 | "github.com/bnema/gordon/internal/adapters/dto" | ||
| 7 | ) | 7 | ) | ||
| 8 | 8 | ||||
| 9 | - | // retiredMutationPaths are legacy mutation endpoints removed by the v2.50 | 9 | + | // retiredMutationPaths are legacy mutation endpoints removed by the v3 |
| 10 | // declarative-apps cutover. Only the 410 Gone rejection dispatcher below | 10 | // declarative-apps cutover. Only the 410 Gone rejection dispatcher below | ||
| 11 | // remains; no old business handlers or compatibility behavior is kept. | 11 | // remains; no old business handlers or compatibility behavior is kept. | ||
| 12 | var retiredMutationPaths = []string{ | 12 | var retiredMutationPaths = []string{ | ||
| @@ -42,7 +42,7 @@ func isRetiredMutation(path string) bool { | |||||
| 42 | func (h *Handler) handleRetiredMutation(w http.ResponseWriter, _ *http.Request, _ string) { | 42 | func (h *Handler) handleRetiredMutation(w http.ResponseWriter, _ *http.Request, _ string) { | ||
| 43 | h.sendJSON(w, http.StatusGone, dto.AppError{ | 43 | h.sendJSON(w, http.StatusGone, dto.AppError{ | ||
| 44 | Error: "endpoint-retired", | 44 | Error: "endpoint-retired", | ||
| 45 | - | Message: "this endpoint was removed by the v2.50 declarative-apps cutover; use /admin/apps/* instead", | 45 | + | Message: "this endpoint was removed by the v3 declarative-apps cutover; use /admin/apps/* instead", |
| 46 | Hint: "see gordon apps --help", | 46 | Hint: "see gordon apps --help", | ||
| 47 | }) | 47 | }) | ||
| 48 | } | 48 | } | ||
M internal/adapters/out/appsecrets/store.go +1 -1
| @@ -1,4 +1,4 @@ | |||
| 1 | - | // Package appsecrets implements out.SecretWriter on pass for v2.50 app | |
| 1 | + | // Package appsecrets implements out.SecretWriter on pass for v3 app | |
| 2 | 2 | // secrets at gordon/apps/<app>/<service>/<name>. Values never pass | |
| 3 | 3 | // through app state, diffs, logs, or backup metadata — only this | |
| 4 | 4 | // explicit write path and the deployment-time read path carry them. | |
| @@ -1,4 +1,4 @@ | |||||
| 1 | - | // Package appsecrets implements out.SecretWriter on pass for v2.50 app | 1 | + | // Package appsecrets implements out.SecretWriter on pass for v3 app |
| 2 | // secrets at gordon/apps/<app>/<service>/<name>. Values never pass | 2 | // secrets at gordon/apps/<app>/<service>/<name>. Values never pass | ||
| 3 | // through app state, diffs, logs, or backup metadata — only this | 3 | // through app state, diffs, logs, or backup metadata — only this | ||
| 4 | // explicit write path and the deployment-time read path carry them. | 4 | // explicit write path and the deployment-time read path carry them. | ||
M internal/app/run.go +4 -4
| @@ -460,7 +460,7 @@ func initConfig(configPath string) (*viper.Viper, Config, error) { | |||
| 460 | 460 | return v, cfg, nil | |
| 461 | 461 | } | |
| 462 | 462 | ||
| 463 | - | // retiredAppConfigKeys are pre-v2.50 application keys removed with the | |
| 463 | + | // retiredAppConfigKeys are pre-v3 application keys removed with the | |
| 464 | 464 | // declarative-apps cutover. Presence fails boot/reload closed with a | |
| 465 | 465 | // config-retired diagnostic naming the fix — never a silent migration. | |
| 466 | 466 | var retiredAppConfigKeys = []struct { | |
| @@ -486,7 +486,7 @@ func validateRetiredAppConfig(v *viper.Viper) error { | |||
| 486 | 486 | diagnostics := make([]string, 0, len(retiredAppConfigKeys)) | |
| 487 | 487 | for _, retired := range retiredAppConfigKeys { | |
| 488 | 488 | if v.InConfig(retired.key) { | |
| 489 | - | diagnostics = append(diagnostics, fmt.Sprintf("key %q was removed in v2.50; %s", retired.key, retired.hint)) | |
| 489 | + | diagnostics = append(diagnostics, fmt.Sprintf("key %q was removed in v3; %s", retired.key, retired.hint)) | |
| 490 | 490 | } | |
| 491 | 491 | } | |
| 492 | 492 | if len(diagnostics) > 0 { | |
| @@ -869,7 +869,7 @@ func newAppDaemonService(ctx context.Context, store out.AppState, deploy appDepl | |||
| 869 | 869 | return apps.NewAppServiceImpl(store, deploy, secrets, log).WithDaemonContext(ctx) | |
| 870 | 870 | } | |
| 871 | 871 | ||
| 872 | - | // initApps wires the single v2.50 app engine: bbolt state, image digests, | |
| 872 | + | // initApps wires the single v3 app engine: bbolt state, image digests, | |
| 873 | 873 | // pass-backed secrets, deployment/lifecycle execution, and traffic | |
| 874 | 874 | // activation. The daemon is the sole app-state writer; CLI reaches the | |
| 875 | 875 | // engine only through the admin /apps surface. | |
| @@ -2481,7 +2481,7 @@ func validateVolumeBackupS3Settings(enabled bool, keep, maxConcurrency int, buck | |||
| 2481 | 2481 | // registerEventHandlers registers event handlers. Push-triggered | |
| 2482 | 2482 | // route creation (auto-route, previews, image-pushed deploy) is | |
| 2483 | 2483 | // retired: pushes transfer OCI content only and apps deploy | |
| 2484 | - | // explicitly via `gordon apps deploy`. The pre-v2.50 route-engine | |
| 2484 | + | // explicitly via `gordon apps deploy`. The pre-v3 route-engine | |
| 2485 | 2485 | // deploy arms (config-reload redeploy, manual SIGUSR2 deploy, | |
| 2486 | 2486 | // secrets-changed redeploy) are removed with the declarative-apps | |
| 2487 | 2487 | // cutover: reload never activates app state, and app secret changes | |
| @@ -460,7 +460,7 @@ func initConfig(configPath string) (*viper.Viper, Config, error) { | |||||
| 460 | return v, cfg, nil | 460 | return v, cfg, nil | ||
| 461 | } | 461 | } | ||
| 462 | 462 | ||||
| 463 | - | // retiredAppConfigKeys are pre-v2.50 application keys removed with the | 463 | + | // retiredAppConfigKeys are pre-v3 application keys removed with the |
| 464 | // declarative-apps cutover. Presence fails boot/reload closed with a | 464 | // declarative-apps cutover. Presence fails boot/reload closed with a | ||
| 465 | // config-retired diagnostic naming the fix — never a silent migration. | 465 | // config-retired diagnostic naming the fix — never a silent migration. | ||
| 466 | var retiredAppConfigKeys = []struct { | 466 | var retiredAppConfigKeys = []struct { | ||
| @@ -486,7 +486,7 @@ func validateRetiredAppConfig(v *viper.Viper) error { | |||||
| 486 | diagnostics := make([]string, 0, len(retiredAppConfigKeys)) | 486 | diagnostics := make([]string, 0, len(retiredAppConfigKeys)) | ||
| 487 | for _, retired := range retiredAppConfigKeys { | 487 | for _, retired := range retiredAppConfigKeys { | ||
| 488 | if v.InConfig(retired.key) { | 488 | if v.InConfig(retired.key) { | ||
| 489 | - | diagnostics = append(diagnostics, fmt.Sprintf("key %q was removed in v2.50; %s", retired.key, retired.hint)) | 489 | + | diagnostics = append(diagnostics, fmt.Sprintf("key %q was removed in v3; %s", retired.key, retired.hint)) |
| 490 | } | 490 | } | ||
| 491 | } | 491 | } | ||
| 492 | if len(diagnostics) > 0 { | 492 | if len(diagnostics) > 0 { | ||
| @@ -869,7 +869,7 @@ func newAppDaemonService(ctx context.Context, store out.AppState, deploy appDepl | |||||
| 869 | return apps.NewAppServiceImpl(store, deploy, secrets, log).WithDaemonContext(ctx) | 869 | return apps.NewAppServiceImpl(store, deploy, secrets, log).WithDaemonContext(ctx) | ||
| 870 | } | 870 | } | ||
| 871 | 871 | ||||
| 872 | - | // initApps wires the single v2.50 app engine: bbolt state, image digests, | 872 | + | // initApps wires the single v3 app engine: bbolt state, image digests, |
| 873 | // pass-backed secrets, deployment/lifecycle execution, and traffic | 873 | // pass-backed secrets, deployment/lifecycle execution, and traffic | ||
| 874 | // activation. The daemon is the sole app-state writer; CLI reaches the | 874 | // activation. The daemon is the sole app-state writer; CLI reaches the | ||
| 875 | // engine only through the admin /apps surface. | 875 | // engine only through the admin /apps surface. | ||
| @@ -2481,7 +2481,7 @@ func validateVolumeBackupS3Settings(enabled bool, keep, maxConcurrency int, buck | |||||
| 2481 | // registerEventHandlers registers event handlers. Push-triggered | 2481 | // registerEventHandlers registers event handlers. Push-triggered | ||
| 2482 | // route creation (auto-route, previews, image-pushed deploy) is | 2482 | // route creation (auto-route, previews, image-pushed deploy) is | ||
| 2483 | // retired: pushes transfer OCI content only and apps deploy | 2483 | // retired: pushes transfer OCI content only and apps deploy | ||
| 2484 | - | // explicitly via `gordon apps deploy`. The pre-v2.50 route-engine | 2484 | + | // explicitly via `gordon apps deploy`. The pre-v3 route-engine |
| 2485 | // deploy arms (config-reload redeploy, manual SIGUSR2 deploy, | 2485 | // deploy arms (config-reload redeploy, manual SIGUSR2 deploy, | ||
| 2486 | // secrets-changed redeploy) are removed with the declarative-apps | 2486 | // secrets-changed redeploy) are removed with the declarative-apps | ||
| 2487 | // cutover: reload never activates app state, and app secret changes | 2487 | // cutover: reload never activates app state, and app secret changes | ||
M internal/boundaries/in/apps.go +1 -1
| @@ -7,7 +7,7 @@ import ( | |||
| 7 | 7 | "github.com/bnema/gordon/internal/domain" | |
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | - | // AppService is the driving port for the v2.50 app lifecycle: | |
| 10 | + | // AppService is the driving port for the v3 app lifecycle: | |
| 11 | 11 | // apply + reads (list/show/diff), lifecycle verbs | |
| 12 | 12 | // (deploy/stop/start/restart/remove), op recovery by idempotency key, | |
| 13 | 13 | // and service-scoped secret value writes. | |
| @@ -7,7 +7,7 @@ import ( | |||||
| 7 | "github.com/bnema/gordon/internal/domain" | 7 | "github.com/bnema/gordon/internal/domain" | ||
| 8 | ) | 8 | ) | ||
| 9 | 9 | ||||
| 10 | - | // AppService is the driving port for the v2.50 app lifecycle: | 10 | + | // AppService is the driving port for the v3 app lifecycle: |
| 11 | // apply + reads (list/show/diff), lifecycle verbs | 11 | // apply + reads (list/show/diff), lifecycle verbs | ||
| 12 | // (deploy/stop/start/restart/remove), op recovery by idempotency key, | 12 | // (deploy/stop/start/restart/remove), op recovery by idempotency key, | ||
| 13 | // and service-scoped secret value writes. | 13 | // and service-scoped secret value writes. | ||
M internal/boundaries/in/container.go +1 -1
| @@ -10,7 +10,7 @@ import ( | |||
| 10 | 10 | ) | |
| 11 | 11 | ||
| 12 | 12 | // ContainerService defines the contract for container runtime reads and | |
| 13 | - | // lifecycle retained by the v2.50 cutover. The route-container engine | |
| 13 | + | // lifecycle retained by the v3 cutover. The route-container engine | |
| 14 | 14 | // (deploy/restart/remove/reconcile/attachments/sync/autostart) was | |
| 15 | 15 | // removed with the declarative-apps cutover; the deployment engine owns | |
| 16 | 16 | // workload effects through out.ContainerRuntime directly. | |
| @@ -10,7 +10,7 @@ import ( | |||||
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| 12 | // ContainerService defines the contract for container runtime reads and | 12 | // ContainerService defines the contract for container runtime reads and | ||
| 13 | - | // lifecycle retained by the v2.50 cutover. The route-container engine | 13 | + | // lifecycle retained by the v3 cutover. The route-container engine |
| 14 | // (deploy/restart/remove/reconcile/attachments/sync/autostart) was | 14 | // (deploy/restart/remove/reconcile/attachments/sync/autostart) was | ||
| 15 | // removed with the declarative-apps cutover; the deployment engine owns | 15 | // removed with the declarative-apps cutover; the deployment engine owns | ||
| 16 | // workload effects through out.ContainerRuntime directly. | 16 | // workload effects through out.ContainerRuntime directly. | ||
M internal/boundaries/out/secrets.go +1 -1
| @@ -15,7 +15,7 @@ type SecretProvider interface { | |||
| 15 | 15 | } | |
| 16 | 16 | ||
| 17 | 17 | // SecretWriter defines the contract for writing app secret values by path. | |
| 18 | - | // v2.50 app secrets live in pass at gordon/apps/<app>/<service>/<name>; | |
| 18 | + | // v3 app secrets live in pass at gordon/apps/<app>/<service>/<name>; | |
| 19 | 19 | // values cross this boundary only on the explicit SetSecrets path. | |
| 20 | 20 | type SecretWriter interface { | |
| 21 | 21 | // SetSecret writes one secret value by path. | |
| @@ -15,7 +15,7 @@ type SecretProvider interface { | |||||
| 15 | } | 15 | } | ||
| 16 | 16 | ||||
| 17 | // SecretWriter defines the contract for writing app secret values by path. | 17 | // SecretWriter defines the contract for writing app secret values by path. | ||
| 18 | - | // v2.50 app secrets live in pass at gordon/apps/<app>/<service>/<name>; | 18 | + | // v3 app secrets live in pass at gordon/apps/<app>/<service>/<name>; |
| 19 | // values cross this boundary only on the explicit SetSecrets path. | 19 | // values cross this boundary only on the explicit SetSecrets path. | ||
| 20 | type SecretWriter interface { | 20 | type SecretWriter interface { | ||
| 21 | // SetSecret writes one secret value by path. | 21 | // SetSecret writes one secret value by path. | ||
M internal/domain/app_spec.go +3 -3
| @@ -31,7 +31,7 @@ var reservedAppNames = map[string]struct{}{ | |||
| 31 | 31 | "localhost": {}, | |
| 32 | 32 | } | |
| 33 | 33 | ||
| 34 | - | // App readiness types. HTTP is new in v2.50. | |
| 34 | + | // App readiness types. HTTP is new in v3. | |
| 35 | 35 | const ( | |
| 36 | 36 | AppReadinessNone = "none" | |
| 37 | 37 | AppReadinessTCP = "tcp" | |
| @@ -53,7 +53,7 @@ const ( | |||
| 53 | 53 | AppVisibilityInternal = "internal" | |
| 54 | 54 | ) | |
| 55 | 55 | ||
| 56 | - | // App database engines. Only postgres in v2.50. | |
| 56 | + | // App database engines. Only postgres in v3. | |
| 57 | 57 | const ( | |
| 58 | 58 | AppDBPostgres = "postgres" | |
| 59 | 59 | ) | |
| @@ -91,7 +91,7 @@ type AppSpec struct { | |||
| 91 | 91 | } | |
| 92 | 92 | ||
| 93 | 93 | // AppService is one explicitly named image-backed service. | |
| 94 | - | // v2.50 runs exactly one container per service: no replicas field. | |
| 94 | + | // v3 runs exactly one container per service: no replicas field. | |
| 95 | 95 | // RCON is ordinary TCP: use TCP interfaces, no special RCON kind. | |
| 96 | 96 | type AppService struct { | |
| 97 | 97 | Name string | |
| @@ -31,7 +31,7 @@ var reservedAppNames = map[string]struct{}{ | |||||
| 31 | "localhost": {}, | 31 | "localhost": {}, | ||
| 32 | } | 32 | } | ||
| 33 | 33 | ||||
| 34 | - | // App readiness types. HTTP is new in v2.50. | 34 | + | // App readiness types. HTTP is new in v3. |
| 35 | const ( | 35 | const ( | ||
| 36 | AppReadinessNone = "none" | 36 | AppReadinessNone = "none" | ||
| 37 | AppReadinessTCP = "tcp" | 37 | AppReadinessTCP = "tcp" | ||
| @@ -53,7 +53,7 @@ const ( | |||||
| 53 | AppVisibilityInternal = "internal" | 53 | AppVisibilityInternal = "internal" | ||
| 54 | ) | 54 | ) | ||
| 55 | 55 | ||||
| 56 | - | // App database engines. Only postgres in v2.50. | 56 | + | // App database engines. Only postgres in v3. |
| 57 | const ( | 57 | const ( | ||
| 58 | AppDBPostgres = "postgres" | 58 | AppDBPostgres = "postgres" | ||
| 59 | ) | 59 | ) | ||
| @@ -91,7 +91,7 @@ type AppSpec struct { | |||||
| 91 | } | 91 | } | ||
| 92 | 92 | ||||
| 93 | // AppService is one explicitly named image-backed service. | 93 | // AppService is one explicitly named image-backed service. | ||
| 94 | - | // v2.50 runs exactly one container per service: no replicas field. | 94 | + | // v3 runs exactly one container per service: no replicas field. |
| 95 | // RCON is ordinary TCP: use TCP interfaces, no special RCON kind. | 95 | // RCON is ordinary TCP: use TCP interfaces, no special RCON kind. | ||
| 96 | type AppService struct { | 96 | type AppService struct { | ||
| 97 | Name string | 97 | Name string | ||
M internal/domain/labels.go +1 -1
| @@ -12,7 +12,7 @@ const ( | |||
| 12 | 12 | // exposing secret values. | |
| 13 | 13 | LabelEnvHash = "gordon.env-hash" | |
| 14 | 14 | ||
| 15 | - | // App ownership labels are stamped by the v2.50 deploy engine on every | |
| 15 | + | // App ownership labels are stamped by the v3 deploy engine on every | |
| 16 | 16 | // container and volume it creates (03-deployment.md §4A/B, frozen here | |
| 17 | 17 | // so prune/backup guards can consume them before the engine activates). | |
| 18 | 18 | // The engine wiring that stamps them lands at cutover; until then no | |
| @@ -12,7 +12,7 @@ const ( | |||||
| 12 | // exposing secret values. | 12 | // exposing secret values. | ||
| 13 | LabelEnvHash = "gordon.env-hash" | 13 | LabelEnvHash = "gordon.env-hash" | ||
| 14 | 14 | ||||
| 15 | - | // App ownership labels are stamped by the v2.50 deploy engine on every | 15 | + | // App ownership labels are stamped by the v3 deploy engine on every |
| 16 | // container and volume it creates (03-deployment.md §4A/B, frozen here | 16 | // container and volume it creates (03-deployment.md §4A/B, frozen here | ||
| 17 | // so prune/backup guards can consume them before the engine activates). | 17 | // so prune/backup guards can consume them before the engine activates). | ||
| 18 | // The engine wiring that stamps them lands at cutover; until then no | 18 | // The engine wiring that stamps them lands at cutover; until then no | ||
M internal/usecase/container/service.go +1 -1
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | // Package container implements the retained container lifecycle use case. | |
| 2 | 2 | // | |
| 3 | - | // The v2.50 declarative-apps cutover removed the route-container engine | |
| 3 | + | // The v3 declarative-apps cutover removed the route-container engine | |
| 4 | 4 | // (deploy/restart/remove/reconcile/attachments/sync/autostart, image-label | |
| 5 | 5 | // inference, readiness cascade, monitor). Workload effects belong to the | |
| 6 | 6 | // deployment engine through out.ContainerRuntime directly. What remains: | |
| @@ -1,6 +1,6 @@ | |||||
| 1 | // Package container implements the retained container lifecycle use case. | 1 | // Package container implements the retained container lifecycle use case. | ||
| 2 | // | 2 | // | ||
| 3 | - | // The v2.50 declarative-apps cutover removed the route-container engine | 3 | + | // The v3 declarative-apps cutover removed the route-container engine |
| 4 | // (deploy/restart/remove/reconcile/attachments/sync/autostart, image-label | 4 | // (deploy/restart/remove/reconcile/attachments/sync/autostart, image-label | ||
| 5 | // inference, readiness cascade, monitor). Workload effects belong to the | 5 | // inference, readiness cascade, monitor). Workload effects belong to the | ||
| 6 | // deployment engine through out.ContainerRuntime directly. What remains: | 6 | // deployment engine through out.ContainerRuntime directly. What remains: | ||
M internal/usecase/proxy/service.go +1 -1
| @@ -41,7 +41,7 @@ type TargetProvider interface { | |||
| 41 | 41 | ||
| 42 | 42 | // Service implements the ProxyService interface. | |
| 43 | 43 | // App backends resolve through appTargets (ACTIVE-derived projection); | |
| 44 | - | // the pre-v2.50 container-service + image-label resolution is removed. | |
| 44 | + | // the pre-v3 container-service + image-label resolution is removed. | |
| 45 | 45 | type Service struct { | |
| 46 | 46 | configSvc in.ConfigService | |
| 47 | 47 | config Config | |
| @@ -41,7 +41,7 @@ type TargetProvider interface { | |||||
| 41 | 41 | ||||
| 42 | // Service implements the ProxyService interface. | 42 | // Service implements the ProxyService interface. | ||
| 43 | // App backends resolve through appTargets (ACTIVE-derived projection); | 43 | // App backends resolve through appTargets (ACTIVE-derived projection); | ||
| 44 | - | // the pre-v2.50 container-service + image-label resolution is removed. | 44 | + | // the pre-v3 container-service + image-label resolution is removed. |
| 45 | type Service struct { | 45 | type Service struct { | ||
| 46 | configSvc in.ConfigService | 46 | configSvc in.ConfigService | ||
| 47 | config Config | 47 | config Config | ||