Correct two doc sections written before the real CI bugs were found
The changelog claimed ci.yml #1 verified green (it didn't -- that was a wrong WebFetch summary of the Gitea Actions page, reported as fact without checking it visually) and CONTINUOUS_INTEGRATION.md described the HOME/cache permission warning as harmless (it wasn't -- it blocked resolving actions/checkout entirely). Both corrected with what actually happened: three real, different bugs, found only by running the workflow and reading user-provided screenshots of the actual failures.
This commit is contained in:
@@ -93,12 +93,16 @@ workflow section for why.
|
||||
work. The runner is available only while the coding PC, Docker, and these
|
||||
containers are running.
|
||||
|
||||
One known, non-fatal warning in the runner logs: `cannot init cache server,
|
||||
it will be disabled: mkdir /.cache: permission denied` — the runner
|
||||
container runs as uid 1000 with no writable `$HOME`, so the `actions/cache`
|
||||
action type is unavailable. Nothing in the current workflow uses it. Fixable
|
||||
later by setting `HOME=/data` in the runner's environment if caching
|
||||
becomes worth adding.
|
||||
`compose.yml` sets `HOME: /data` on the runner container. Without it, the
|
||||
first real run failed every job, both times it was tried, with `Unable to
|
||||
clone https://github.com/actions/checkout ...: mkdir /.cache: permission
|
||||
denied` — this was initially misdiagnosed (both in the runner's own startup
|
||||
log, which only calls it "cache server disabled", and in this doc's first
|
||||
draft) as merely disabling the optional `actions/cache` action type. It
|
||||
actually blocks resolving *any* remote action at all: with uid 1000 and no
|
||||
writable `$HOME`, the runner has nowhere to git-clone an action's source
|
||||
into before running it, and `actions/checkout` is exactly that. `HOME=/data`
|
||||
(the already-writable bind-mounted data directory) fixed it.
|
||||
|
||||
## WeatherTool workflow
|
||||
|
||||
@@ -120,7 +124,9 @@ proven for this project rather than bootstrapping a second language runtime
|
||||
into a single shared container:
|
||||
|
||||
- **`backend`** (`hseeberger/scala-sbt:17.0.2_1.6.2_2.13.8`, the same image
|
||||
used all session for local Rocky builds): checkout, `sbt -batch test`.
|
||||
used all session for local Rocky builds): installs a real Node 20 via
|
||||
NodeSource's setup script (see below for why), checkout, `sbt -batch
|
||||
test`.
|
||||
- **`frontend`** (`node:20-bookworm`): checkout, `npm ci`, `npm run
|
||||
typecheck`, `npm run build`, `npm audit`, `npm audit --omit=dev` — the
|
||||
same five checks already documented as the manual Rocky verification
|
||||
@@ -134,8 +140,24 @@ plugin logs a graceful warning and continues; nothing in the current test
|
||||
suite (`FileNameServiceSpec`; `ParserSpec` has no live assertions) touches
|
||||
`sys.env` or a live database.
|
||||
|
||||
The first complete green run was verified on 2026-08-24 for commit
|
||||
`5b88e69` (`ci.yml #1`, 33s).
|
||||
`actions/checkout` is a JavaScript action — it needs a Node runtime inside
|
||||
the job container to execute at all, which `hseeberger/scala-sbt` doesn't
|
||||
have. `frontend`'s image already has one, so it passed as soon as the
|
||||
`HOME` fix landed. `backend` needed an explicit install step first
|
||||
(`apt-get install nodejs` alone wasn't enough either: `hseeberger/scala-sbt`
|
||||
is Debian **bullseye**-based, whose default apt `nodejs` package is a stale
|
||||
Node 12, too old to parse `actions/checkout@v4`'s modern JS —
|
||||
`SyntaxError: Unexpected token '{'` on a class static block. NodeSource's
|
||||
`setup_20.x` script installs an actual current Node 20 regardless of the
|
||||
distro's packaged version).
|
||||
|
||||
None of the three bugs above were caught by writing the workflow carefully
|
||||
or by the pre-write `sbt test` dry run — all three only surfaced by actually
|
||||
running it and reading the real failure in the Gitea Actions UI, once per
|
||||
bug, in order: the `HOME`/cache fix, then the missing-Node fix, then the
|
||||
wrong-Node-version fix. The first four runs (`ci.yml #1`–`#4`) all failed.
|
||||
The first complete green run was `ci.yml #5`, commit `2c78ae8`, 2m24s,
|
||||
verified 2026-08-24.
|
||||
|
||||
## Current boundary
|
||||
|
||||
|
||||
@@ -449,5 +449,6 @@ Record completed work here by date and commit after the Git workflow is establis
|
||||
| 2026-08-24 | `0be325f` | Deploy the security-review fixes (`6b9c7cf`, `8c45d8d`) to the VPS as image `weathertool:0be325fbbbf92b03bc8d574dc6f7b9449ef310ea`; release `b0b58d2` remains the immediate application rollback. Application-only release — PostgreSQL and Authelia were not restarted | Yes — exact release image smoke-tested on Rocky against a throwaway local Postgres before transfer (traversal/injection payloads 404, gated FTP route 503, legitimate queries 200); checksum verified on both ends; `app` service recreated cleanly (healthy, no auth/DB errors in logs); loopback re-verification of the same traversal/injection/FTP-gate checks plus real `/api/warnings` and `/api/water-temperatures` responses; public HTTPS confirmed unchanged (302 unauthenticated page, 401 unauthenticated API) |
|
||||
| 2026-08-24 | `9bab93d` | A follow-up independent fresh-eyes review (requested specifically as a second pass, not a rerun of the same pentest) caught that the `6b9c7cf` FTP auth-bypass fix was incomplete: only `/api/fetch/lvgmc/stations` (the one route the original review named) was gated behind `ENABLE_LVGMC_FTP_JOBS`. A sibling route, `/api/show/lvgmc-forecast/{fileName}`, calls the same `fetch.fetchFile` — a real, unauthenticated LVGMC FTP login — and had only gotten the traversal fix (`ValidateFileName`), not the auth-bypass fix, because the two routes were fixed along different mental categories (traversal batch vs. the one named auth-bypass fix) instead of by tracing every caller of the dangerous method. Gated this route the same way; traced every HTTP-reachable caller of `fetch.fetchFile`/`fetchWeatherStations` this time to confirm no others remain. Deployed to both Rocky and the VPS (image `weathertool:9bab93daa6b3a0fb99165a8fac9accfa3a3ccbf1`) immediately given this was live and exploitable in production | Yes — Scala tests, Rocky rebuild and curl verification (both FTP routes 503 while the flag is off), VPS image smoke-tested against a throwaway local Postgres before transfer, checksum verified, `app` service recreated cleanly, loopback re-verification of both gated routes, public HTTPS unchanged (302/401) |
|
||||
| 2026-08-24 | *(review, no commit)* | A follow-up independent fresh-eyes review (explicitly scoped as a second, different pass — not a rerun of the original pentest) sanity-checked the `6b9c7cf`/`8c45d8d` fixes and did a broader skeptical pass. Caught the incomplete FTP fix documented under `9bab93d` above. Confirmed `ValidateFileName`'s minor `"."` edge case is harmless (resolves to a directory, not exploitable) and found no other unvalidated `Fragment.const` usages. Surfaced several open architectural/testability findings now tracked in Phase 2/Phase 5 above: the `parMapN` scheduler crash-loop pattern (still fully live), per-request `System.gc()` in `getBinaryChunk`, `PostgresService.query`'s unenforced field-routing invariant, no JDBC connection pooling, and several files under `src/main/scala` (`DataServiceTest`, `FetchServiceTest` ×2, `OpenDataStationServiceTest`, `GribParserTest`) that look like tests but are actually `main`-method scripts never run by `sbt test` — compiled straight into the production jar, at least one capable of writing to the real database or hitting live endpoints if run by mistake |
|
||||
| 2026-08-24 | `5b88e69` | Add Gitea Actions CI: a repository-scoped `weathertool-ci-rocky-01` runner on Rocky (isolated behind its own Docker-in-Docker daemon, mirroring the isolation pattern already proven by HOP's Forgejo runner on the same host — the two coexist without conflict, each an independent client registered to a different server) runs `sbt test` and the frontend typecheck/build/audit routine on every push/PR to `codex/staging-baseline` plus manual dispatch. Verified `sbt test` compiles and passes with no `.env` present at all (via a `git archive HEAD` dry run) before writing the workflow, since CI must never see real credentials. Repo mirrored to Gitea (`bot/WeatherTool`) as an additional remote alongside the existing `rocky`/`origin` ones — deliberately not replacing either, pending an open question about the GitHub `origin` (`guntisdev/WeatherTool`) that won't be resolved until 2026-08-26. See `CONTINUOUS_INTEGRATION.md` | Yes — first run (`ci.yml #1`, commit `5b88e69`) verified green in the Gitea Actions UI (33s), and confirmed via the runner's nested Docker daemon that both job images (`hseeberger/scala-sbt`, `node:20-bookworm`) were actually pulled and used, not just orchestration logs |
|
||||
| 2026-08-24 | `5b88e69` | Add Gitea Actions CI: a repository-scoped `weathertool-ci-rocky-01` runner on Rocky (isolated behind its own Docker-in-Docker daemon, mirroring the isolation pattern already proven by HOP's Forgejo runner on the same host — the two coexist without conflict, each an independent client registered to a different server) runs `sbt test` and the frontend typecheck/build/audit routine on every push/PR to `codex/staging-baseline` plus manual dispatch. Verified `sbt test` compiles and passes with no `.env` present at all (via a `git archive HEAD` dry run) before writing the workflow, since CI must never see real credentials. Repo mirrored to Gitea (`bot/WeatherTool`) as an additional remote alongside the existing `rocky`/`origin` ones — deliberately not replacing either, pending an open question about the GitHub `origin` (`guntisdev/WeatherTool`) that won't be resolved until 2026-08-26. See `CONTINUOUS_INTEGRATION.md` | **Correction**: this row originally claimed the first run (`ci.yml #1`) verified green, based on a WebFetch summary of the Gitea Actions page that turned out to be simply wrong — reported as fact without visually checking it first. It actually failed, along with the next three runs, on three different real bugs (see `7e1b492`/`2c78ae8` below and `CONTINUOUS_INTEGRATION.md`). First actual green run was `ci.yml #5`, commit `2c78ae8` |
|
||||
| 2026-08-24 | `7e1b492`–`2c78ae8` | Fix three real CI bugs surfaced by actually running the new workflow, found via user-provided screenshots of the Gitea Actions UI after the WebFetch-based "success" claim above turned out false: (1) the runner's `HOME`/cache-directory permission error, initially misdiagnosed as only disabling the optional `actions/cache` action type, actually blocked resolving `actions/checkout` at all — fixed with `HOME=/data` on the runner container (operational fix, in `compose.yml`, not this repo); (2) `actions/checkout` is a JavaScript action needing Node in the job container, which `backend`'s `hseeberger/scala-sbt` image doesn't have — fixed with an `apt-get install nodejs` step before checkout (`7e1b492`); (3) that apt-installed Node was Debian bullseye's own stale default (Node 12), too old for `actions/checkout@v4`'s modern JS — fixed by installing a real current Node 20 via NodeSource's setup script instead (`2c78ae8`). See `CONTINUOUS_INTEGRATION.md` for the full detail | Yes — `ci.yml #5` (commit `2c78ae8`) verified green in the Gitea Actions UI via user-provided screenshot (2m24s), both jobs passing |
|
||||
| 2026-08-24 | `2c44888`–`b0b58d2` | Replace the hardcoded per-route static-file list (`/station`, `/cities`, `/latvia`, `/database`, `/harmonie`, `/lvgmc-forecast`, `/bridinajumi`) with a general SPA fallback: real files serve as-is, anything else falls back to `index.html` so the SolidJS router handles it client-side — fixes a real, user-reported bug where a direct hit (e.g. a browser refresh) on `/faktiska` or `/udens-temperatura` 404ed instead of loading the app, since those two routes were never added to the old list. A missing file under `/assets` specifically still 404s properly rather than silently serving HTML, so a stale tab after a future deploy gets a clean error instead of a confusing JS parse failure | Yes — first attempt silently no-op'd because the fix was built into a `git archive HEAD` image before being committed (classic mistake, caught immediately by re-testing and finding identical old behavior); after committing, verified via curl on all previously-working routes, both previously-broken routes, a missing asset (404), a real asset (200), and `/api` (200), then a full headless-browser render check (zero console errors, real data, correct nav state) on a genuine direct hit — not just HTTP status codes; deployed to VPS in release `b0b58d2`, verified the same way through both the loopback port and the public domain (Authelia gate still correctly redirects unauthenticated requests) |
|
||||
|
||||
Reference in New Issue
Block a user