Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/install-uat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
45 changes: 45 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion docs-site/docs/release-notes/v0.13.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 61 additions & 0 deletions docs-site/docs/release-notes/v0.13.1.md
Original file line number Diff line number Diff line change
@@ -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).
Loading