Skip to content

fix(release): CGO=0-safe pure-Go sqlite driver + thin all-in-one image - #5662

Merged
norman-abramovitz merged 8 commits into
cloudfoundry:developfrom
nabramovitz:fix/release-cgo0-sqlite-aio
Jul 21, 2026
Merged

fix(release): CGO=0-safe pure-Go sqlite driver + thin all-in-one image#5662
norman-abramovitz merged 8 commits into
cloudfoundry:developfrom
nabramovitz:fix/release-cgo0-sqlite-aio

Conversation

@nabramovitz

Copy link
Copy Markdown
Contributor

Why

v5.0.0-rc.1 is broken for its default database in every deployment mode. The
release binaries cross-compile with CGO_ENABLED=0, but the sqlite driver was
mattn/go-sqlite3 (cgo-only). At CGO=0 it compiles to a stub that errors on the
first DB touch. Every shipped config (run-local config.example, cf, all-in-one)
defaults DATABASE_PROVIDER=sqlite, so run-local, cf push, and the all-in-one
image were all broken. Tests were green only because go test defaults CGO_ENABLED=1.

What

  • Pure-Go sqlite driver. Swap mattn/go-sqlite3ncruces/go-sqlite3
    (sqlite compiled to wasm, run on wazero). It registers the same "sqlite3"
    driver name, so datastore, goose migrations, and the session store are
    unchanged. CGO=0 cross-compiles now produce fully static, sqlite-capable
    binaries on all platforms.
  • Drop the mattn transitive. nwmac/sqlitestore blank-imported
    mattn/go-sqlite3, re-registering "sqlite3" and colliding with ncruces.
    Stratos only calls NewSqliteStoreFromConnection with an already-open
    *sql.DB, so the 344-line MIT store is vendored into
    repository/sqlitestore/ minus that dead import. Drops both mattn and
    nwmac from go.mod.
  • Force CGO_ENABLED=0 in the single-platform backend build so the build
    is no longer host-dependent (native linux implicitly went CGO=1 and masked
    the bug; mac cross went CGO=0 and broke).
  • Thin all-in-one docker image. New deploy/all-in-one/Dockerfile
    (debian:bookworm-slim, COPY prebuilt jetstream + ui, no source build),
    make release aio, and a build-all-in-one-image release job that pushes to
    ghcr. Deletes the broken deploy/Dockerfile.all-in-one.
  • Docs + changelog. 5.0.0 CHANGELOG entry; console image references point
    at ghcr.io/cloudfoundry/stratos.

Verification

  • CGO_ENABLED=0 go test . -run TestConsoleSetup passes (was the stub failure).
  • grep -c mattn/go-sqlite3 src/jetstream/go.mod → 0.
  • Ran the CGO=0 ncruces binary live: logged into the console, listed apps/orgs
    from a token decrypted out of sqlite.
  • docker run of the AIO image serves and reads sqlite.

The release binaries are cross-compiled with CGO_ENABLED=0, but the sqlite
driver was mattn/go-sqlite3 (cgo-only). At CGO=0 it compiles to a stub that
errors on the first DB touch ("requires cgo to work"). Every shipped config
(run-local config.example, cf, all-in-one) defaults DATABASE_PROVIDER=sqlite,
so all three deployment modes were broken for their default DB. Tests passed
only because `go test` defaults CGO_ENABLED=1.

Swap to modernc-style pure-Go: ncruces/go-sqlite3 (sqlite compiled to wasm,
run on wazero). It registers the same "sqlite3" driver name, so datastore,
goose, and the session store keep working unchanged, and CGO=0 cross-compiles
now produce fully static, sqlite-capable binaries on all platforms.

nwmac/sqlitestore (the sqlite gorilla session store) blank-imported
mattn/go-sqlite3, which re-registered "sqlite3" and collided with ncruces.
Stratos only calls NewSqliteStoreFromConnection with an already-open *sql.DB,
so vendor the 344-line MIT store into repository/sqlitestore/ minus that dead
import. This drops both mattn/go-sqlite3 and nwmac/sqlitestore from go.mod.
`make build backend PLATFORM=...` (used by the cf/korifi paths) ran `go build`
without setting CGO_ENABLED, so it inherited Go's host-dependent default:
CGO=1 when the target matches the host (native linux CI), CGO=0 when cross
(mac). That made the cf zip's sqlite work-or-not depend on where it was built.
Pin CGO_ENABLED=0 to match cross-compile.sh, so every backend build is the
same static, pure-Go binary regardless of host.
…facts

