Skip to main content

Portal Controller

Overview​

The Portal Controller syncs Kratix Promises and Resource requests into a developer portal, such as Backstage or Cortex, from a single, unified integration. It replaces the Backstage Controller and SKE Cortex Controller, which are now deprecated in its favour. See Portal Controller for the full documentation.

The release manifest is available at:

http://syntasso-enterprise-releases.s3-website.eu-west-2.amazonaws.com/#ske-portal-controller/

Release Notes​

v0.8.0 (2026-10-23)​

Released via the SKE Operator Helm Chart version 0.104.0

Features​

  • Rerun a portal sync on demand. Add the portal.kratix.io/manual-reconciliation: "true" label to a Promise or Resource request, and the Portal Controller syncs it again. The label removes itself, so you can apply it again later. See Manual reconciliation.

Security Fixes​

  • Rebuilt with Go 1.27.3 to fix CVE-2026-111943 in the Go standard library (crypto/x509).

Maintenance​

  • Base image updates.

v0.7.1 (2026-10-19)​

Released via the SKE Operator Helm Chart version 0.101.1

Bug Fixes​

  • The Portal Controller leaves Kratix's workflow restart label unchanged. This prevents extra portal sync Jobs and stops the controller from consuming a restart intended for Kratix.

Maintenance​

  • Base image updates.

v0.7.0 (2026-10-09)​

Released via the SKE Operator Helm Chart version 0.99.0

Bug Fixes​

  • Cortex portals now sync Promises that have int-or-string fields (x-kubernetes-int-or-string). These fields show as a text input in the generated workflows. Before, the workflows failed to build and nothing was synced.
  • Deleting a Promise synced to Cortex no longer gets stuck.

Maintenance​

  • Base image updates.

v0.6.1 (2026-10-06)​

Released via the SKE Operator Helm Chart version 0.97.0

Features​

  • A Backstage portal can now choose the namespace of a resource request for the developer, using the new requestNamespace setting:

    • from: group: the developer picks one of their Backstage Groups, and the request goes to the namespace named after it.
    • from: group with an annotation: the namespace is read from that annotation on the Group.
    • from: fixed: every request goes to one namespace. Use this instead of the hideNamespace portal-patch recipes.

    These settings need @syntasso/plugin-ske-backend v0.24.0 and @syntasso/plugin-ske-frontend v0.22.0 or later. See Choosing the request namespace.

  • A resource requested for a Backstage Group is now owned by that Group in the catalogue, so it shows on the Group's page. An explicit ske.backstage.component/owner annotation still takes precedence.

  • Cortex requests now appear straight away as a <name> request (pending) entity, owned by the person who asked for it. The end of the workflow links to the entity. Before, nothing appeared until the platform had built the resource. Deleting a request that was never built also deletes its entity.

Maintenance​

  • Base image updates.

v0.5.0 (2026-09-29)​

Released via the SKE Operator Helm Chart version 0.95.0

Backstage Templates now default to a single form page

Generated Backstage Templates now put every spec field on one form page by default. Existing Backstage connections that don't set --single-spec-page switch to the single-page form when you upgrade. To keep the multi-step form, add --single-spec-page=false to the connection's adapterConfig.generate.args before upgrading. If you run ske-portal-adapter directly in your own Promise pipeline, add --single-spec-page=false as a container argument instead: the TEMPLATE_SINGLE_SPEC_PAGE environment variable can't turn the single-page form off. See Portal-wide generate flags.

Features​

  • Generated Backstage Templates now link to the result when a task completes: View in Catalog first, then Pull Request in pull-request mode. The catalogue link goes to the pending entity until the real one exists.
  • Generated Templates now name each step after its outcome and the resource kind, for example "Submitting your Jenkins request". Push-mode Templates now also record whether each run is a create or an update, as pull-request mode already did.

Maintenance​

  • Base image updates. Bump dependencies.

v0.4.2 (2026-09-22)​

Requires SKE v0.59.0

SKE v0.59.0 removed the workflow counters from Promise and resource request status, and this version tracks that change. On earlier Portal Controller versions, resource requests stay unreconciled once SKE is upgraded.

Maintenance​

  • Base image updates. Bump dependencies.

v0.4.1 (2026-09-07)​

Bug Fixes​

  • Resource-request pipelines no longer leak ServiceAccounts and RBAC. Each resource request used to get its own ServiceAccount, Role and RoleBinding, and none of them were ever deleted. The resource-request pipelines of a Promise now share a single set, and deleting a Promise cleans up everything it created — including what earlier versions left behind.

v0.4.0 (2026-08-27)​

Requires SKE Operator v0.34.0

Upgrade the SKE Operator to v0.34.0 first.

Features​

  • The Portal Controller no longer needs the skeintegrations CRD. It reads its connections from a ConfigMap, so it can be installed on its own, without the SKE Operator. See Installing without the SKE Operator.

  • The Jobs the controller creates are now configurable. Labels, annotations and other pod settings come from the ske-portal-workloads-config ConfigMap, so the Jobs can satisfy cluster policies that would otherwise reject them. See Installation.

