Server-side fixes
Fix API and validation bugs without a deploy. Run the sidecar next to your app, then add the Sarcio library for your language.
1. Run the sidecar
The sidecar runs on the same host as your app and hands it approved fixes over a local socket. It only makes outbound HTTPS requests to control.sarcio.io. If it is down, your app runs its normal code.
Docker Compose
Add the service and share its socket directory with your app. Pin a version: there is no latest tag.
compose.yaml
services: sarcio-sidecar: image: ghcr.io/sarcioai/sarcio-sidecar:0.2.2 command: - "-socket" - "/run/sarcio/sarcio.sock" - "-control-plane" - "https://control.sarcio.io" - "-site" - "pk_your_site" environment: SARCIO_CONTROL_PLANE_KEY: sk_your_sidecar_key SARCIO_SHIM_TOKEN: an-app-token-you-choose SARCIO_SOCKET_MODE: "0660" # if your app runs as a different user volumes: - sarcio-run:/run/sarcio
your-app: volumes: - sarcio-run:/run/sarcio # the same socket directory
volumes: sarcio-run:Linux: install script, deb or rpm
The script picks the deb, rpm or binary for the machine and verifies it before installing. Read it first.
Shell
curl -fsSLO https://github.com/sarcioai/sarcio-sidecar-releases/releases/latest/download/install.shless install.shsh install.sh v0.2.2Set your keys in /etc/sarcio/sidecar.env:
/etc/sarcio/sidecar.env
SARCIO_CONTROL_PLANE=https://control.sarcio.ioSARCIO_SITE_KEY=pk_your_siteSARCIO_CONTROL_PLANE_KEY=sk_your_sidecar_keySARCIO_SHIM_TOKEN=an-app-token-you-chooseAdd your app's user (here www-data) to the sarcio group so it can reach the socket, then start the service:
Shell
sudo usermod -aG sarcio www-datasudo systemctl enable --now sarcio-sidecarPackages and binaries are also on the releases page.
Add the sidecar as a second container in the pod and share the socket over an emptyDir volume:
deployment.yaml (pod spec)
spec: volumes: - name: sarcio-run emptyDir: {} containers: - name: your-app volumeMounts: - { name: sarcio-run, mountPath: /run/sarcio } - name: sarcio-sidecar image: ghcr.io/sarcioai/sarcio-sidecar:0.2.2 args: - "-socket" - "/run/sarcio/sarcio.sock" - "-control-plane" - "https://control.sarcio.io" - "-site" - "pk_your_site" env: - { name: SARCIO_SOCKET_MODE, value: "0660" } envFrom: - secretRef: { name: sarcio-sidecar } # SARCIO_CONTROL_PLANE_KEY, SARCIO_SHIM_TOKEN volumeMounts: - { name: sarcio-run, mountPath: /run/sarcio }Each release's SHA256SUMS is signed with minisign. The install script checks it when minisign is installed. By hand:
Shell
minisign -Vm SHA256SUMS -P RWT/8gXBswXCZXMhfResaZIVGcwEjR/89MHEoYpo0C5ejHNUVTWiddoDsha256sum --check --ignore-missing SHA256SUMSThe container image is signed with cosign. Save this public key as sarcio-cosign.pub, verify, and pin the digest it prints rather than a tag:
sarcio-cosign.pub
-----BEGIN PUBLIC KEY-----MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0BZVOjeZFPL6TDrSNwB7nEwnencpxBbo2v/0aOF+3+jt9faYKQVP4I55/QSNvEKzEdIORD6Xr7R/HU3Q46LC3g==-----END PUBLIC KEY-----Shell
cosign verify --key sarcio-cosign.pub ghcr.io/sarcioai/sarcio-sidecar:0.2.22. Add the Sarcio library to your app
One small dependency from your language's public registry. It asks the local sidecar, per request, whether a fix applies. Use the same site key, socket path and app token you gave the sidecar.
Node.js
The Express adapter needs Express 5.
Shell
npm install @sarcio/middlewareExpress
Create one client per process and register it after your body parser:
server.ts
import { createProtocolShim, ProtocolShimClient } from '@sarcio/middleware';import express from 'express';
const sarcio = new ProtocolShimClient({ siteKey: 'pk_your_site', shimToken: process.env.SARCIO_SHIM_TOKEN, target: { socketPath: '/run/sarcio/sarcio.sock' }});await sarcio.start();
const app = express();app.use(express.json());app.use(createProtocolShim(sarcio)); // after your body parserA fix that relaxes a rule or changes a setting reaches your handler on req.sarcio.skipValidations and req.sarcio.config.
Create the client as above, then register one line:
Fastify
import { createProtocolFastifyHook } from '@sarcio/middleware';
app.addHook('preHandler', createProtocolFastifyHook(sarcio));Koa
import { createProtocolKoaMiddleware } from '@sarcio/middleware';
app.use(createProtocolKoaMiddleware(sarcio)); // after your body parserHono
import { createProtocolHonoMiddleware } from '@sarcio/middleware';
app.use('*', createProtocolHonoMiddleware(sarcio));node:http
import { createServer } from 'node:http';import { withProtocolSarcio } from '@sarcio/middleware';
createServer(withProtocolSarcio(sarcio, handler)).listen(3000);PHP
Shell
composer require sarcio/shim:^0.2Laravel
The service provider registers itself. Set the connection in .env:
.env
SARCIO_SIDECAR_DSN=unix:///run/sarcio/sarcio.sockSARCIO_SITE_KEY=pk_your_siteSARCIO_SHIM_TOKEN=an-app-token-you-chooseAdd the middleware to the global stack (Laravel 11 and later):
bootstrap/app.php
// bootstrap/app.php->withMiddleware(function (Middleware $middleware) { $middleware->append(\Sarcio\Shim\Laravel\SarcioMiddleware::class);})Your validation code reads what an approved fix relaxed:
PHP
$sarcio = $request->attributes->get('sarcio');
if (!in_array('referralCodeRequired', $sarcio['skipValidations'] ?? [], true)) { // enforce the rule as normal}Laravel 10: app/Http/Kernel.php
// app/Http/Kernel.phpprotected $middleware = [ // ... \Sarcio\Shim\Laravel\SarcioMiddleware::class,];Symfony: config/services.yaml
# config/services.yamlSarcio\Shim\Cache\ApcuRouteSetCache: ~
Sarcio\Shim\Shim: arguments: $dsn: '%env(SARCIO_SIDECAR_DSN)%' $siteKey: '%env(SARCIO_SITE_KEY)%' $cache: '@Sarcio\Shim\Cache\ApcuRouteSetCache' $framework: 'symfony' $shimToken: '%env(SARCIO_SHIM_TOKEN)%'
Sarcio\Shim\Symfony\SarcioKernelListener: arguments: $shim: '@Sarcio\Shim\Shim' tags: - { name: kernel.event_listener, event: kernel.request } - { name: kernel.event_listener, event: kernel.response }Plain PHP
$sarcio = new \Sarcio\Shim\Shim( dsn: 'unix:///run/sarcio/sarcio.sock', siteKey: 'pk_your_site', cache: new \Sarcio\Shim\Cache\ApcuRouteSetCache(), shimToken: getenv('SARCIO_SHIM_TOKEN') ?: '',);
// null means: run your normal code$fix = $sarcio->evaluate($method, $path, ['headers' => $headers, 'body' => $body]);On PHP-FPM, install the APCu extension so requests to unpatched routes skip the sidecar.
Java
Needs Java 21. The library is on Maven Central.
pom.xml
<dependency> <groupId>io.sarcio</groupId> <artifactId>shim</artifactId> <version>0.2.0</version></dependency>Spring Boot
The filter registers itself at the front of the chain. Configure it:
application.properties
sarcio.enabled=truesarcio.socket-path=/run/sarcio/sarcio.socksarcio.site-key=pk_your_sitesarcio.shim-token=${SARCIO_SHIM_TOKEN}Your handlers read what an approved fix relaxed. Set sarcio.enabled=false to switch the filter off.
Java
@SuppressWarnings("unchecked")var sarcio = (Map<String, Object>) request.getAttribute(SarcioFilter.ATTRIBUTE);var skip = (List<String>) sarcio.get("skipValidations");build.gradle.kts
dependencies { implementation("io.sarcio:shim:0.2.0")}Without Spring, register the filter yourself:
Plain servlets
var sarcio = SarcioShim.create( ProtocolClient.Target.unix("/run/sarcio/sarcio.sock"), "pk_your_site", "java", 25, System.getenv().getOrDefault("SARCIO_SHIM_TOKEN", ""));sarcio.start();
servletContext.addFilter("sarcio", new SarcioFilter(sarcio)) .addMappingForUrlPatterns(null, false, "/*");WordPress
One plugin covers front-end and server-side fixes. No script tag, no Composer.
- Install Sarcio from Plugins → Add New and activate it.
- Open Settings → Sarcio and enter your site key and the API URL
https://control.sarcio.io. Reporting and front-end fixes now work, with no sidecar. - For server-side fixes, run the sidecar on the host and add its connection to
wp-config.php:
wp-config.php
define('SARCIO_SITE_KEY', 'pk_your_site');define('SARCIO_API_URL', 'https://control.sarcio.io');define('SARCIO_SIDECAR_DSN', 'unix:///run/sarcio/sarcio.sock');define('SARCIO_SHIM_TOKEN', 'an-app-token-you-choose');| Setting | What it does |
|---|---|
Reporter audience | Who sees the reporter: users who can edit_posts (default), logged_in or everyone. Fixes always apply to every visitor. |
SARCIO_SERVER_SCOPE | all (default), rest for the REST API only, or off for front-end fixes only. |
A value set in wp-config.php shows read-only in the admin.
3. Check it works
The sidecar logs listening on unix /run/sarcio/sarcio.sock when it is up:
Shell
# Docker Composedocker compose logs sarcio-sidecar
# deb / rpmjournalctl -u sarcio-sidecar -n 20curl -s http://127.0.0.1:9090/healthzThen report a bug on a server-backed form and run your first fix. The fix applies on the next request after approval.
Rotating the sidecar key
Ready to try it on your own site?
Create a workspace, add a site, and follow these steps on your own app.
Create a workspace