The docker/all-in-one deployment mode (mode 3) was broken: the old
deploy/Dockerfile.all-in-one built current source on splatform/stratos-*
:leap15_2 (Node 12), which cannot run the ESM/bun build, and docker.yml
referenced a non-existent deploy/all-in-one/Dockerfile so its job silently
skipped and reported green while shipping no image.

Rebuild it as a thin image that reuses what the release already produces —
now possible because the CGO=0 binaries are sqlite-capable (pure-Go driver):

- deploy/all-in-one/stage-aio.sh assembles dist/aio-package/ from the
  release-built jetstream + ui + templates + plugins + all-in-one config,
  and generates dev-certs. It builds nothing.
- deploy/all-in-one/Dockerfile COPYs that payload onto debian:bookworm-slim.
  No Node/Go toolchain, no source build. One image serves both `docker run`
  (HTTPS :5443) and `cf push -o` (VCAP -> $PORT via cloudfoundryhosting).
- make release aio wires the staging into the verb system (actions.mk +
  Makefile), so `make release cf github aio` composes in one pass.
- release.yml stages the payload and a new build-all-in-one-image job pushes
  ghcr.io/<owner>/stratos, built for prereleases too so rc tags get an image.
- docker.yml's silent-skip all-in-one job is removed (superseded here).

Deletes the broken deploy/Dockerfile.all-in-one. linux/amd64 only for now.
Validated: docker run of the image serves :5443 and reads sqlite live.
The changelog had no entry past 4.5.0 (2023) — nothing for the 5.0.0 line.
Add a 5.0.0 section covering the signal-native frontend rebuild, Tailwind v4 /
OKLCH theming, the pure-Go sqlite fix, the three reuse-the-same-artifacts
deployment modes, and the GitHub Actions release automation, so the release
notes have real content to extract.
The release pipeline publishes the all-in-one console image to
ghcr.io/cloudfoundry/stratos, but the deploy docs and manifest still told
users to pull splatform/stratos:stable from Docker Hub (never published by
this pipeline). Update manifest-docker.yml, the all-in-one guide, and the
cloud-foundry docker-image push method to ghcr.io/cloudfoundry/stratos:latest.
The separate splatform/stratos-uaa dev image is left as-is (not published here).
Comment thread src/jetstream/repository/sqlitestore/sqlitestore.go Fixed
Comment thread src/jetstream/repository/sqlitestore/sqlitestore.go Fixed
The vendored sqlitestore emits session cookies via http.SetCookie whose
Secure flag comes from the runtime session.Options. initSessionStore already
sets Options.Secure = true for every provider, so this was correct at runtime,
but CodeQL (go/cookie-secure-not-set) cannot trace the runtime option and
flagged both SetCookie sinks once the store moved in-tree. The sibling
pg/mysql stores have the same pattern but live in external deps CodeQL does
not scan.

Set Secure = true locally at both sinks (Save and Delete). Stratos serves the
console over HTTPS in every mode, so this is behavior-preserving and adds
defense-in-depth: the store now guarantees secure cookies independent of the
caller.
Clears four Dependabot alerts:
- js-yaml < 4.3.0 (quadratic CPU via YAML merge-key chains, High) — root
  package.json direct dev dep and the devkit transitive.
- webpack-dev-server <= 5.2.5 (DoS via malformed Host/Origin header; CSRF via
  internal dev endpoints, Moderate) — pinned in the devkit override block.

Bump the root js-yaml to 4.3.0 (bun.lock regenerated), add a js-yaml 4.3.0
override in devkit, and move the devkit webpack-dev-server override to 5.2.6
(package-lock.json regenerated). bun install --frozen-lockfile passes, so this
does not repeat the Dependabot-npm-PR lockfile-mismatch CI failure.
CodeQL go/cookie-secure-not-set tracks the Secure field on the *http.Cookie
handed to http.SetCookie; it does not model gorilla sessions.NewCookie
propagating Options.Secure, so setting session.Options.Secure = true did not
clear the alert. Set cookie.Secure = true on the returned cookie directly in
Save and Delete. Behaviour is unchanged (Stratos already runs HTTPS-only and
initSessionStore forces Options.Secure = true).

@norman-abramovitz norman-abramovitz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@norman-abramovitz
norman-abramovitz merged commit 9bf03df into cloudfoundry:develop Jul 21, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants