Commit Graph
25 Commits
Author SHA1 Message Date
openhands 6793f77733 fix(deploy): stub git status in the simulation harness
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 33s
CI / tests-integration (push) Successful in 1m37s
CI / tests-unit (push) Successful in 1m39s
CI / tests-ui (push) Successful in 2m20s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 3m6s
The clean-tree guard in ci-deploy.sh aborts the release when
`git status --porcelain` prints anything. The harness stubs `git` as a
shell function that only special-cases `rev-parse`; every other
subcommand fell through to its `ls-remote`-shaped printf, so `git status`
emitted a fake refs/heads/main line and the guard failed on every
scenario.

Introduced in fdb7af7e, which added the guard without teaching the
harness about it, so all 21 deploy tests have been failing since. This
stubs `status` to report a clean tree, and adds a scenario that asserts
the guard actually stops a release before it builds, migrates or starts
anything — the guard itself had no coverage, which is how it could break
silently in the first place.
2026-10-10 17:26:12 +02:00
openhands fdb7af7ef5 fix(deploy): unblock every rebuild on BuildKit's host-network refusal
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 33s
CI / tests-unit (push) Failing after 2m4s
CI / tests-integration (push) Successful in 2m6s
CI / tests-ui (push) Successful in 2m43s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
Docker 29.1.3 ships BuildKit v0.26, which refuses to grant a build host
networking unless each caller passes --allow=network.host. All three rebuild
paths asked for it, and `docker compose build` has no flag to grant it, so a
rebuild failed immediately with "additional privileges requested". The live
container was never replaced, which is exactly the reported symptom: the site
kept serving the previous release after a rebuild.

Nothing in the build actually needs host networking. It uses the network only
for apk, pnpm and next/font/google — all outbound internet, which the default
bridge provides. Verified by building both the full runner image and the
migrations stage with --no-cache after dropping the flag.

Runtime `network_mode: host` stays: blue/green needs per-release host ports
(3002/3003) and nginx reaches each slot over 127.0.0.1.

The second gap is how a rebuild could still ship the wrong code. ci-deploy.sh
stamped every image with HEAD's revision label, and verify-deployed-release.mjs
only re-checks that same label, so a dirty working tree produced an image that
claimed to be release $sha while containing uncommitted code. docker-update.sh
already refused this; ci-deploy.sh now does too, before any build work.
2026-10-10 13:07:13 +02:00
openhands 5b2eb91c5c fix(ops): stop a compose replica from blocking the blue/green release
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m57s
CI / tests-unit (push) Successful in 2m3s
CI / tests-ui (push) Successful in 2m49s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m48s
The deploy failed after the build, the migrations and the browser gate:
"Port 3002 is already in use". The holder was `epicnext-cms`, a compose
replica of release 6bffc537 that the daily scripts/docker-update.sh cron
had recreated at 03:30 with restart=unless-stopped. nginx serves the green
slot on 3003, so that replica was squatting the blue slot the next
candidate needed, and live traffic never noticed.

It got there because the updater's CI-ownership guard only tested
epicnext-cms-app. After a cutover to the green slot that container is
stopped, renamed and deleted, so the guard stopped firing while the host
stayed CI-managed.

- scripts/docker-update.sh: refuse a compose deployment on a CI host by
  checking both slot containers and the nginx upstream, which is the only
  thing that still marks the host as blue/green while a slot is idle.
- scripts/ci-deploy.sh: retire a compose replica of this checkout from
  the candidate port before starting the candidate, so a stray replica
  can never block a release again. Never a slot container, never the port
  nginx serves; anything else still fails loudly in assert_port_free.
- Tests cover both directions: a squatting replica is removed and the
  release lands, a replica on the live port is left alone.
2026-10-05 21:13:49 +02:00
openhands 8218039c64 test(live): stop the live suites inheriting the production database
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 31s
CI / tests-unit (push) Successful in 1m57s
CI / tests-integration (push) Successful in 2m1s
CI / tests-ui (push) Successful in 2m51s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 1m42s
Seven suites read .env with a bare `process.env[key] = value`, which
overwrites whatever the shell already set. That made the DATABASE_URL from
the production .env authoritative, so a single environment variable was
enough to aim them at the live hotel database:

  RUN_CATALOG_AUDIT_LIVE=1 pnpm vitest run src/lib/services/catalog-audit-repair-live.test.ts

Three of those suites then repair the catalog in place: catalog-audit-repair-live
and catalog-repair-direct-live rewrite catalog_items and delete duplicate
classnames, and clone-bulk-import-live bulk-imports every cloneable item. None
of that is undoable, and nothing in their output said the target was
production rather than a sandbox.

Added src/test/live-env.ts with one shared loader, and pointed all seven suites
at it:

- Values already in the real environment win, so an explicit DATABASE_URL on
  the command line is always respected.
- DATABASE_URL defaults to the sandbox on port 3307 rather than inheriting the
  production one from .env.
- Anything that is not loopback is treated as production and redirected.
- Reaching production requires ALLOW_PRODUCTION_LIVE_DB=1 and logs a warning
  saying the suite repairs the catalog.

