From d3e3b2c3760be8c697d850b90a85a9fdca1d8938 Mon Sep 17 00:00:00 2001 From: Haksung Jang Date: Mon, 6 Jul 2026 23:45:41 +0900 Subject: [PATCH 1/2] fix(release): strip Docusaurus front matter from GitHub Release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release job fed docs-site/docs/release-notes/.md into `gh release create --notes-file` verbatim. GitHub renders the body as plain Markdown and does not recognise YAML front matter — worse, the closing `---` is parsed as the setext-heading underline of the metadata block above it, so the entire id:/title:/description:/sidebar_* block rendered as one giant H2 (visible on v0.10.0–v0.13.0). Strip the leading `--- ... ---` front matter with awk before publishing, emitting only the body after the second delimiter. --- .github/workflows/release.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 96758986..02b21866 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -329,7 +329,17 @@ jobs: NOTES_FILE="docs-site/docs/release-notes/${TAG}.md" if [ -f "$NOTES_FILE" ]; then echo "using curated release notes: $NOTES_FILE" - gh release create "$TAG" --draft --title "$TAG" --notes-file "$NOTES_FILE" + # Strip the Docusaurus YAML front matter (the leading --- ... --- + # block). GitHub renders the Release body as plain Markdown and does + # NOT recognise front matter — worse, the closing `---` is parsed as + # the setext-heading underline of the metadata block above it, so the + # whole `id:/title:/description:/...` block renders as one giant H2. + # Emit only the body after the second `---` delimiter. + BODY_FILE="${RUNNER_TEMP}/${TAG}-notes.md" + awk 'NR==1 && $0=="---" {infm=1; next} + infm && $0=="---" {infm=0; next} + !infm {print}' "$NOTES_FILE" > "$BODY_FILE" + gh release create "$TAG" --draft --title "$TAG" --notes-file "$BODY_FILE" else echo "no curated notes for $TAG — auto-generating from history" gh release create "$TAG" --draft --title "$TAG" --generate-notes From f1245af131185dd59463cef0a122f0027389d0ff Mon Sep 17 00:00:00 2001 From: Haksung Jang Date: Tue, 7 Jul 2026 08:38:32 +0900 Subject: [PATCH 2/2] docs(release): prepare v0.13.1 notes and changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.13.1 is a fixes-only patch: it repairs fresh role-separated (L1) installs and deployments (trustedoss_app role creation, AUTO_MIGRATE plumbing, owner-password consistency + staged boot, dev entrypoint auto-migration) and bumps python-multipart 0.0.30 → 0.0.31 for CVE-2026-53540. No feature or schema change. - add docs-site/docs/release-notes/v0.13.1.md - record the 0.13.1 entry in CHANGELOG.md - reorder v0.13.0 note (sidebar_position 1 → 2) so v0.13.1 sits on top - bump install-uat's default IMAGE_TAG 0.13.0 → 0.13.1 --- .github/workflows/install-uat.yml | 6 +-- CHANGELOG.md | 45 ++++++++++++++++++ docs-site/docs/release-notes/v0.13.0.md | 2 +- docs-site/docs/release-notes/v0.13.1.md | 61 +++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 docs-site/docs/release-notes/v0.13.1.md diff --git a/.github/workflows/install-uat.yml b/.github/workflows/install-uat.yml index 884fb861..1e0b34ff 100644 --- a/.github/workflows/install-uat.yml +++ b/.github/workflows/install-uat.yml @@ -34,7 +34,7 @@ on: pull_image_tag: description: "Published IMAGE_TAG to verify the ghcr pull path against (e.g. 0.13.0)." required: false - default: "0.13.0" + default: "0.13.1" type: string schedule: # Weekly Sunday 03:00 UTC — catches drift from base image / dep updates. @@ -231,7 +231,7 @@ jobs: env: # A known-published tag, NOT the repo ref — the commit under test may # predate any release. Override on dispatch via `pull_image_tag`. - IMAGE_TAG: ${{ github.event.inputs.pull_image_tag || '0.13.0' }} + IMAGE_TAG: ${{ github.event.inputs.pull_image_tag || '0.13.1' }} # The published-image services need these to be set for `config` to # interpolate without warnings; values are irrelevant to a pull. DOMAIN: example.invalid @@ -299,7 +299,7 @@ jobs: env: # Published image set, resolved through the production docker-compose.yml # exactly as an operator would. Override IMAGE_TAG on dispatch if needed. - IMAGE_TAG: ${{ github.event.inputs.pull_image_tag || '0.13.0' }} + IMAGE_TAG: ${{ github.event.inputs.pull_image_tag || '0.13.1' }} IMAGE_REGISTRY: ghcr.io/trustedoss # APP_ENV=dev matches install.sh's default .env (it copies .env.example, which # pins APP_ENV=dev, and never sets prod). It also lets the smoke reach the API diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dba787c..f33ba7e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,51 @@ and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0. ## [Unreleased] +## [0.13.1] — 2026-07-07 + +A fixes-only patch release: repairs fresh role-separated (L1) installs and +deployments, and picks up a security bump. No feature or schema changes. + +### Fixed +- **L1 role provisioning: `trustedoss_app` was never created.** + `scripts/postgres-init.sh` interpolated the role name / password inside a + dollar-quoted `DO $$ … $$` block, where psql performs no variable + substitution, so the literal `:'app_user'` reached the server and aborted the + init script (`syntax error at or near ":"`). Every L1 backend then failed + password auth as `trustedoss_app`. Role creation now uses `SELECT format(…) + … \gexec` with `WHERE NOT EXISTS` — SQL-quoted and idempotent. (#466) +- **`AUTO_MIGRATE` was never plumbed into the container.** `install.sh` writes + `AUTO_MIGRATE=false` on L1 stacks (migrations run once as the owner role), but + the compose file never referenced `${AUTO_MIGRATE}`, so the backend entrypoint + defaulted back to `true` and attempted DDL as the unprivileged app role. (#466) +- **install.sh L1 path: owner-password consistency + staged boot.** The secret + block is now idempotent — `POSTGRES_PASSWORD` is the single source of truth for + the owner password and is never rotated on re-run — and boot is staged + (postgres+redis+backend → wait `/health` → owner-role `alembic upgrade head` → + wait `/health/ready` → full fleet) so the worker's `depends_on backend: + service_healthy` no longer deadlocks under `AUTO_MIGRATE=false`. A fresh + install now also generates a strong random owner password instead of the + shipped default. (#470) +- **Dev backend image now auto-migrates.** `apps/backend/Dockerfile` had a `CMD` + but no `ENTRYPOINT`, so the dev container skipped `docker-entrypoint.sh` and + never ran its migration — `/health/ready` stayed 503 and the backend was + permanently unhealthy. It now carries the entrypoint like the production + image. (#469) + +### Security +- **`python-multipart` 0.0.30 → 0.0.31** — picks up the fix for CVE-2026-53540. + Ships in the backend image. (#472) + +### Internal +- Release notes are now stripped of Docusaurus front matter before being + published to GitHub Releases (the closing `---` was rendering the metadata + block as a giant heading). (#473) +- Release-gate CI hardening: cold-boot postgres readiness race, dev-runtime + boot mode, docker-compose V1 nested-DSN interpolation, and health-gated + (not `up`-exit-gated) patience. (#462, #463, #464, #465) +- Added L1 role-separated `install-uat` coverage and a `postgres-init` role + contract gate. (#467, #468) + ## [0.13.0] — 2026-07-04 A broad parity release closing the BomLens capability gap — additive throughout; diff --git a/docs-site/docs/release-notes/v0.13.0.md b/docs-site/docs/release-notes/v0.13.0.md index bcd2b704..1178467f 100644 --- a/docs-site/docs/release-notes/v0.13.0.md +++ b/docs-site/docs/release-notes/v0.13.0.md @@ -3,7 +3,7 @@ id: v0-13-0 title: v0.13.0 — parity release (graph, search, Excel, vendored OSS + more) description: A broad feature release closing the BomLens capability gap — dependency graph view, cross-project ⌘K search, Excel reports, a bigger license catalog, KEV surfacing, G7 AI-SBOM conformance, and opt-in SCANOSS vendored-OSS identification. All additive. sidebar_label: v0.13.0 -sidebar_position: 1 +sidebar_position: 2 --- # v0.13.0 — parity release diff --git a/docs-site/docs/release-notes/v0.13.1.md b/docs-site/docs/release-notes/v0.13.1.md new file mode 100644 index 00000000..8a08b8af --- /dev/null +++ b/docs-site/docs/release-notes/v0.13.1.md @@ -0,0 +1,61 @@ +--- +id: v0-13-1 +title: v0.13.1 — install / deploy L1 repair + security patch +description: A patch release that repairs fresh role-separated (L1) installs and deployments, plumbs AUTO_MIGRATE into the container, and bumps python-multipart for CVE-2026-53540. No feature or schema changes. +sidebar_label: v0.13.1 +sidebar_position: 1 +--- + +# v0.13.1 — install / deploy L1 repair + security patch + +A **patch release**: no new features, no schema changes. It fixes fresh +**role-separated (L1) installs and deployments** that could fail to come up, and +picks up a security bump. The full machine-readable changelog lives in +[`CHANGELOG.md`](https://github.com/trustedoss/trusca/blob/main/CHANGELOG.md). + +## Highlights + +### Fresh L1 (role-separated) installs and deployments now boot + +Several confirmed bugs prevented a from-scratch **role-separated** stack — the +posture `install.sh` provisions — from coming up. They only affected L1 stacks +(operators who set `POSTGRES_APP_PASSWORD`); legacy single-role deployments were +unaffected, which is why they went unnoticed until the release gate booted the +production compose file from scratch. + +- **`trustedoss_app` role was never created.** `scripts/postgres-init.sh` + interpolated the role name / password *inside* a dollar-quoted `DO $$ … $$` + block, where psql performs no variable substitution — the literal `:'app_user'` + reached the server and aborted the init script, so every L1 backend then failed + password auth as `trustedoss_app`. Role creation now uses + `SELECT format(…) … \gexec` with `WHERE NOT EXISTS` (SQL-quoted, idempotent). +- **`AUTO_MIGRATE` never reached the container.** `install.sh` writes + `AUTO_MIGRATE=false` on L1 stacks (migrations run once as the owner role), but + the compose file never referenced `${AUTO_MIGRATE}`, so the backend entrypoint + defaulted back to `true` and attempted DDL as the unprivileged app role. The + value is now plumbed through. +- **Owner-password consistency + staged boot.** The install secret block is now + idempotent (`POSTGRES_PASSWORD` is the single source of truth for the owner + password, never rotated on re-run), and boot is staged + (postgres+redis+backend → wait `/health` → owner-role `alembic upgrade head` → + wait `/health/ready` → full fleet) so the worker's + `depends_on backend: service_healthy` no longer deadlocks under + `AUTO_MIGRATE=false`. +- **Dev backend image now auto-migrates.** The dev image (`Dockerfile`) had a + `CMD` but no `ENTRYPOINT`, so it skipped `docker-entrypoint.sh` and never ran + its migration — leaving `/health/ready` at 503 and the backend permanently + unhealthy. It now carries the entrypoint like the production image. + +### Security + +- **`python-multipart` 0.0.30 → 0.0.31** — picks up the fix for + CVE-2026-53540. Ships in the backend image. + +## Upgrade notes + +- **No action required, no migrations.** This is a fixes-only patch; the schema + is unchanged from v0.13.0. +- **Fresh L1 installs should use v0.13.1.** A from-scratch role-separated install + at v0.13.0 could fail to provision `trustedoss_app` or deadlock on boot — both + are fixed here. Existing, already-running v0.13.0 stacks are unaffected. +- Pull the `0.13.1` images (or `helm upgrade` to the `0.13.1` image tag).