diff --git a/.planning/phases/14.3-one-command-app-scaffolding-summer-new-and-summercms-io-new/14.3-02-SUMMARY.md b/.planning/phases/14.3-one-command-app-scaffolding-summer-new-and-summercms-io-new/14.3-02-SUMMARY.md new file mode 100644 index 0000000..8e938cc --- /dev/null +++ b/.planning/phases/14.3-one-command-app-scaffolding-summer-new-and-summercms-io-new/14.3-02-SUMMARY.md @@ -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 --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 | 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 -- ` 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--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 install ./cmd/summer`, `summer new --framework ` 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 +==> 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 (" must be an ancestor of the target") could say "HEAD of " — 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