Skip to content

barakoCMS 4.0

Arnel Robles edited this page Sep 7, 2026 · 1 revision

barakoCMS 4.0

The 4.0 line. This page is what changed, what is new, the one structural decision behind the release, the known issues, and how to move from 3.x.

barakoCMS is a headless CMS on .NET and Postgres (Marten). 4.0 is the release where it commits to being the API, hardens authorization down to per-capability gates, and ships the integration builder (connectors, requests, queries, workflows) that lets a site configure an integration instead of coding one.

The one structural decision: barakoCMS is the API, the console is barakoBrew

Through 3.x the admin UI lived in this repository under admin/. In 4.0 it does not. The console is its own project at BaryoDev/barakoBrew and still ships as ghcr.io/baryodev/barako-admin; the marketing site has its own repository too (#505).

Why split it:

  • The two have different release cadences. An API contract change and a screen that reads it no longer have to ship in the same commit, and should not.
  • It makes the API the product. A consumer, any consumer, talks to the same HTTP surface the console does. That surface is now a written, versioned contract rather than an internal detail (#630, #637): every response carries X-Api-Contract-Version, and /api/public has a written stability and deprecation policy.
  • It keeps the core honest. If the console cannot do something without a private endpoint, that is a gap in the public API, and now it shows.

The trade the split creates is that an API change can break the console silently, because they no longer share a commit. Closing that (an OpenAPI diff in CI) is tracked in #629 and is the main open item against 4.0.

Version pairing: CMS 4.0.0 pairs with barakoBrew 1.0.0. From here they move together (4.1.0 with 1.1.0, 5.0.0 with 2.0.0).

What is new

Integration builder (#325). Configure an outbound integration instead of writing one.

  • Connectors hold a third party's credentials in one place, encrypted and write-only (#326).
  • Requests are the call to make through a connector, held as configuration (#327).
  • Queries fetch the rows a payload needs beyond the entry that triggered it (#328).
  • A workflow runs them, records every attempt, and can retry (#329). Each of connectors, requests, queries and workflow runs has an admin screen.

Content modelling.

  • Content type blueprints: a site starts from a named set of types rather than an empty schema (#109).
  • States and transitions: a content type declares its own states and the named moves between them; a workflow can trigger on a transition, so approving routes differently from editing, and approving is a separate right from editing (#340, #341, #342).
  • Event sourcing is per type: a content type opts in by name, with expected-version concurrency (#331, and DECISIONS D1 through D7).
  • SEO fields, URL redirects so a rebuild does not break links, a media library (alt text, caption, where-used), a geopoint field with a proximity filter, and document-type concurrency so a second write no longer silently overwrites the first (#565).

Modules. A module is found by reference and chosen by configuration (#170, #172). A module author starts from a template and tests on a packable host (#174). GET /api/modules reports what an instance actually booted with. The schema a module needs is checked before it runs (#519). Fourteen module packages ship, all versioned 4.0.0, all free.

Delivery and operations. An SMTP email provider (#125), a spreadsheet import screen (#126), a content-change event stream, a job queue whose enqueue shares the request's transaction (#106), a searchable and status-filtered entries list (#440), and multi-architecture images so 4.0 runs on arm64 including the project's own playground (#333).

Security

4.0 is the release where authorization stopped depending on role names.

  • Capabilities, not role names (#443). Every core and module endpoint now asks for a capability the caller's roles carry, rather than a role name checked in C#. Roles are data: a deployment defines its own with any subset of the capability set. The legacy role-name fallback is off by default (#492).
  • Tenancy at the database (#446). Postgres can enforce tenant isolation as a second boundary behind the application check (DECISIONS D11).
  • Registration no longer creates a live account for an unverified email (#268, DECISIONS D10). Uploads can be malware-scanned before they are stored (#138). Webhook secrets are protected on every action type and redacted correctly, including the URL path where Discord, Slack and Teams carry the secret (#526, #606). Access tokens issued before a security event are refused (session epoch), and webhook deliveries are signed (#95).

Four findings from the pre-tag security pass were fixed before the tag (PR #647): an Admin could grant itself SuperAdmin, any tenant admin could read every tenant's audit log, a deployment could boot on the placeholder JWT key shipped in the k8s manifest, and the RSS feed passed authored HTML through unescaped. Each has a regression test.

The wider pass confirmed clean under live attack: JWT and refresh handling, MFA and device gates, SSRF, SQL injection, path traversal, secret redaction, public-delivery field hiding, CORS and host-header handling, and the full capability matrix (every capability allows only its own endpoints).

Known issues

Filed and deferred past the tag. None is a release blocker; each has a repro and a milestone.

Issue What Milestone
#648 Some malformed or boundary input returns 500 instead of a 4xx 4.0.1
#649 A backslash in a redirect target can make an open redirect 4.0.1
#650 Content-type field count is uncapped 4.0.1
#651 Forwarded-header trust is the whole bridge range, not the proxy 4.0.1
#652 OAuth state token uses a GUID rather than a CSPRNG 4.0.1
#653 API-key scope treats erase and rollback as ordinary writes 4.0.1
#654 Response hygiene: no-store on auth responses, Server banner, config-hint 500s 4.0.1
#640 A locked account answers 423, which enumerates users 4.0.1
#655 CreateWorkflow binds the domain entity as its request DTO 4.1.0
#629 The API owes the console an OpenAPI-diff check so a change cannot break it silently 4.0.0
#394 Versioned image tags were amd64 only; fixed in code, proven on the tag 4.0.0

Upgrading from 3.x

  • The migration is migrations/4.0.0/3.x-to-4.0.sql, and the way back is migrations/4.0.0/rollback-to-3.x.sql (which now parses; it did not before #604).
  • The admin console moves to barakoBrew. Point it at your API's DOMAIN_API; the DOMAIN_ADMIN Caddy route is gone.
  • Production runs the published images from docker-compose.prod.yml, which requires real secrets with no defaults. Do not apply the k8s manifests without replacing every placeholder; the app now refuses to start on the placeholder JWT key.
  • The legacy role-name fallback is off. A deployment that relied on a role name opening a gate must grant the matching capability to that role.

Support and licence

barakoCMS is MPL-2.0. Every module BaryoDev publishes under the barakocms-module tag is free, wherever it lives; other vendors may publish and charge for their own modules. The software carries no SLA; hosting and support are a separate commercial relationship. The 3.x line is supported until 12 months after 4.0 is tagged.

Clone this wiki locally