Skip to main content
Workflows are HTTP automation scripts that call external APIs on behalf of your SOC. Python is the glue layer — you use it to construct HTTP requests, call endpoints via ctx.http, and parse responses. Agents discover workflows via API or MCP and trigger them during investigations. Calseta supports two workflow types: sandboxed HTTP automation scripts for logic that runs inside the platform, and custom HTTP endpoints for triggering external automation.

HTTP Automation Scripts

Each workflow is an async def run() function that receives a WorkflowContext and returns a WorkflowResult. The primary tool is ctx.http — an httpx.AsyncClient for calling any REST API, webhook, serverless function, or HTTP endpoint:
async def run(ctx: WorkflowContext) -> WorkflowResult:
    api_key = ctx.secrets.get("FIREWALL_API_KEY")
    if not api_key:
        return WorkflowResult.fail("FIREWALL_API_KEY is not set")

    ip = ctx.indicator.value
    try:
        resp = await ctx.http.post(
            "https://firewall.internal/api/block",
            json={"ip": ip},
            headers={"Authorization": f"Bearer {api_key}"}
        )
    except Exception as exc:
        return WorkflowResult.fail(f"Request failed: {exc}")

    if resp.status_code == 200:
        return WorkflowResult.ok(
            message=f"Blocked {ip}",
            data={"status": resp.status_code}
        )
    return WorkflowResult.fail(
        message=f"Failed to block {ip}: {resp.status_code}"
    )

What You Can Do

  • Call any HTTP endpoint — REST APIs, webhooks, Lambda Function URLs, Logic App triggers, internal services
  • Use environment variables for secrets — API keys, tokens, webhook URLs via ctx.secrets.get("KEY")
  • Use safe stdlib modulesjson, hashlib, hmac, base64, datetime, re, uuid, and more
  • Use builtin integration clientsctx.integrations.okta and ctx.integrations.entra for pre-built Okta/Entra identity actions

WorkflowContext

The context object provides everything a workflow needs:
PropertyDescription
indicatorThe indicator being acted on (type, value, malice verdict, enrichment results)
alertThe alert that triggered the workflow (may be None)
httpPre-configured httpx.AsyncClient for calling external HTTP endpoints
logStructured logger for execution steps
secretsRead environment variables: ctx.secrets.get("KEY") returns str or None
integrationsPre-built integration clients (Okta, Entra) — None if not configured

WorkflowResult

Every workflow returns a result — never raises an exception:
WorkflowResult.ok(message="Success", data={"key": "value"})
WorkflowResult.fail(message="Failed because...")

Code Safety

Workflow code is validated via AST analysis at save time:
  • Allowed: Python standard library (json, hashlib, hmac, base64, datetime, re, uuid, etc.), calseta.workflows
  • Blocked: Third-party packages, file system access, subprocess calls, os, sys, socket
Workflows interact with external systems exclusively through ctx.http.

Builtin Workflows

Calseta ships with 9 pre-built workflows for Okta and Microsoft Entra identity lifecycle management. These are the “batteries included” version of the HTTP automation pattern — they use the same ctx.http under the hood, wrapped in typed integration clients:
  • Okta — Revoke sessions, suspend/unsuspend user, reset password, force password expiry
  • Entra — Revoke sign-in sessions, disable/enable account, force MFA re-registration
All builtins require human approval when triggered by an AI agent.

Code Generation

Use POST /v1/workflows/generate to describe what you want in plain English. The API generates valid workflow code from your description, validates it, and returns it for review before saving. Requires ANTHROPIC_API_KEY.

Testing

Use POST /v1/workflows/{uuid}/test to run a workflow with mock HTTP responses. No real external calls are made — the test endpoint intercepts HTTP requests and returns your mock responses.

Custom HTTP Endpoint Workflows

For automation that lives outside Calseta — Azure Logic Apps, AWS Lambda functions, n8n workflows, or any HTTP-accessible service — create an HTTP endpoint workflow. Calseta calls your endpoint with the alert and indicator context, and your service performs the action. This pattern is useful for:
  • Triggering Logic Apps that interact with internal systems
  • Calling Lambda functions that access cloud-specific resources
  • Integrating with ticketing systems, chat platforms, or custom tooling
  • Any automation that needs dependencies beyond Python’s standard library
The workflow documentation field describes what the endpoint does, so agents can discover and reason about it alongside sandboxed workflows.

Workflow States

StateDescription
draftUnder development, cannot be executed
activeAvailable for execution
inactiveDisabled, cannot be executed

Human-in-the-Loop Approval

Workflows support a configurable approval gate via approval_mode:
  • "always" — all triggers (human and agent) require approval before execution
  • "agent_only" — only agent-triggered executions require approval; humans bypass the gate
  • "never" — no approval required, execute immediately
{
  "approval_mode": "always",
  "approval_channel": "#soc-approvals",
  "approval_timeout_seconds": 3600,
  "risk_level": "high"
}

Approval Flow

  1. A request hits POST /v1/workflows/{uuid}/execute. The trigger_source is derived server-side from the API key’s key_type (human or agent) — it is not a request body field.
  2. If the trigger requires approval (based on approval_mode and trigger_source), Calseta creates an approval request. Agent keys (key_type: agent) must include reason and confidence in the request body.
  3. Calseta notifies the configured channel with a unique decide_token
  4. A human approves or rejects via the browser approval page, Slack buttons, or REST API
  5. If approved, the workflow is queued for execution
  6. If rejected or expired, no action is taken

Browser Approval Page

Every approval request includes a token-authenticated browser link that approvers can open directly — no API key or login required. The link is included in Slack and Teams notifications as a “Review & Decide” button. The page displays the workflow name, risk level, indicator, agent reason, confidence, and expiry. Approvers click Approve or Reject and see an immediate confirmation. The token is 256-bit entropy (secrets.token_urlsafe(32)), validated with constant-time comparison, single-use (consumed on decision), and time-bound (same expiry as the approval request). Use HTTPS in production since the token is in the URL.

Notification Channels

ChannelInteractiveConfiguration
SlackYes (approve/reject buttons + browser link)APPROVAL_NOTIFIER=slack
TeamsYes (browser approval link)APPROVAL_NOTIFIER=teams
NoneAPPROVAL_NOTIFIER=none (default)

Version History

Every code change increments code_version and creates a version history entry. Workflow runs record which version was executed, providing a complete audit trail.

API Endpoints

MethodEndpointDescription
GET/v1/workflowsList workflows
GET/v1/workflows/{uuid}Get a workflow
POST/v1/workflowsCreate a workflow
PATCH/v1/workflows/{uuid}Update a workflow
POST/v1/workflows/{uuid}/executeExecute a workflow
GET/v1/workflows/{uuid}/runsList runs
POST/v1/workflow-approvals/{uuid}/approveApprove
POST/v1/workflow-approvals/{uuid}/rejectReject
GET/v1/approvals/{uuid}/decide?token=...Browser approval page
POST/v1/approvals/{uuid}/decideSubmit browser decision

MCP Access

  • Resource: calseta://workflows — list active workflows
  • Resource: calseta://workflows/{uuid} — get a workflow
  • Tool: execute_workflow — trigger execution (always agent-triggered)