docs(14.3-02): complete bootstrap script plan
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user