Skip to content

Repository files navigation

Serto

A Developer Integration Platform built on the principle of Integration-as-Code. We replace legacy, opaque IPaaS "Low-Code" designers with a high-velocity workflow developers actually love.

Product direction

We provide the magic developer experience of Vercel or Temporal for enterprise C# integrations. We eliminate "Click-Ops" by allowing the Code to be the Manifest.

The Integration-as-Code Workflow:

  1. Author: Write a C# class and decorate it with [ScheduledIntegration].
  2. Develop: serto dev watches your code and runs tests locally on every save.
  3. Deploy: serto deploy. The Control Plane auto-provisions the infrastructure based on your code.

We are the "Terraform for Enterprise Integrations," designed specifically for engineering teams who need to solve complex SAP, Salesforce, and internal API automation without proprietary lock-in.

Near-term product priorities:

  1. Version-pinned package execution
  2. Work item queue
  3. Workflow DAG foundation
  4. Retry policy
  5. Agent heartbeats and agent pools
  6. Webhook triggers
  7. Core connectors for HTTP, SQL, files/SFTP, object storage, and notifications
  8. Code-first transform steps
  9. Environment promotion
  10. Audit and RBAC

Stack

  • Backend: ASP.NET Core 10, EF Core, PostgreSQL
  • Frontend: React 19, Vite, TypeScript, TanStack Query, shadcn/ui, Tailwind

Documentation

The sections below are a condensed version of the Installation Guide.

Local development

Prerequisites

  • .NET 10 SDK
  • Node.js 20+
  • Docker

1. Start the database

docker-compose -f docker-compose.dev.yml up -d

2. Start the API

$HOME/.dotnet/dotnet run --project src/ControlPlane

Runs on http://localhost:5000. Migrations are applied automatically on startup.

3. Start the frontend dev server

cd src/ControlPlane.Client && npm run dev

Runs on http://localhost:5173. API calls are proxied to the backend automatically.

Note: Use port 5173 during development, not 5000. Hot module replacement means changes are reflected instantly without rebuilding.

First run

Navigate to http://localhost:5173 — you'll be directed to /setup to create the first tenant and admin user.

Connecting to the database (pgAdmin)

Field Value
Host localhost
Port 5433
Database integration_platform
Username devuser
Password devpassword

Port is 5433 (not the default 5432) to avoid conflicts with any local Postgres instance.

Agent tokens

Agent tokens allow a runtime agent to fetch decrypted secrets from the control plane. They are scoped to a single environment — a production token cannot access staging secrets.

Creating a token

  1. Go to Agent tokens in the UI and click New token
  2. Give it a name and set the environment (e.g. production)
  3. Copy the token value — it is shown once only and cannot be retrieved again

Using a token

The agent calls the secret bundle endpoint with the token in the X-Agent-Token header:

GET /api/agent/secrets/{environment}
X-Agent-Token: agt_<token>

Response is a decrypted key/value map:

{
  "secrets": {
    "DATABASE_URL": "postgres://...",
    "API_KEY": "sk-..."
  }
}

The agent injects these into the job's execution environment before running an integration.

Running the Runtime Agent

The runtime agent is a separate process that executes integrations. It polls the control plane for work, fetches secrets, and runs your C# integration classes.

Configuration

Create an appsettings.json in the RuntimeAgent project directory:

{
  "Agent": {
    "ControlPlaneUrl": "http://localhost:5000",
    "AgentToken": "agt_<your-token>",
    "Environment": "production",
    "IntegrationsPath": "./integrations",
    "PackagesPath": "./packages",
    "PollIntervalSeconds": 30,
    "PackageSyncIntervalSeconds": 300,
    "MaxConcurrentExecutions": 5,
    "ShutdownDrainSeconds": 30
  }
}

Running

dotnet run --project src/RuntimeAgent

