MCPcopy Index your code
hub / github.com/simstudioai/sim / applyPiiRedaction

Method applyPiiRedaction

apps/sim/lib/logs/execution/logger.ts:619–665  ·  view source on GitHub ↗

* Mask PII from log content before persistence when the execution's workspace * (via workspace override or org default) has enterprise PII redaction enabled. * Resolved at persist time so both the inline and externalized write paths are * covered. Returns the payload unchanged when disabled

(
    workspaceId: string | null,
    payload: RedactablePayload,
    storeContext: { workflowId?: string | null; executionId: string; userId?: string | null }
  )

Source from the content-addressed store, hash-verified

617 * covered. Returns the payload unchanged when disabled or non-enterprise.
618 */
619 private async applyPiiRedaction(
620 workspaceId: string | null,
621 payload: RedactablePayload,
622 storeContext: { workflowId?: string | null; executionId: string; userId?: string | null }
623 ): Promise<RedactablePayload> {
624 if (!workspaceId) return payload
625
626 const [row] = await db
627 .select({ orgSettings: organization.dataRetentionSettings })
628 .from(workspace)
629 .leftJoin(organization, eq(organization.id, workspace.organizationId))
630 .where(eq(workspace.id, workspaceId))
631 .limit(1)
632 if (!row) return payload
633
634 // Resolve from stored rules UNCONDITIONALLY — deliberately NOT gated on the
635 // `pii-redaction` feature flag or the enterprise-plan check. Rules are only
636 // writable by entitled orgs (route-gated), so their presence is the source of
637 // truth; re-checking the flag/plan here returns false on a transient read and
638 // would silently skip masking, leaking PII (fail-open). Absence of rules
639 // yields the disabled default, so non-PII orgs incur only the lookup.
640 const config = resolveEffectivePiiRedaction({ orgSettings: row.orgSettings, workspaceId }).logs
641 if (!config.enabled) return payload
642
643 // The string redactor can't reach values already offloaded to large-value
644 // storage (>8MB refs). Always hydrate → mask → re-store them under the LOGS
645 // policy, even if the block-output stage already masked before offload: that
646 // used the block-output entity set, which can differ from the logs set, so
647 // the log's large values must get the logs policy applied like inline content
648 // does. Masking is idempotent, so already-masked spans are unaffected; a ref
649 // that can't be materialized/re-stored falls back to a marker.
650 const working = await redactLargeValueRefs(payload, {
651 entityTypes: config.entityTypes,
652 language: config.language,
653 store: {
654 workspaceId,
655 workflowId: storeContext.workflowId ?? undefined,
656 executionId: storeContext.executionId,
657 userId: storeContext.userId ?? undefined,
658 },
659 })
660
661 return redactPIIFromExecution(working, {
662 entityTypes: config.entityTypes,
663 language: config.language,
664 })
665 }
666
667 async completeWorkflowExecution(params: {
668 executionId: string

Callers 1

Calls 4

redactLargeValueRefsFunction · 0.90
redactPIIFromExecutionFunction · 0.90
eqFunction · 0.50

Tested by

no test coverage detected