36  How Sophea Automations Works

36.1 Overview

Sophea Automations is the workflow automation layer of the Sophea platform. It runs embedded inside the Nous backend, sharing authentication, tenant isolation, and permissions with the rest of the platform. This document explains the architecture, the broker pattern, and how tenant isolation and ACL propagation work.

36.2 Architecture

Sophea Automations consists of two components:

  1. Automations API server (TypeScript, Fastify): handles flow management, execution, and the web builder UI
  2. Automations web frontend (React, Vite): the visual flow builder and dashboard

Both components run inside the Nous namespace in Kubernetes. The Automations API communicates with the Nous backend via HMAC-signed broker endpoints, and with the RAG service via signed ACL principals.

36.2.1 Identity and access lifecycle

The Automations account is bound to the member’s stable Portal user identity, not to an email address. Changing or reassigning an email therefore does not merge Automations accounts or transfer their access.

The Automations platform is provisioned by the platform operator before customer access is enabled. Opening Automations can create the member’s workspace project and project membership, but it cannot create the platform or grant platform-administrator authority.

For every user request to a workspace project, Automations checks the current effective workspace membership in Portal before applying its local project role. Removing a direct, Team-derived, or Organization-derived workspace grant blocks the member’s next request, including requests made with an existing Automations session. If Portal cannot confirm membership, access fails closed.

Browser
  |
  v
Nous (nginx reverse proxy)
  |
  +--> Automations API (Fastify, TypeScript)
  |       |
  |       +--> Nous Broker (HMAC-signed HTTP)
  |       |      |
  |       |      +--> Nous RAG (signed ACL principals)
  |       |      +--> Agent Service (X-Sophea headers)
  |       |      +--> Portal (HMAC bearer auth)
  |       |
  |       +--> Flow Engine (Code steps and {{ }} expressions run in V8 isolates)
  |
  +--> Nous Backend (FastAPI, Python)

36.3 The Broker Pattern

The broker pattern is the core security mechanism for Sophea Automations. Instead of giving the Automations API direct database access, all data operations flow through HMAC-signed HTTP endpoints on the Nous backend.

36.3.1 How it works

  1. A flow step executes in the Automations sandbox
  2. The Sophea piece action calls postToNousBrokerRaw() with a broker path and payload
  3. The broker client (broker.ts) resolves workspace identity from the flow context:
    • workspaceId from context.project.externalId()
    • tenantId from workspace mapping
    • runAsUserId from context.run.triggeredBy.externalId()
  4. The client computes an HMAC-SHA256 signature over the request body and identity fields
  5. The signed request is sent to the Nous backend broker endpoint
  6. The Nous backend verifies the HMAC signature, checks the workspace membership, and executes the operation

36.3.2 Why this matters

  • No direct database access: The Automations API never touches the Nous database directly
  • Tenant isolation enforced at the boundary: Every broker request carries workspace identity, verified on every call
  • Auditable: Every broker call is logged with workspace ID, run ID, step ID, and attempt number
  • Rate-limited: Broker endpoints can enforce per-workspace rate limits

36.3.3 HMAC signature

The HMAC signature is computed over:

${timestamp}.${sha256(body)}.${projectId}.${runId}.${stepId}.${attemptNo}

Signed with SOPHEA_AUTOMATIONS_BROKER_SECRET (shared between Automations API and Nous backend). The signature is sent in the Authorization header as Bearer ${timestamp}.${signature}.

Additional headers: - X-Sophea-Automation-Project-ID - X-Sophea-Automation-Run-ID - X-Sophea-Automation-Step-ID - X-Sophea-Operation-ID - X-Sophea-Tenant-ID (if set) - X-Sophea-User-ID (if set)

36.4 Tenant Isolation

36.4.1 Workspace equals tenant

In Sophea, a workspace is a tenant. Every flow, run, and piece execution is scoped to a workspace. The workspace ID is propagated through:

  1. Flow context: context.project.externalId() returns the workspace ID
  2. Broker requests: workspace_id field in every broker request body
  3. Database queries: The Nous backend opens a tenant-scoped database session for each broker call

36.4.2 Broker endpoint security

Every broker endpoint follows the same security pattern:

  1. _headers_match_body(): verifies that the HMAC signature was computed over the same body that was received
  2. verify_automation_broker_authorization(): verifies the HMAC signature and timestamp
  3. _verify_runtime_member(): checks that the requesting user is an active member of the workspace
  4. _tenant_id_from_member(): resolves the tenant ID from the workspace membership
  5. _execute_runtime_broker_call(): opens a tenant-scoped database session and executes the operation

36.4.3 Shell mode

Shell mode restricts the available pieces to a vetted allowlist. This prevents untrusted pieces from running in production environments. The allowlist is defined in nous-automations-shell.ts and includes only Sophea-approved pieces.

Shell mode also pins the code execution mode. In every Sophea environment, AP_EXECUTION_MODE is SANDBOX_CODE_ONLY: Code steps and { } template expressions run inside fresh V8 isolates (isolated-vm) instead of the engine process. Sandboxed code receives only copied inputs; Node APIs (process, require, filesystem, network access, timers) are not available, and npm packages cannot be installed. Trusted Sophea piece code continues to run in the engine process, where it signs broker calls with SOPHEA_AUTOMATIONS_BROKER_SECRET; sandboxed user code cannot read that process or its environment. If AP_EXECUTION_MODE is set to UNSANDBOXED while shell mode is enabled, the engine rejects the combination and fails closed, so a configuration error cannot silently restore in-process code execution. UNSANDBOXED remains only for explicit trusted-operator development with shell mode off and is never a Sophea production option. V8 isolation is not a kernel boundary; separate process isolation remains follow-up hardening.

36.5 ACL Propagation

36.5.1 Signed ACL principals

When a flow step searches the knowledge base, the broker endpoint builds signed ACL principals that determine which documents the search can access. The ACL is built from:

  1. Public documents: PUBLIC_DOC_PAT (all workspace members can access)
  2. User-specific documents: prefix_user_email(email) (documents scoped to the user’s email)

The ACL is signed with NOUS_RAG_SERVICE_AUTH_KEY using HMAC-SHA256 and sent to the RAG service in the X-Sophea-Principals header.

36.5.2 How it works

  1. The broker endpoint receives the search request with workspace and user identity
  2. _signed_principals_for_member() builds the ACL for the requesting user
  3. The ACL is signed and sent to the RAG service
  4. The RAG service verifies the signature and filters search results to only include documents the user can access

This ensures that flow steps can only access documents that the requesting user has permission to see, even when running in an automated context.

36.6 Cross-Service Headers

All cross-service calls carry Sophea-specific headers:

Header Purpose
X-Sophea-Tenant-ID Required: identifies the tenant
X-Sophea-Run-ID Agent service idempotency key
X-Sophea-User-ID Optional: identifies the user
X-Sophea-Operation-ID Tracing and correlation
X-Sophea-Principals Signed ACL for RAG service
X-Sophea-Signature HMAC signature for webhook triggers
X-Sophea-Timestamp Timestamp for webhook signature verification