The agent will:

  1. Load integration assemblies from IntegrationsPath
  2. Sync uploaded integration packages into PackagesPath
  3. Poll the control plane for claimed due integrations matching its environment
  4. Execute the integrations returned by the control plane
  5. Report execution results back to the control plane

Scheduling state is persisted in the control plane, so agent restarts do not reset cron evaluation.

Deploying integrations

The runtime agent loads assemblies from the local filesystem and can sync uploaded packages from the control plane. Synced packages are downloaded, SHA-256 verified, extracted under PackagesPath, and loaded by the agent. Integrations can be pinned to uploaded package versions so future executions use deterministic code.

  1. Build your integration project: dotnet publish -c Release
  2. Zip the publish output if you want to store the package in the control plane:
    cd bin/Release/net10.0/publish
    zip -r integrations.zip .
    curl -X POST http://localhost:5000/api/integration-packages \
      -H "Authorization: Bearer <jwt>" \
      -F "name=MyCompany.Integrations" \
      -F "version=1.0.0" \
      -F "file=@integrations.zip"
  3. The agent will download and extract the package on startup or at the next package sync interval
  4. Register or update the integration in the control plane with the fully qualified class name and package version

The CLI can scan, package, and upload the current integration project:

dotnet run --project src/Cli -- scan

dotnet run --project src/Cli -- package \
  --name MyCompany.Integrations \
  --version 1.0.0

SERTO_API_TOKEN=<personal-access-token> dotnet run --project src/Cli -- deploy \
  --url http://localhost:5000 \
  --name MyCompany.Integrations \
  --version 1.0.0

serto scan, serto package, and serto deploy all show the same discovery preview: package metadata, decorated integration classes, trigger declarations, run policy, validation errors, and required secret names detected from connector/context usage. If --version is omitted, serto deploy uses PackageVersion or Version from the project file and falls back to a timestamped development version. You can still copy published DLLs directly to the agent's IntegrationsPath for local development. Package sync avoids manual copying; integrations can be pinned to uploaded package versions, and rollback is performed by repointing the integration to a previous package version.

See docs/writing-integrations.md for details.

Building the frontend for production

cd src/ControlPlane.Client && npm run build

Output goes to src/ControlPlane/wwwroot and is served by the .NET server at http://localhost:5000.

Docker deployment

Production deployments use published Docker images, so servers do not need a source checkout:

cp .env.example .env
# Fill in SERTO_CONTROL_PLANE_CONNECTION_STRING, JWT_SECRET, and ENCRYPTION_MASTER_KEY.
docker compose -f docker-compose.prod.yml up -d

The production compose file pulls craytech/serto.controlplane:${SERTO_IMAGE_TAG:-1.0.3} and points it at an external PostgreSQL database. Runtime agents are deployed separately on hosts that can reach the systems your integrations use:

docker compose -f docker-compose.agent.yml up -d

For a single-host trial with PostgreSQL and the control plane together, use docker-compose.trial.yml.

For maintainers publishing images, see Docker Images.

Running tests

scripts/validate.sh

This runs patch hygiene checks, .NET restore/build/test, and frontend lint/build when node_modules is present.

Currently 476 tests cover control plane features, SDK behavior, runtime agent behavior, CLI behavior (including saved-credential storage, project scaffolding, name validation, and local serto test validation), connector configuration validation and test harness, API contracts, RBAC/security boundaries, audit logging, failure alerting, environment management, commercial API surfaces, and database-backed integration paths.

The control plane integration tests use a temporary PostgreSQL database when one is available. By default they try the local development database server at 127.0.0.1:5433 with devuser / devpassword. To point them at a different server, set:

export INTEGRATION_TEST_CONNECTION="Host=127.0.0.1;Port=5433;Database=postgres;Username=devuser;Password=devpassword"
dotnet test

The test harness creates and drops isolated databases named integration_platform_test_*.

See docs/correctness-controls.md for the CI gates and review checklist used to keep feature work honest.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages