Security & compliance

Three compliance layers
built into the runtime

Every FlowMason pipeline automatically inherits PII redaction, cross-user FLS enforcement, and async resilience. No bolt-on layer. No vendor lock-in. All opt-in with kill switches.

Phase A

Value-pattern redaction

FMRedactor scans every string leaf in the JSON payload — not just keys — for sensitive patterns (SSN, credit card, email, US phone, IBAN, IPv4, AWS keys, bearer tokens, OpenAI/Anthropic keys). Matches are replaced with a configurable placeholder and counted on PipelineExecution__c.

Kill switch
FM_Config__mdt.REDACTION_VALUE_PATTERN_ENABLED
Audit surface
PipelineExecution__c.Redaction_Count__c + Redaction_Summary__c
Schema
FM_Redaction_Pattern__mdt.Value_Pattern__c
Example
// Case.Description contains an SSN. Pre-Phase-A behavior:
{ "Case": { "Description": "Please reach me at 123-45-6789 today" } }
//                                          ^^^^^^^^^^^ never scrubbed by key-only redaction

// With US_SSN pattern active, Phase A replaces in-place:
{ "Case": { "Description": "Please reach me at ***SSN*** today" } }
Phase B

FLS-aware prompt guard

FMPromptGuard enforces the invoking user's field-level security on every LLM prompt — even when the pipeline runs in a system/integration context for throughput. Uses UserFieldAccess (Spring '24, API 60+) so profile, permission sets, permission set groups, muting, and expiration all resolve correctly.

Kill switch
FM_Config__mdt.FLS_PROMPT_GUARD_ENABLED (master), FLS_PROMPT_GUARD_PLACEHOLDER (placeholder string), FLS_PROMPT_GUARD_FAIL_CLOSED (unresolved-ref handling)
Audit surface
PipelineExecution__c.FLS_Redaction_Count__c + FLS_Redacted_Fields__c
Schema
ExecutionState.invokingUserId (additive, no schema bump)
Example
// Pipeline runs system-mode. Invoking user has no FLS on Account.Compensation__c.
// Prompt template:
{{ stages.query.records[0].Compensation__c }}
// Renders in system context as: "$150,000"
// FMPromptGuard intercepts before provider invoke → replaces with:
[redacted: FLS]
// Audit row: FLS_Redacted_Fields__c = "Account.Compensation__c"

Variable-laundering defense

A pipeline author can't bypass the guard by routing a restricted field through vars.X. When VariableSet writes a FieldRef-sourced value, the source refs are tagged as Provenance. Downstream references to context.X or vars.X fold the provenance back into FLS tracking — laundered values are caught.

Phase C

Buffered circuit breaker

Opt-in mode: "buffered" on any circuit_breaker stage. When the breaker is open, the pipeline's ExecutionState is serialized (and redacted via Phase A) into FM_Circuit_Queue__c. On breaker close, FMCircuitDrainerQueueable replays each queued pipeline from the exact buffered stage — no re-running upstream stages, no double-DML, no re-issued callouts.

Kill switch
FM_Config__mdt.CIRCUIT_BUFFER_ENABLED (master), CIRCUIT_DRAIN_BATCH_SIZE (per-Queueable), CIRCUIT_DRAIN_MAX_AGE_MINUTES (expiry), CIRCUIT_DRAIN_MAX_ATTEMPTS (retry budget)
Audit surface
FM_Circuit_Queue__c rows + FM_Circuit_Dead_Letter__e platform event
Schema
FM_Circuit_Queue__c (12 fields, Private sharing)
Example
{
  "id": "breaker_for_provider",
  "component_type": "circuit_breaker",
  "config": {
    "bucket_key": "external_credit_bureau",
    "wrapped_stage": "call_credit_bureau",
    "mode": "buffered",
    "window_size": 20,
    "failure_threshold_pct": 50,
    "cooldown_seconds": 60
  }
}

Concurrency-safe drain

FOR UPDATE row locks plus a Queued → Draining status transition mean two parallel drainers can't double-process the same item. The breaker's half-open → closed hook only enqueues the drainer when queued items actually exist.

Dead-letter monitoring

After CIRCUIT_DRAIN_MAX_ATTEMPTS failures, the item goes to Status__c = 'Failed' and publishes FM_Circuit_Dead_Letter__e. Subscribe from PagerDuty, Datadog (via Heroku Connect), or Slack (via Apex callout) for incident alerts.

How these fit the FlowMason invariants

#2Every kill switch is an FM_Config__mdt key — no hardcoded behavior.
#3Phase B uses UserFieldAccess, Phase A+C write through FMSecurityUtil — all DML/SOQL honors FLS/CRUD.
#4No new executor. Phase C reuses the existing yield/resume machinery via PipelineRunner.continueExecution.
#5ExecutionState.invokingUserId + flsRedactedFields are additive optional — no schemaVersion bump. v1 serialized states deserialize cleanly.

Deployment & verification

All three phases deploy as standard SFDX metadata. Verification sequence:

# 1. MDT field first (deploy ordering)
sf project deploy start --source-dir force-app/main/default/objects/FM_Redaction_Pattern__mdt

# 2. Full source
sf project deploy start --source-dir force-app

# 3. Run the Phase A+B+C test suites
sf apex run test --tests FMRedactor_Test,FMPromptGuard_Test,FMFLSDescribeCache_Test,\
FMCircuitDrainerQueueable_Test,PipelineQueueable_Test --result-format human

# 4. Activate a seed pattern for Phase A smoke test
# Setup → Custom Metadata Types → FM Redaction Pattern → US_SSN → Edit → Is Active ✓

# 5. Verify a test pipeline redacted as expected
SELECT Redaction_Count__c, Redaction_Summary__c, FLS_Redaction_Count__c, FLS_Redacted_Fields__c
FROM PipelineExecution__c ORDER BY StartTime__c DESC LIMIT 5

Want the full architecture + runbooks?

Design specs, architect-level review, and operational runbooks ship with the managed package.

Request access