Tests in src/test/live-env.test.ts run the loader against a temporary .env so
the real project file is never read, and cover the redirect, the shell
override, non-loopback detection, the opt-in and quote stripping. A second
block asserts each of the seven suites no longer contains an inline
`process.env[...] =` assignment. Verified four of them fail against the old
loader.

This does not enable the suites; they stay gated behind their RUN_* flags.
It only removes the possibility of them silently hitting production.

Unit suite: 3330 passed, 12 skipped. Typecheck and lint clean.
2026-10-03 19:03:28 +02:00
openhands 8ee144745a fix(deploy): stub ss in the deploy harness and cover the port-conflict path
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m47s
CI / tests-unit (push) Successful in 1m54s
CI / tests-ui (push) Successful in 2m40s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 1m41s
The port-conflict guard added in the previous commit made the six existing
blue/green deployment simulation tests fail. assert_port_free() shells out to
ss, and the simulation harness stubs git, curl, docker, nginx, pnpm and node —
but not ss. Because the runner is self-hosted and the containers use
--net=host, the simulation saw the production CMS containers holding 3002 and
3003 and refused to start its own candidate.

The harness now stubs ss. It reports no listener for every scenario except
'port-taken', which reserves whichever port the script asks about, so the
simulation stays independent of the host it runs on.

Also switched the ss probe from `command -v ss` to `type ss`. The stub is a
shell function delivered through BASH_ENV; `command -v` happens to find it,
but `type` is the reliable test for "is this resolvable", and the two differ
across shells.

Added a regression test for the guard itself: with the candidate port already
occupied, the deploy must fail, must not have run `docker run`, and must leave
the nginx upstream untouched on the old port — no half-finished cutover.
Verified it fails when the assert_port_free call is removed.

Deploy simulation: 26 passed. Full unit suite: 3316 passed, 12 skipped.
2026-10-03 18:30:00 +02:00
openhands e4f83a8036 chore: upgrade to pnpm v12, vitest v5 and resolve deprecated subdependencies
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Failing after 21s
CI / tests-unit (push) Skipped
CI / tests-integration (push) Skipped
CI / tests-ui (push) Skipped
CI / preflight (push) Skipped
CI / deploy (push) Skipped
2026-09-27 19:42:34 +02:00
openhands 420210ffa0 fix(build): make the production build pass, and stop it eating 20GB
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m39s
CI / tests-unit (push) Successful in 1m43s
CI / tests-ui (push) Successful in 2m31s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m17s
`next build` had never completed on this host, so three real defects were
sitting in the tree untested. All three are now fixed and the build is green.

- The build was not memory-bound the way it looked. Turbopack's builder reached
  20.5GB RSS and died, and raising `--max-old-space-size` could never have
  helped: that flag caps the V8 heap, while the 20GB sat in Turbopack's own Rust
  allocator. The first symptom was misleading because the process doing the
  allocating is a grandchild of `npx`, so watching the direct child shows a
  95MB shim the whole time. Building with `--webpack` puts the build back under
  the JS heap, where the flag actually applies: peak 5.9GB, 150s, exit 0.

- withAdmin's second parameter was typed `{ params?: ... }` and given a `= {}`
  default, which made it optional and `RouteContext | undefined`. Next's
  generated route types assert that argument against `ParamCheck<RouteContext>`
  and reject it, across 113 route files. `tsc --noEmit` cannot see this, because
  Next only adds `.next/types` to the project during a production build — so the
  type check that everyone runs locally was structurally incapable of catching
  the only type error that blocks a deploy. `params` is now required, which is
  also what the code already assumed: it is awaited with no guard. The 35 test
  call sites that invoked a handler with one argument now pass a real context,
  and the await got a guard so a direct internal call cannot turn a missing
  context into a 500.

- `src/app/api/admin/import/furni/route.ts` re-exported `ensureDirectories` and
  `importSingleFurni` for "backward compatibility" that nothing used; the batch
  route imports from `@/lib/services/furni-import` directly. Next rejects any
  value export from a route module that is not an HTTP verb or config, so this
  had been breaking the build for as long as it existed. Removed.

- `isomorphic-dompurify` builds its server-side DOM through jsdom. Bundled, that
  pulls jsdom's `browser/default-stylesheet.css` into the server chunk, where the
  path no longer resolves, and page-data collection dies with ENOENT on every
  page that sanitizes HTML. Marked external so Node resolves it from
  node_modules and the standalone tracer includes it.

The remaining build warning is a pre-existing circular dependency between
chunks that share the webpack runtime. It costs hash reuse, not correctness, and
is left alone rather than churned here.

