# OpenLife v1.18.1 — Changelog

**Branch:** `main`
**Predecessor:** v1.18.0 (tagged 2026-05-22)
**Released:** 2026-05-22

Patch release closing the gaps explicitly deferred from v1.18.0:
- Cloudflare + Fly deploy adapters
- Railway native rollback (no longer "not supported yet")
- `openlife scaffold custom --from=<git-url>` — accepts github.com /
  gitlab.com / bitbucket.org / codeberg.org URLs

SvelteKit-Postgres-Lucia template moved to v1.18.2 (separate effort,
needs ~25 file writes mirroring the Next.js template).

## What landed

### Cloudflare + Fly adapters

| Adapter | CLI | Detect marker | Rollback |
|---|---|---|---|
| `CloudflareAdapter` | `wrangler` | `wrangler.toml` or `wrangler.jsonc` | ✓ native via `wrangler rollback <id>` |
| `FlyAdapter` | `fly` (or `flyctl`) | `fly.toml` | ✓ native via `fly releases rollback <version>` |

Both register automatically in `DeployRegistry.ensureDefaults()` and are
included in `autoDetect()` filesystem-marker probing. `openlife deploy
list` shows all 4 providers + install status:

```
Available deploy providers:
  vercel       ✓ installed
  railway      ✓ installed
  cloudflare   ✗ CLI not on PATH
  fly          ✗ CLI not on PATH
```

Preflight checks per adapter:
- **Cloudflare:** missing wrangler.toml warning; missing `name = ...`
  entry → error (blocks deploy). CI without `CLOUDFLARE_API_TOKEN` warning.
- **Fly:** missing fly.toml warning; missing `app = ...` entry → error.
  CI without `FLY_API_TOKEN` warning. Tries `fly` then falls back to
  `flyctl` binary.

### Railway native rollback

Replaces the v1.18.0 "rollback_not_supported_yet" stub with a real
`railway redeploy --yes <deployment-id>` invocation. Requires the user
to pass `--to <id>` (Railway doesn't expose a stable "last good"
deployment via CLI — that requires the dashboard or API). When `--to`
absent, emits actionable error:

```
rollback_requires_id: pass --to <deployment-id>. List candidates via
`railway status` or the Railway dashboard → Deployments tab.
```

### `scaffold custom --from=<git-url>`

The v1.16.0 deferral. Accepts:

- Full URLs: `https://github.com/owner/repo`, `https://github.com/owner/repo.git`,
  `https://gitlab.com/...`, `https://bitbucket.org/...`,
  `https://codeberg.org/...`
- GitHub shorthand: `owner/repo` (auto-prefixed with `https://github.com/`)

Rejects (v1.18.1):
- `git@` SSH URLs — bypass SSRF guard model, require key management
- Domains outside the allowlist — surfaces `url_not_allowlisted` error

Security flow:
1. URL validation via `SecurityDownloadGuard.validateUrl` (existing v1.13
   guard — SSRF + blocklist)
2. Belt-and-suspenders allowlist check (4 hosts)
3. SHA-256 hash of canonical URL → stable cache dir at
   `~/.openlife/templates/.git-cache/<hash>/`
4. `git clone --depth=1 --quiet` (shallow, no history)
5. Validate clone has `manifest.yaml` at root
6. Apply via standard scaffold path

Idempotent: re-running with the same URL reuses the cached clone (no
re-download).

```bash
# All three equivalent:
openlife scaffold meu-app --from=https://github.com/myorg/template-saas.git
openlife scaffold meu-app --from=https://github.com/myorg/template-saas
openlife scaffold meu-app --from=myorg/template-saas
```

## Test updates

`test_deploy_adapters.ts` extended from 8 → 11 scenarios:
- (renamed) scenario 8 — `RailwayAdapter.rollback requires --to <id>`
- (new) scenario 9 — registry has all 4 adapters
- (new) scenario 10 — `CloudflareAdapter.preflight` detects missing config
- (new) scenario 11 — `FlyAdapter.preflight` detects missing fly.toml

All 11 green. No regression in adjacent tests.

## Out of scope (deferred)

- **SvelteKit-Postgres-Lucia template** → v1.18.2 (full 25-file template
  pass)
- **SSH git URLs** (`git@github.com:owner/repo.git`) → v1.18.3 (requires
  ssh key resolution + agent forwarding consideration)
- **Branch / ref selection** for git clones (`--from=...#branch`) → v1.18.3
- **Private repo support** via token → v1.18.3 (needs credential helper
  integration)
- **Multi-environment deploy promote** (`--env=staging --then-prod`) →
  v1.19.0

## Tarball impact

```
v1.18.0 → v1.18.1
package size:    2.0MB → 2.0MB    (negligible)
unpacked size:   7.6MB → 7.7MB    (+50KB)
total files:     1231 → 1235      (+4)
```

The +4 files: 2 adapters + 1 doc + 1 dist artifact.

## Upgrade

```bash
openlife update --global

# Verify
openlife --version             # 1.18.1
openlife deploy list            # 4 providers
openlife scaffold custom --help # shows --from accepts git URLs
```

## Roadmap continuation

- **v1.18.2** — SvelteKit template
- **v1.18.3** — SSH git URLs, branch/ref selection, private repo support
- **v1.19.0** — Multi-environment promote + AI-driven preflight remediation
- **Issue #9** — Cross-machine bridge (independent)
