docs(14.3-02): complete bootstrap script plan

This commit is contained in:
Jakub Zych
2026-10-08 11:58:45 +02:00
parent 55dffb5b63
commit e7637a0271

View File

@@ -0,0 +1,247 @@
---
phase: 14.3-one-command-app-scaffolding-summer-new-and-summercms-io-new
plan: 02
subsystem: cli
tags: [bootstrap, curl-bash, sunrise, embed, site-route, docker, acceptance, security-review]
requires:
- phase: 14.3-01
provides: "summer new <name> --framework, next steps printed by summer new, scripts/check-phase14.3.sh --generator"
provides:
- "modules/sunrise: new.sh (curl | bash bootstrap) and sunrise.Script()"
- "site plugin GET /new serving sunrise.Script() as text/plain (sm-summercmsio-plugin 2157bb9, app gitlink fd721cf)"
- "scripts/check-phase14.3.sh --acceptance and --acceptance-production (D-20 in node:24-bookworm)"
- "14.3-SECURITY-REVIEW.md covering T-14.3-01..19 and T-14.3-SC"
affects: [14.3-03 docs and landing page, 14.3-04 unit tests and gate, v0.1.13 release, site redeploy]
actuals:
tokens: 12013
tasks: 3
commits: 3
plan_head_before: d0888d7576901ef7043963d70792573581f40c22
plan_head_after: 55dffb5b635b5096b02d8440b11041662d4cd248
tech-stack:
added: []
patterns:
- "Bootstrap script as functions plus a final `main \"$@\"`, using only bash builtins and git/go/docker so a stub PATH can prove truncation safety"
- "Script embedded in a framework module and served by the site from the framework version it builds against"
key-files:
created:
- modules/sunrise/new.sh
- modules/sunrise/sunrise.go
- modules/sunrise/sunrise_test.go
- modules/sunrise/README.md
- ../sm-summercmsio-app/plugins/golem15/summercms/script.go
- .planning/phases/14.3-one-command-app-scaffolding-summer-new-and-summercms-io-new/14.3-SECURITY-REVIEW.md
modified:
- README.md
- scripts/check-phase14.3.sh
- ../sm-summercmsio-app/plugins/golem15/summercms/plugin.go
- ../sm-summercmsio-app/plugins/golem15/summercms/routes_test.go
- ../sm-summercmsio-app/plugins/golem15/summercms/README.md
key-decisions:
- "Framework module for the script is named sunrise; package exports only Script() []byte (fresh copy per call)"
- "The script installs summer with GOWORK=off so the clone's committed go.work (examples) and missing go.work.sum do not affect go install"
- "Progress, warnings and errors go to stderr; the closing cd line and PATH hint go to stdout"
- "On a fresh clone with no usable target the clone is left in place and the error says to remove it; the script never deletes anything"
- "Security review found no high issue, so no code fix; the dirty, branch, moved-tag and non-fast-forward refusals were probed on a throwaway repository"
patterns-established:
- "Stub-PATH truncation harness: every line-boundary prefix and every byte prefix of the final line, with a positive control"
- "Container acceptance through the host Docker socket: --network host, read-only framework mount, unique compose project, host-side label cleanup"
requirements-completed: [D-13, D-14, D-15, D-16, D-17, D-18, D-20, D-24, D-26, D-28]
coverage:
- id: D1
description: "new.sh embedded in modules/sunrise; Script() returns the file bytes as a fresh copy; shape and bash -n checked"
requirement: D-13
verification:
- kind: unit
ref: "modules/sunrise/sunrise_test.go#TestScriptEmbedded"
status: pass
- kind: unit
ref: "modules/sunrise/sunrise_test.go#TestScriptShape"
status: pass
human_judgment: false
- id: D2
description: "A truncated download (any line-boundary prefix, any byte prefix of the final line) invokes nothing and creates no file"
requirement: D-14
verification:
- kind: unit
ref: "modules/sunrise/sunrise_test.go#TestScriptTruncationRunsNothing"
status: pass
human_judgment: false
- id: D3
description: "curl -fsSL <server> | bash -s -- demo clones the framework detached at a pinned ref, installs summer into a GOBIN off PATH, creates a buildable sm-demo-app with a ../summercms replace and prints the cd line and PATH hint"
requirement: D-15
verification:
- kind: e2e
ref: "SUMMERCMS_BOOTSTRAP_CHECK=1 go test ./modules/sunrise/ -run '^TestBootstrapEndToEnd$'"
status: pass
human_judgment: false
- id: D4
description: "Site plugin GET /new: 200 text/plain; charset=utf-8, nosniff, no-cache, strong ETag, body = sunrise.Script(); HEAD 200 no body; matching If-None-Match 304; POST 405"
requirement: D-13
verification:
- kind: unit
ref: "sm-summercmsio-plugin routes_test.go#TestNewScriptRoute"
status: pass
- kind: unit
ref: "sm-summercmsio-plugin routes_test.go#TestRoutesAssemble"
status: pass
human_judgment: false
- id: D5
description: "D-20: from a bare node:24-bookworm image, the one-liner (committed script, repo at HEAD) then docker compose up -d --wait, summer build, summer migrate, summer serve answers GET / with \"plugin\":\"golem15.demo\""
requirement: D-20
verification:
- kind: e2e
ref: "bash scripts/check-phase14.3.sh --acceptance"
status: pass
human_judgment: false
- id: D6
description: "Refusals that protect an existing checkout (branch, dirty, moved tag, non-fast-forward, non-framework dir) and early name/existing-app stops"
requirement: D-16
verification:
- kind: manual_procedural
ref: "14.3-SECURITY-REVIEW.md#refusal-probe-2026-10-08"
status: pass
human_judgment: true
rationale: "Probed by hand on a throwaway repository during the review; plan 04 TestScriptBehavior pins these paths as automated tests"
- id: D7
description: "Security review of plans 01-02 at ASVS L1 with no open high threat"
verification:
- kind: other
ref: "Task 3 verify (REVIEW-OK)"
status: pass
human_judgment: true
rationale: "Self-performed review (no separate auditor agent); a human should read the register and accepted risks"
- id: D8
description: "Production acceptance against https://summercms.io/new after v0.1.13 is tagged and the site redeployed"
requirement: D-28
verification: []
human_judgment: true
rationale: "Release and deploy are user actions; bash scripts/check-phase14.3.sh --acceptance-production runs after them"
duration: 11min
completed: 2026-10-08
status: complete
---
# Phase 14.3 Plan 02: curl | bash bootstrap, GET /new and D-20 acceptance Summary
**`modules/sunrise` embeds `new.sh`, a truncation-safe `curl -fsSL https://summercms.io/new | bash -s -- <name>` installer that checks Go 1.27+/git/Docker, clones or fast-forwards the framework at its newest release tag, installs summer and runs `summer new`; the site plugin serves it at `GET /new` as text/plain, and the full one-liner-to-serving chain passed from a bare node:24-bookworm container.**
## Performance
- **Duration:** 11 min
- **Started:** 2026-10-08T09:46:59Z
- **Completed:** 2026-10-08T09:58:30Z
- **Tasks:** 3
- **Files modified:** 11 (7 in summercms.go, 4 in sm-summercmsio-plugin) plus the site app gitlink
## Accomplishments
- `new.sh`: argument parsing first (`-h`/`--help`, exactly one name, regex), lexical absolute path for `SUMMERCMS_DIR`, early stop on an existing `sm-<name>-app`, Go version from `/` with a go.dev/dl hint, git required, Docker and compose as warnings, clone or ff-only update with refusals, `GOWORK=off go -C <dir> install ./cmd/summer`, `summer new <name> --framework <abs dir>` with stdin closed, then the `cd` line and the PATH hint.
- `sunrise.Script()` plus README (standard structure) and root modules-table row; `TestDocsTree` and `TestEveryModuleInSidebar` pass.
- Site plugin `scriptHandler` and `GET /new` registered before the catch-all; `TestNewScriptRoute`, three `TestRoutesAssemble` rows, README route row.
- `--acceptance` / `--acceptance-production` gate stages; `--acceptance` passed.
- `14.3-SECURITY-REVIEW.md`: 20 threats, 17 mitigated, 3 accepted (low), 0 open.
## D-20 evidence (`bash scripts/check-phase14.3.sh --acceptance`, 2026-10-08)
```
== node:24-bookworm (local, compose project phase143acc-3499410-1791453239)
Docker version 29.8.2, build 7fc2dff
Docker Compose version v5.6.0
== Go 1.27.0 from go.dev, sha256 checked
go1.27.0.linux-amd64.tar.gz: OK
go version go1.27.0 linux/amd64
+ curl -fsSL file:///fw/modules/sunrise/new.sh | SUMMERCMS_REPO=/fw SUMMERCMS_REF=cfd110eddb2af449aae0a2a420008c4368dfd9c9 bash -s -- demo
==> cloning /fw into /work/summercms
==> framework target: cfd110eddb2af449aae0a2a420008c4368dfd9c9 (cfd110eddb2a)
==> installing summer into /root/go/bin
==> creating /work/sm-demo-app
warning: git user.name and user.email not configured; the first commit uses SummerCMS <summer@localhost>
==> Done. Start with:
cd /work/sm-demo-app
==> summer is installed in /root/go/bin, which is not on your PATH. Run this (and add it to your shell profile):
export PATH="/root/go/bin:$PATH"
== D-20 chain
+ docker compose up -d --wait
+ summer build
+ summer migrate
+ summer serve &
GET http://127.0.0.1:8080/ -> {"message":"Hello from SummerCMS","plugin":"golem15.demo"}
Phase 14.3 acceptance passed
```
Afterwards no container or volume of the `phase143acc-*` project remained. With `new.sh` modified the stage refuses: `FAIL: modules/sunrise/new.sh differs from HEAD; commit it first`.
## Task Commits
1. **Task 1: script, embed, GET /new, wired end to end**
- `cfd110e` (feat, summercms.go): sunrise module, tests, README, modules row
- `2157bb9` (feat, sm-summercmsio-plugin): `GET /new` route, tests, README
- `fd721cf` (feat, sm-summercmsio-app): plugin gitlink bump
2. **Task 2: D-20 container acceptance** - `612d0c6` (chore)
3. **Task 3: security review** - `55dffb5` (docs)
Nothing was pushed, tagged or deployed.
## Files Created/Modified
- `modules/sunrise/new.sh` - the bootstrap script (0755)
- `modules/sunrise/sunrise.go` - `//go:embed new.sh`, `Script()`
- `modules/sunrise/sunrise_test.go` - embedded, shape, truncation, gated end-to-end tests
- `modules/sunrise/README.md`, `README.md` - module docs and table row
- `scripts/check-phase14.3.sh` - `--acceptance`, `--acceptance-production`
- `../sm-summercmsio-app/plugins/golem15/summercms/script.go` - `scriptHandler`
- `../sm-summercmsio-app/plugins/golem15/summercms/plugin.go` - `GET /new`, doc comments
- `../sm-summercmsio-app/plugins/golem15/summercms/routes_test.go` - `TestNewScriptRoute`, route rows, coexistence patterns
- `../sm-summercmsio-app/plugins/golem15/summercms/README.md` - route row
- `14.3-SECURITY-REVIEW.md` - ASVS L1 review
## Decisions Made
- Module name `sunrise` (beach-themed like the other modules); only `Script()` is exported.
- `GOWORK=off` for `go install`: the framework commits a `go.work` for its examples but not `go.work.sum`, and the CLI builds from the main module alone.
- No code changes came out of the security review; the non-fast-forward error wording ("<dir> must be an ancestor of the target") could say "HEAD of <dir>" — cosmetic, left so the acceptance evidence matches the committed bytes.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] TestRoutesCoexistWithAdminPatterns pinned the plugin's exact route list**
- **Found during:** Task 1
- **Issue:** The test asserts the plugin registers exactly `GET /docs`, `GET /docs/{path...}`, `GET /`; adding `GET /new` would fail it.
- **Fix:** Added `GET /new` to `wantPatterns` and its handler to the coexistence mux, so the test also proves `/new` does not conflict with the admin patterns.
- **Files modified:** `../sm-summercmsio-app/plugins/golem15/summercms/routes_test.go`
- **Verification:** `go -C ../sm-summercmsio-app/plugins/golem15/summercms test ./...` passes
- **Committed in:** 2157bb9
---
**Total deviations:** 1 auto-fixed (1 blocking). **Impact:** test kept in step with the new route; no scope change.
## Issues Encountered
None.
## User Setup Required
None now. After `v0.1.13` is tagged, the site's `require` is bumped and the site redeployed (user actions, D-28), run `bash scripts/check-phase14.3.sh --acceptance-production`.
## Next Phase Readiness
- Plan 03 can document the one-liner, `SUMMERCMS_REPO/DIR/REF` and `summer new`, and switch the landing page; the site's gated `TestTerminalCommands` will need a script-URL override (research Q9) and can pass `SUMMERCMS_REPO/REF` through.
- Plan 04: `TestScriptBehavior` should pin the refusal probe cases from the security review; `TestScriptShellcheck` can run `shellcheck` (clean today apart from one annotated SC2016).
---
*Phase: 14.3-one-command-app-scaffolding-summer-new-and-summercms-io-new*
*Completed: 2026-10-08*
## Self-Check: PASSED