Skip to content

RunR 0.6.8

Latest

Choose a tag to compare

@brkfun brkfun released this 07 Nov 22:57
v0.6.8

RunR is an open-source, self-hosted serverless platform on Kubernetes and Knative: functions, containers, sandboxes, WebAssembly and durable workflows, with an API, a web console, the runr CLI, SDKs, a Terraform provider and a GitHub Action. You install it on infrastructure you operate, connected or air-gapped. It is developed by BRF Teknoloji and released under the MIT License.

0.6.8 makes executors dynamic. Platform administrators and organizations connect runtime sources (signed OCI catalogs and Git repositories of runtime.yaml manifests, public or private), and RunR's own built-in runtimes now come from a signed catalog that BRF-Tech/runr-runtimes publishes, so a new language reaches an installation without a RunR release. Java, .NET (C#), Ruby and TypeScript on Bun join the built-in runtimes, the code interpreter runs Java and C#, and docs/executor-development.md with the sample repository BRF-Tech/runr-sample-custom-executor shows how to build an executor for any language. Every runtime, built-in or not, gets the same lifecycle (deprecation, sunset, end of life). Sandbox commands run without a kubectl process, the console warns when its certificate cannot be issued, single-tenant installations get the permission platform.manage for the installation's own pages, the region Traefik moves to chart 42.3.1 with its probe timing in keys the chart reads, kube-prometheus-stack 92.22.0 comes to new regions, and Symfony 7.4.23 clears seven advisories.

One database migration, which only adds a table and columns. The API reads RunR's catalog from ghcr.io (or offline: the bundled catalog, as before). Nothing has to be set.