Verified: build exit 0, 276 static pages generated, 3223 tests pass, tsc and
biome clean.
2026-09-25 19:47:10 +02:00
openhands 93862c2275 lint: fix biome issues in new test files and helpers
CI / check (push) Failing after 34s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
2026-09-21 18:19:39 +02:00
openhands 99eb3af17b test: add ~100 unit tests + bugfixes (theme-resolver, actions, services, features)
CI / check (push) Failing after 26s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
- 100% coverage on 58 src/actions/*.ts, 24 src/lib/services/*.ts, 19 src/features|db|hooks|i18n/*.ts
- 3 core lib modules (theme-resolver, ip-lookup, translation-pool): 100%
- ~3,000 new meaningful tests
- Bugfixes:
  - theme-resolver: generateScopedCss now emits scoped CSS blocks (was early-return bug)
  - admin-radio-api-keys: blank rateLimit now uses fallback
  - admin-badge-upload: validation before try-block to prevent swallowed redirect
- Coverage raised from 26% -> 34% statements
2026-09-21 18:11:15 +02:00
openhands 8638e81444 refactor(db): typed query helpers, shared test FormData helper
CI / check (push) Successful in 4m10s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m4s
Replace raw db.execute tuple casts with queryRows/rowsFrom/execResult/
affectedRows helpers from lib/db, drop redundant mysql2 casts on typed
query builders, and centralize per-test fakeForm into test/fake-form.
Update db mocks in tests so helpers resolve against mocked execute.
2026-09-17 21:02:57 +02:00
openhands faa37e7c58 fix(ci): restore preflight image cleanup marker and remove obsolete publish-container tests
CI / check (push) Successful in 4m23s
CI / preflight (push) Skipped
CI / deploy (push) Failing after 5m37s
- Restore build_attempted=1 in ci-preflight.sh so the exit trap
  removes the temporary image tag
- Remove publish-container.test.ts and its harness (publication
  workflow and script were removed in fff284aa)
- Update deploy-workflow-contract and docker-build-contract tests
  to assert that publication has been removed
2026-09-15 11:29:20 +02:00
Simo 33a760ab6b ci: verify isolated Docker news journeys before merging to main
CI / check (push) Successful in 4m23s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped
CI / preflight (push) Successful in 1m36s
2026-09-13 21:05:02 +02:00
Simo 7867bf6b72 test(news): gate deployment on an isolated real browser publication journey
CI / check (push) Successful in 3m28s
CI / deploy (push) Successful in 18s
CI / publish-container (push) Successful in 2m47s
2026-09-13 20:27:04 +02:00
Simo 8f55ff2d17 feat(docker): guide clone installation and validate paired update artifacts
CI / check (push) Failing after 1m18s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped
2026-09-13 17:57:14 +02:00
Simo 88790d1a0d feat(cms): recover drafts and failed imports with verified UI workflows
CI / check (push) Successful in 2m3s
CI / deploy (push) Successful in 1m31s
CI / publish-container (push) Successful in 1m41s
2026-09-11 08:58:10 +02:00
Simo 27447ce029 feat(docker): add guided install and saved one-command updates
CI / check (push) Successful in 53s
CI / deploy (push) Successful in 1m9s
CI / publish-container (push) Successful in 46s
2026-09-09 20:49:05 +02:00
Simo 8dc187483c fix(ci): verify registry upload against exported OCI config
CI / check (push) Successful in 51s
CI / deploy (push) Successful in 1m9s
CI / publish-container (push) Successful in 54s
2026-09-09 20:33:14 +02:00
Simo 2af244b634 fix(ci): publish registry blobs in bounded chunks
CI / check (push) Successful in 52s
CI / deploy (push) Successful in 1m6s
CI / publish-container (push) Failing after 1m2s
2026-09-09 20:22:07 +02:00
Simo c389c3893d feat(cms): improve catalog, editorial recovery and operations
CI / check (push) Successful in 52s
CI / deploy (push) Successful in 2m10s
CI / publish-container (push) Failing after 1m18s
2026-09-09 19:36:15 +02:00
openhands 2a1aef1c1b fix: complete Playwright removal in CI deploy workflow
CI / check (push) Successful in 1m13s
CI / deploy (push) Successful in 2m9s
Drop the leftover Playwright browser install and e2e smoke test from the deployment script, and update the deployment contract tests to cover the verify-deployed-release smoke check instead.
2026-09-08 16:47:39 +02:00
Simo c4496e710b feat(docker): prepare portable images with runtime hotel configuration
CI / check (push) Successful in 1m6s
CI / deploy (push) Successful in 1m23s
2026-09-07 22:37:53 +02:00
Simo 745d0b7247 feat(docker): restore failed Compose updates and retain recent releases
CI / check (push) Successful in 1m7s
CI / deploy (push) Successful in 1m20s
2026-09-07 22:10:13 +02:00
Simo cbaa115d56 fix(deploy): verify Docker clone updates against the served release
CI / check (push) Successful in 59s
CI / deploy (push) Failing after 1m21s
2026-09-07 21:17:34 +02:00
Simo 7c1f109a9d ci: serialize deployments and restore previous release on smoke failure
CI / check (push) Successful in 1m7s
CI / deploy (push) Successful in 1m9s
2026-09-06 11:48:20 +02:00
SimoandCursor ef2c3324b4 Prune unused deps, bump safe minors, add server-only guards.
Local Build and Deploy / deploy (push) Failing after 15s
Remove unused translate/jpeg types packages; refresh patch updates; mark Redis/site-settings/gamedata hotel as server-only with a Vitest stub.

Co-authored-by: Cursor <[email protected]>
2026-07-17 22:53:56 +02:00