Bug Fixes​

  • Immutable fields are now declared as immutable in generated Templates, so an edit that would change one is rejected up front rather than failing later.

  • The Portal Controller no longer consumes Kratix's manual-reconciliation flag.

v0.3.0 (2026-08-18)​

Features​

  • Portal Sync condition is now filtered out from the generated Entity.: similar to other Kratix-owned conditions, the Portal Sync conditions are no longer added to the resource Entity when they are generated.

  • Push-mode Templates record the request. A generated push Template now applies the resource request and then hands it to the Backstage backend, so the developer sees a pending request in the catalogue while the platform catches up rather than nothing at all. Pull-request Templates are unchanged.

Upgrade the Backstage plugins first

This release requires ske-backend v0.23.0 and ske-frontend v0.20.0 or later.

Upgrade the plugins before the Portal Controller. Doing it in that order is safe: the new plugins accept everything the current Templates send, so nothing changes until the controller follows.

In the other order, newly generated push Templates carry a record-request step that an older backend rejects. Because that step runs after the request has been applied, the developer sees a failed task for a resource that was in fact created.

v0.2.0 (2026-07-30)​

The first release of the Portal Controller: one integration for every developer portal your platform exposes.

Until now, each portal needed its own controller, its own SKEIntegration, and its own customization CRD. Adding a second portal meant running a second controller, and the two had little in common. The Portal Controller replaces that with a single integration that declares every portal on one resource, generates entities through one pipeline, and gives Promise authors one way to shape what those entities look like.

Both the Backstage Controller and the SKE Cortex Controller are deprecated as of this release. They continue to work, so you can migrate when it suits you. See Migrating from Backstage and Migrating from Cortex.

What you gain over the standalone controllers​

The Portal Controller generates the same entities the standalone controllers did. What changes is everything around them:

Standalone controllersPortal ControllerPortals
Portals per platformOne SKEIntegration per type, so one Backstage and one CortexEvery portal on one SKEIntegration, including two Backstage instances side by sideBoth
Opting a Promise inPer-portal wiringOne label, kratix.io/portal-<type>, and a single Resource can opt back outBoth
Customizing what is generatedBackstage had BackstageEntityCustomization, one pipeline shared by the Promise and its Resources. Cortex had a handful of annotations and no way to edit the generated documentsPortalCustomization with independent promise and resource lanes, for every portal typeBoth
Expressing a customizationTyped entityGenerationOptions fields, or a hand-written containerDeclarative Portal Patch recipes, with your own container still availableBoth
ReportingPer-controllerOne PortalBindingReady condition plus a per-type sync condition and an entity URL annotationBoth
Reviewing requestsNot available: submitting a form applied it immediatelypull-request delivery mode raises the request as a pull request, and update and delete go through review tooBackstage
Where entities are writtenA Destination you create and label environment: backstage beforehandThe portal creates and owns its Destination and state store, or adopts an existing oneBackstage

For Cortex specifically, the headline change is customization. The standalone controller generated its entity and workflows the one way it knew how, and the only levers were annotations. A Cortex portal now runs the same generate → configure → writer pipeline as every other portal, so you can reshape the generated entity and workflows at both the Promise and the Resource level. See Cortex examples.

Two things become portal-wide rather than per-Promise: the Cortex fixed namespace, previously the kratix.io/cortex-fixed-namespace annotation, and the Backstage single-page form. Both are now adapterConfig.generate.args flags on the portal. Where you need them per Promise, the hideNamespaceManifest and singleSpecPage Portal Patch recipes do that job.

Features​

  • One integration, many portals. Declare every portal your platform exposes on a single SKEIntegration of type: portal-controller. Portals of the same type can coexist, so a staging and a production Backstage are two entries rather than two installations. See Installation.

  • Opt in with a label. A Promise or Resource request joins a portal by carrying kratix.io/portal-<type>, instead of needing a dedicated resource per portal. A single Resource can opt back out without affecting its Promise. See Bind a Promise to a portal.

  • Request review with pull-request delivery. Backstage portals can run in pull-request mode, where submitting the generated form raises a pull request against a Git repository instead of applying the request directly. Nothing reaches the platform until a human merges it, and updates and deletions go through the same review. Currently GitHub only. See Delivery modes.

  • Backstage portals manage their own destination. A portal can create and own the Kratix Destination and state store it writes entities to, rather than requiring you to wire one up beforehand. Platforms that already manage Destinations can adopt an existing one instead. See Backstage.

  • Customizable Cortex entities and workflows. A Cortex portal runs the same generate → configure → writer pipeline as every other portal type, so the generated entity and workflows can be reshaped at both the Promise and the Resource level. It also runs a status exporter and a setup Job that provisions the shared entity and relationship types the integration depends on. See Cortex.

  • Shape entities declaratively. The new PortalCustomization resource, which replaces BackstageEntityCustomization, runs containers that edit generated documents before they ship, with separate lanes for the Promise and its Resources. Paired with Portal Patch, most customizations are a few lines of declarative recipe rather than a hand-written script. See Customization.

Known issues​

  • Portal Patch recipes that target the ske-configure-resource step, including hideNamespaceManifest, fail under pull-request delivery mode, because that step only exists in push mode. A recipe that matches nothing aborts the sync, so no entity ships.