Install

  • Kubernetes (Helm): the chart comes from BRF's public Helm repository, without credentials:
    helm repo add brf-tech https://helm.brf.sh
    helm upgrade --install runr brf-tech/runr --namespace runr --create-namespace --set domain=runr.example.com
    See the README and docs/install.md; helm show values brf-tech/runr lists every value. A pinned install adds --version 0.6.8; the API and UI images, the region agent and the event gateway follow the chart version.
  • Single host (Docker Compose, also air-gapped): compose/README.md, from a checkout of the release tag (git clone -b v0.6.8 https://github.com/BRF-Tech/runr.git).
  • CLI: curl -fsSL https://runr.sh/install.sh | sh on Linux and macOS. The archives of every platform are at runr.sh/dl (https://runr.sh/dl/cli/v0.6.8/) and attached below; check them against checksums.txt (docs/cli.md#install).
  • Terraform / OpenTofu: source = "brf-tech/runr", version = "~> 0.6", from the Terraform Registry; terraform init checks the archive against SHA256SUMS, signed with the RunR release key (key ID 2588846B241BC095). runr.sh serves the same archives under runr.sh/brf-tech/runr, for OpenTofu and for configurations that use that address (docs/terraform.md#install).
  • GitHub Action: uses: brf-tech/runr/actions/deploy@v0.6.8; it downloads the CLI from runr.sh (docs/github-action.md).
  • Images: every image is published under ghcr.io/brf-tech/runr by release-images.yml, for linux/amd64 and linux/arm64, and pulls anonymously.

The documentation is at runr.sh/docs and in the documentation index here.

Upgrading from 0.6.7

Upgrade in place with helm upgrade of the running release; never uninstall and install again, and back up the database first (Procedure in docs/upgrade.md). From 0.6.7 the images keep their names and nothing has to be set (0.6.7 → 0.6.8).

helm repo update brf-tech
helm upgrade runr brf-tech/runr --version 0.6.8 -n runr --reuse-values
  • One migration, which only adds. 2026_11_07_100001_create_runtime_sources adds the table runtime_sources and nullable columns to runtimes, executor_images, runtime_patches and runtime_patch_feeds; existing runtimes, versions, patches and projects keep what they have (Runtime sources).
  • The built-in runtimes come from RunR's signed catalog. The API creates the default source RunR runtimes (ghcr.io/brf-tech/runr/runtime-catalog:stable, signed with the patch feed's key) and reads it at its start and every 15 minutes; until it has been read once, the catalog of the API image is in use, as in 0.6.7. The API needs to reach ghcr.io for it, as for the patch feed, or a region's registry (runtimeCatalog.viaRegion); an air-gapped installation sets runtimeCatalog.offline: true and keeps the bundled catalog. The upgrade connects no other source.
  • EXECUTOR_RUNTIMES is now only the first default of the platform setting Built-in runtimes, whose default is every runtime of the catalog. An installation that sets EXECUTOR_RUNTIMES keeps its list until a platform administrator saves the setting.
  • Projects without a runtime version are refused once their runtime's default version ends (end of life or sunset), as pinned projects already were; running deployments stay untouched.
  • Java, .NET, Ruby and Bun are offered right after the upgrade with the default of the Built-in runtimes setting. A region whose nodes pull through a mirror of its own needs exec-java, exec-dotnet, exec-ruby, exec-bun and reqs/dotnet-runtime-deps:10.0-chiseled-extra there before a project uses them (New runtimes).
  • Sandbox commands run without a kubectl process. The API opens the exec stream itself (v5.channel.k8s.io); terminal sessions keep kubectl exec -t. kubectl takes over by itself, before a command starts, for a region kubeconfig the native client does not take (an exec plugin, an auth provider, credentials in files, a proxy, impersonation) and for an API server that refuses the upgrade; SANDBOX_EXEC_CLIENT=kubectl (via extraEnv) brings back kubectl for every command (Sandbox commands without kubectl).
  • Check the TLS mode the upgrade renders. The console now warns when cert-manager cannot issue its certificate; the chart adds CONSOLE_TLS_* to runr-config and, with cert-manager, two read rules to the Role runr-api-role (ingress.tls.certificateCheck: false leaves them out). A marketplace that merges the package's default values into an upgrade can give a release that never set ingress.tls.mode the mode letsencrypt: without the ClusterIssuer letsencrypt-prod the console stays on the ingress controller's default certificate, which the warning then reports (The console certificate warning).
  • Single-tenant installations: platform.manage. Their Owners hold it after the upgrade, with no migration, and reach the Patches page, the platform banners and notifications, the console certificate warning and the Horizon dashboard; Admins get it only through a custom role. Multi-tenant installations are unchanged (The installation's own pages on single-tenant installs).
  • The region agent and the event gateway move to 0.6.8. As in 0.6.0 to 0.6.7, after helm upgrade returned, the Job runr-region-reconcile-<revision> moves the regions' agents, queue consumers and topic publishers to ghcr.io/brf-tech/runr/agent:0.6.8 and queue-consumer:0.6.8; each rolls once. A region that pulls through a mirror of its own needs these two images there before the upgrade (Order of operations).
  • The region Traefik moves to chart 42.3.1 by itself (region:reconcile, step traefik-chart): its pods roll once, a new one Ready before an old one goes, now with RunR's probe timing; Traefik stays v3.7.17 and no CRD step is needed (Region Traefik chart 42.3.1).
  • kube-prometheus-stack does not move by itself. php artisan cluster:patch-observability moves a region to 92.22.0 when it suits it: node-exporter restarts once with a stricter security context, nothing else restarts, and nothing has to be mirrored (kube-prometheus-stack 92.22.0).
  • Back to 0.6.7: a helm rollback on the same database; do not roll the migration back. Every function keeps serving, and projects on Java, .NET, Ruby and Bun keep running and deploying on the versions 0.6.8 last discovered, though 0.6.7 does not list these runtimes. A connected source's runtime that discovers its versions loses them under 0.6.7, and the images of a private source cannot be pulled there. The regions' Traefik stays on chart 42.3.1. After going to 0.6.8 again, php artisan runtime-sources:sync --force reads the sources anew (Back to 0.6.7).
  • Terraform provider 0.6.8: it adds the resource and the data source runr_runtime_source.

From 0.6.6, upgrade straight to 0.6.8 and read 0.6.6 → 0.6.7 as well: 0.6.7 changes how sandbox commands travel on Kata and gVisor (a command on gVisor takes about 100 ms more), input that arrives short fails, and a custom sandbox image needs cat and mkfifo. From 0.6.5, also read 0.6.5 → 0.6.6: 0.6.6 re-runs kata-deploy with Kata Containers 4.3.1, which stops the running Kata pods of every region with Kata, the region Traefik moves to chart 42.3.0 and deletes request headers with _ or . in their names, and Reverb refuses client events. From 0.6.4, also read 0.6.4 → 0.6.5: 0.6.5 adds the notification_user_states migration, the Helm value notifications.retentionDays, and its daily task deletes notifications older than 90 days. From 0.6.3, also read 0.6.3 → 0.6.4: 0.6.4 adds the captcha_settings migration and the Helm values captcha.*, and its first upgrade rolls the pods once. From 0.6.2, also read 0.6.2 → 0.6.3; from 0.6.1, also 0.6.1 → 0.6.2. From 0.6.0, also read 0.6.0 → 0.6.1 first: before a rollback to 0.6.0, let the running deploys finish (Rolling back to 0.6.0). From 0.5.10, read 0.5.10 → 0.6.0 in docs/upgrade.md first — in particular what to decide before the upgrade — and the notes of 0.6.0 to 0.6.7 in CHANGELOG.md; everything said there applies. From 0.5.9 or earlier, read the notes of the releases in between as well; from 0.5.8 or earlier, add --set api.image.tag= --set ui.image.tag= to that upgrade once (step 3 of the Procedure).

Changes in 0.6.8 (2026-11-08)

Upgrade notes

  • A migration adds runtime sources (2026_11_07_100001_create_runtime_sources): the table
    runtime_sources; runtimes.source_id, source_path, orphaned_at; executor_images.deprecated_at,
    sunset_at; runtime_patches.source_id and runtime_patch_feeds.source_id. It only adds columns
    and a table; existing runtimes, versions, patches and projects are unchanged. See
    docs/runtimes.md.
  • The built-in runtimes now come from RunR's signed catalog ghcr.io/brf-tech/runr/runtime-catalog:stable
    (published by BRF-Tech/runr-runtimes, signed with the patch feed's key), read at the API's start and
    every 15 minutes. Until it has been read once the catalog the API image ships is in use, as before;
    an air-gapped installation sets Helm runtimeCatalog.offline: true (RUNR_RUNTIME_CATALOG_REF="")
    and keeps the bundled catalog. The API needs to reach ghcr.io — or runtimeCatalog.viaRegion
    (default: runtimePatches.viaRegion) — like the patch feed already does.
  • EXECUTOR_RUNTIMES is now only the first default of the platform setting Built-in runtimes
    (Build & Run → Runtimes): its default changed from the list of eleven built-ins to every runtime
    of the catalog
    , so a runtime the catalog gains is offered without a release. An installation that
    sets EXECUTOR_RUNTIMES keeps its list until a platform administrator saves the setting.
  • Projects without a runtime version are refused once their runtime's default version ends
    (end of life or sunset), like pinned projects already were; running deployments stay untouched.
    Before, a project on no version deployed a default that was past its end of life.
  • The API image adds openssh-client for Git sources with an SSH deploy key.
  • The console certificate is checked (0.6.7 → 0.6.8 in upgrade.md).
    When cert-manager issues it, the Role runr-api-role gains get on the console's Certificate and
    list on the CertificateRequests of the release namespace; runr-config gains
    CONSOLE_TLS_MODE, CONSOLE_TLS_ISSUER and CONSOLE_TLS_CHECK. A marketplace that merges the
    package's default values into an upgrade can bring ingress.tls.mode: letsencrypt to a release
    that never set it: without the ClusterIssuer letsencrypt-prod the console stays on the ingress
    controller's default certificate, which the new warning reports. Set ingress.tls.mode: none (or
    the mode you use) in the release's own values.
  • Single-tenant: the Owners now get the Patches page, the platform banners and the platform
    administrators' notifications
    through the new permission platform.manage. Nothing is
    migrated: built-in roles come from the catalog. The Admin role does not hold it; a custom role
    can (0.6.7 → 0.6.8 in upgrade.md).
  • Back to 0.6.7 is a helm rollback without rolling the migration back
    (Back to 0.6.7). 0.6.7 runs on the new table and columns and
    ignores them. Projects on Java, .NET, Ruby and Bun keep running and deploying there: 0.6.8 keeps
    every built-in runtime's manifest on its row, which 0.6.7 reads for the runtimes its own catalog
    lacks. A source's runtime that discovers its versions loses them on 0.6.7, and the images of a
    private source cannot be pulled there. After upgrading to 0.6.8 again, run php artisan runtime-sources:sync --force once where sources are connected.

Added

  • A dependency test bot. Every week (and by hand for one issue), each new version of a region
    dependency that the daily release check filed an issue for (the Traefik, kube-prometheus-stack,
    loki-stack, Zot and kata-deploy charts, a Knative minor) is moved in the development branch with
    every test and doc that names the old version, tested with its suites (PHPUnit, the Kind e2e that
    installs it, and the move of a region installed by the last release), and committed only when
    they pass; the issue is then closed with deps: passed. A failed suite, or a version that is no
    mechanical bump (a new major, changed CRDs, values the chart no longer takes, a new image of the
    reqs mirror), labels the issue needs attention with what failed, and nothing is committed
    (development.md).
  • Runtime sources (docs/runtimes.md): platform
    administrators (for everyone) and organizations (for themselves, while custom runtimes are on)
    connect signed OCI catalogs and Git repositories of runtimes/<id>/runtime.yaml, public or
    private (HTTPS token or SSH deploy key; registry credentials for a private catalog and private
    images). Each source is read periodically and on Sync now; every manifest is validated
    strictly, a bad one is reported with its file and JSON path and does not stop the others; the
    source records its status, revision, last read and problems; its runtimes are enabled or disabled
    one by one. Test connection reads a source before it is saved.
  • RunR's own catalog is a source: the built-in runtimes, a new language of BRF-Tech/runr-runtimes
    offered without a RunR release; builtin.json stays as the offline fallback and the Runtimes page
    says which is in use. The Built-in runtimes setting picks the offered built-ins.
  • Runtime ids stay one namespace with explicit rules: built-in ids are RunR's, the first
    registration wins, a clash is a sync problem naming the holder (never another organization),
    orphans are adopted by the same owner.
  • Private runtime images: function pods, Kaniko function and runtime image builds, WebAssembly
    toolchain Jobs, sandboxes, the node pre-pull and version discovery use the source's registry
    credentials (a RunR-managed kubernetes.io/dockerconfigjson Secret, Kaniko's docker config,
    crictl --creds). Credentials are encrypted at rest, write-only and masked everywhere.
  • Lifecycle for every runtime (docs/runtimes.md): manifest fields
    deprecated (a date or true), sunset, replacement and notice for a runtime, deprecated and
    sunset for a version, versionDiscovery.lifecycle for discovered versions. A version ends at the
    earlier of its end of life and its sunset — the same reminders (13, 4, 1 weeks), picker removal and
    save / deploy refusal as an end of life; deprecations are announced once. A runtime that leaves its
    source is orphaned: no new projects, its projects keep running and deploying for 90 days
    (RUNR_RUNTIME_ORPHAN_GRACE_DAYS), then its sunset.
  • Patches of a source's own runtimes: from its signed catalog or its own signed patch feed,
    verified with the source's key — levels, deadlines, notifications, automatic migration and the
    Patches page like the built-ins. RunR's feed patches only the built-ins.
  • Console: Build & Run → Runtimes → Sources (list, add / edit with credentials, test connection,
    sync now, problems, the source's runtimes with enable / disable, its patches), the same for
    organizations; the Built-in runtimes card; lifecycle badges (end of life, deprecated, sunset,
    orphaned) on runtimes, versions, the runtime picker and projects; a tour of the Runtimes page.
  • API /api/runtime-sources (list, connect, show, change, remove, sync, test) and
    /api/runtime-catalog; CLI runr runtimes sources … and runr runtimes catalog; MCP tools
    runtime_sources_list, runtime_source_connect, runtime_source_sync, runtime_source_remove;
    Terraform resource runr_runtime_source; Helm values runtimeCatalog.*.
  • docs/executor-development.md: building an executor for any language,
    testing, publishing a repository or a signed catalog, private sources, signing, lifecycle and
    patches — with the sample repository
    BRF-Tech/runr-sample-custom-executor
    (Lua in persistent mode, compiled Zig in http mode).
  • e2e suite runtime-sources (runtime/ci.sh test-runtime-sources): RunR's published catalog, a
    signed OCI catalog, the sample repository served as a Git source in the cluster, a private image,
    a sunset refusing deploys.
  • Java, .NET (C#), Ruby and TypeScript on Bun as built-in runtimes. Four runtimes join the
    catalog (java, dotnet, ruby, bun), each with its handler server, starter code, dependency
    file and the three triggers (http, schedule, queue), under runc, gVisor and Kata. Their images
    are published by BRF-Tech/runr-runtimes (exec-java, exec-dotnet, exec-ruby, exec-bun),
    run as a user other than root, and get patch tags and the patch feed like the others
    (runtimes).
    • Java: Eclipse Temurin, the LTS lines (21.0 and 25.0).
      public static Object handler(Map<String, Object> event, Map<String, Object> context) in
      Main.java; every save is built with javac, and a FaaS project's pom.xml brings its jars
      through Maven.
    • .NET (C#): .NET 10.0. public static object Handler(JsonNode? input, IDictionary<string, object?> context) in Function.cs; every save is built with the SDK, Function.csproj names
      the NuGet packages, and the function runs as a self-contained application on Microsoft's
      chiseled runtime-deps image.
    • Ruby: 3.3, 3.4 and 4.0. def handler(event, context), or handler(event:, context:) as on
      AWS Lambda; a FaaS project's Gemfile is installed with Bundler.
    • TypeScript (Bun): Bun 1.4, the newest release (Bun supports only its latest).
      export async function handler(event, context) in main.ts, JavaScript too; a FaaS project's
      package.json is installed with bun install.
  • The code interpreter runs Java and C# (java: Java's source launcher, csharp: .NET's
    file-based apps, dotnet run), and TypeScript and JavaScript with Bun in a Bun sandbox; a
    sandbox of the new runtimes defaults to its language (Sandbox API).
  • Console and CLI: the runtime picker, icons, editor highlighting, upload types and the code
    interpreter's language list know the four; runr init and runr dev scaffold and run them
    (Main.java, Function.cs, main.rb, main.ts).
  • End-to-end: the main suite runs xaas-<runtime>-<version>-http/schedule/queue and
    faas-<runtime>-<version>-http for the four (the FaaS cases with Jedis, StackExchange.Redis,
    the redis gem and ioredis), and their gVisor sandbox cases.
  • A warning when the console certificate cannot be issued (install.md).
    With ingress.tls.mode: letsencrypt (or a clusterIssuer of the older keys) the API reads the
    console's cert-manager Certificate and its newest CertificateRequest at most every five minutes;
    platform administrators (single-tenant: the holders of platform.manage) see a banner across the
    console while it cannot be issued — a missing
    ClusterIssuer, a failed, denied or invalid request, a certificate still pending after ten
    minutes, or a renewal that fails (with the current certificate's expiry). It says why, whether
    the console serves the ingress controller's default certificate, and what to do: create the
    ClusterIssuer, set ingress.tls.clusterIssuer to an existing one, or use custom or none.
    GET /api/admin/console-tls returns the state for every mode (ok, pending, failed,
    not_applicable, unknown). The ClusterIssuer itself is not read (it would need a cluster-wide
    permission): a missing one shows in the CertificateRequest. Helm ingress.tls.certificateCheck: false turns the check and its permissions off.

Changed

  • The node pre-pull pulls the image a function runs on, not every version image. For a runtime
    with a build that is the build's runImage: .NET's chiseled dotnet-runtime-deps image instead
    of its 1.3 GB SDK image, Go's Alpine instead of the Go toolchain images; Java (runImage: "{image}") and the runtimes without a build keep their version image. No function runs on an SDK,
    and Kaniko fetches it through the region registry, which region:reconcile pre-warms with it; a
    private run image of a runtime source is pulled with the source's credentials
    (docs/runtimes.md). A Go or .NET sandbox runs on the toolchain
    or SDK, so a node pulls it on its first such sandbox, as for any image it does not have; a warm
    pool keeps such sandboxes started (docs/sandbox-api.md).
  • Sandbox commands run without a kubectl process. The API opens the API server's exec stream
    itself (a WebSocket per command, v5.channel.k8s.io): exec (JSON and SSE), the code
    interpreter, file transfers, background processes, kill and pause, and the exec WebSocket
    without a terminal. Exit codes, output caps, timeouts, kills, error messages and the activity
    records stay as they were. Terminal sessions ("tty": true, the console terminal) keep
    kubectl exec -t for now.
    kubectl also takes over where the API's client cannot work: a
    region kubeconfig with an exec plugin, an auth provider, credentials or a CA in files, a proxy
    or impersonation, and an API server that refuses the WebSocket upgrade (one without
    v5.channel.k8s.io is remembered for 10 minutes); a command goes to kubectl only before it
    started. SANDBOX_EXEC_CLIENT=kubectl (via extraEnv) brings back a kubectl process for
    every command. The region kubeconfig's CA, client certificate and key are kept in 0600 temp
    files of the API process, as the API's other cluster calls already do.
    • The native client takes a bearer token (a ServiceAccount's too) and
      client-certificate-data / client-key-data, alone or together. Every other credential form
      (an exec plugin, an auth provider, a token, certificate or CA in a file, basic auth,
      impersonation, a proxy-url) goes to kubectl, and so does a server that an HTTPS_PROXY /
      HTTP_PROXY of the API's environment covers and NO_PROXY does not exclude: kubectl and the
      API's other cluster calls go through that proxy. Each reason is logged once per process
      (sandbox exec: kubectl instead of the native client: …), also a command that went to kubectl
      because the server refused it.
    • e2e: the sandbox-api suite runs one command through the native client with a ServiceAccount
      bearer-token kubeconfig of the Kind cluster (sbx-exec-bearer-token): refused without RBAC,
      run with a Role of pods/exec.
  • Region Traefik chart 42.3.1 (from 42.3.0). New regions install it; region:reconcile moves
    the Traefik of an existing region to it (step traefik-chart), one pod at a time. Traefik stays
    v3.7.17. The chart's traefik.io CRDs gain optional fields that RunR does not set, so an installed
    region needs no CRD step (0.6.7 → 0.6.8 in upgrade.md).
  • kube-prometheus-stack 92.22.0 (from 92.21.2; Prometheus Operator v0.94.2, as before). Regions
    installed from now on run it; an installed region keeps its chart until php artisan cluster:patch-observability, a change back to RunR's own monitoring or a new Serving install
    moves it. On that move node-exporter restarts once with a stricter security context, and nothing
    else restarts (upgrade.md).

Fixed

  • php artisan runtimes:sync keeps the versions of a source's runtime that discovers them. Such
    a manifest (versionDiscovery) lists no versions, and the command took that for every version
    retired: the runtime's projects could not deploy until the next executor:sync. It now leaves
    them to executor:sync, which reads them from the runtime's registry.

  • The region Traefik gets its probe timing and Service types in keys the chart reads.

    • RunR gave the Traefik chart keys it never read.
      • The probes' timing went under deployment. Traefik ran the chart's defaults instead: a
        readiness failure threshold of 1 and timeouts of 2 s.
      • Each Service's type went beside its spec.
      • tlsOptions.default.preferServerCipherSuites was set, which no Traefik v3 reads.
    • Chart 42.3.1's schema refuses the type keys. They now sit in the Services' spec, the
      probes' timing in the chart's root keys, and the TLS key is gone.
    • A new region's Traefik now runs RunR's probes: readiness after 10 s with two successes,
      timeouts of 5 s, liveness after 20 s with five failures. Its Services render as before, except
      one line: traefik-internal states type: ClusterIP, the type Kubernetes already gave it.
    • An installed region gets the same keys when region:reconcile moves its Traefik to chart
      42.3.1 (step traefik-chart, under Changed). That move rolls the pods anyway, and the probe
      timing comes with it.
  • The install notes of ingress.tls.mode: letsencrypt say the ClusterIssuer has to exist. They
    said cert-manager issues the certificate even in a cluster without that issuer, where it never
    is; they now name the issuer, how to check it (kubectl get clusterissuer, kubectl get certificate -n <namespace>) and the other choices.

  • Symfony 7.4.23 for the API. The update covers http-foundation, http-kernel, routing
    and yaml, plus the error-handler, var-dumper and contracts releases they need. It clears
    the seven advisories published on 2026-11-04. They cover:

    • HEAD requests that bypassed method-restricted access rules;
    • path rules bypassed by a path appended to the script name;
    • host placeholders that matched the start of the path;
    • client-chosen hosts in generated URLs and in inline fragments;
    • slow parse times in the YAML parser;
    • Symfony's private_ranges shortcut trusting IPv4-mapped, 6to4, Teredo and NAT64 addresses.
      RunR's TRUSTED_PROXIES=private_ranges already uses its own list, as before.

    composer audit reports none.

  • A single-tenant installation reaches its own Patches page, platform banners and notices.

    • The single-tenant edition has no users.is_admin, so what was for platform administrators
      reached nobody there:
      • the Patches page (/api/admin/runtime-patches) and GET /api/admin/console-tls;
      • the banners of a newer RunR release, of a patch feed that is off or refused, and of a console
        certificate cert-manager cannot issue;
      • the notifications of a critical patch's platform count, a refused feed, a region reconcile
        that did not finish and the bot protection's alarms.
    • The new single-tenant permission platform.manage (Infrastructure) stands in for the flag. The
      Owner role holds it; the Admin role does not; a custom role can include it
      (docs/permissions.md).
    • The Horizon dashboard follows the same permission. Owners keep their access; its link still
      needs a session or an API token with full access.
    • An API token with a selection of permissions reaches those routes when it carries
      platform.manage.
    • Multi-tenant installs are unchanged: only platform administrators, and their scoped tokens
      stay refused. The @platform:billing.* routes stay as they are: tenant bills, archived bills
      of deleted tenants, the per-tenant queue consumers of a platform region and the 0.5.7 records
      (archived by a Tenancy migration) exist only in the multi-tenant edition.
  • RunR's catalog no longer reads as an authentication failure while it is not published. While
    ghcr.io/brf-tech/runr/runtime-catalog did not exist or was not public, the default source showed
    auth_failed: ghcr.io answers an anonymous read of a missing or private package with 401 / 403. A
    source read without credentials that the registry or Git host refuses, or that answers 404 / "not
    found", now has the status not_found, shown as Not found or not public (Bulunamadı ya da
    herkese açık değil
    ), with a hint on RunR's catalog that the bundled catalog stays in use.
    auth_failed is left to a source whose own credentials were refused; registry credentials for
    another host than the catalog's do not count. The API, the CLI (runr.RuntimeSourceNotFound),
    the Terraform provider and the MCP tool list the new status
    (runtimes.md).

  • The gVisor installer retries its download. A node fetched gVisor's release tarball and its
    checksum with one wget: a node whose DNS was not back yet (CoreDNS restarting) failed the
    install. Both downloads now take five tries, 5, 10, 20 and 40 s apart, each failed try in the
    installer pod's log; the WebAssembly installer downloads its shim tarballs the same way.

  • The sandbox-api e2e no longer passes its gVisor cases on runc. The setup restarted CoreDNS and
    slept 5 s; the nodes' gVisor download failed 16 s later, and the runc RuntimeClass the e2e stands
    in with ran the gvisor class. The setup now waits until CoreDNS is Ready again, and the suite
    fails when gVisor was not installed (sbx-gvisor-install, with the install's error) or when its
    gvisor sandbox does not see gVisor's kernel (sbx-gvisor-runsc: the RuntimeClass handler
    runsc, uname -r, dmesg).

  • ci.sh test-helm-upgrade keeps etcd in memory with KIND_ETCD_IN_MEMORY=1, as the other Kind
    suites do; its Kind configuration had no etcd patch. test-global-projects' second cluster gets
    it as well, and every suite takes the patch from one helper.