Reference implementation. ArchRails enforces the architectural slice of this framework — this template is not itself a compliance certification, attestation, or audit outcome. Read the full disclaimer →
Attestation, not implementation. Each snippet below records a CALM-level attestation against a node, edge, or graph. The engine enforces that the attestation is present (where a SOC 2 framework validator covers the control) and that the agent's declared_pattern matches what you authored (where the constraint engine reads your config). It does not read your runtime code or infrastructure to verify the attestation reflects reality — verifying that session-timeout-minutes: 30 actually appears in your IdP configuration is the responsibility of your runtime monitoring, infrastructure scanning, and auditor review. ArchRails enforces the contract; the contract enforces the engineer.

Control template: SOC 2 Type II Trust Services Criteria

Status: Stable · Version: soc2-type-ii/v1.0.0

A bundle of CALM control snippets covering the architecturally enforceable subset of the AICPA 2017 Trust Services Criteria (TSC) that SOC 2 Type II auditors test. You copy these into your *.calm.json files on the nodes that are in your SOC 2 audit scope.

Who SOC 2 applies to

Any service organization that wants to demonstrate to customers (usually enterprise customers via security questionnaires or vendor- risk assessments) that it maintains effective controls over relevant trust criteria. There is no regulatory requirement for SOC 2 — it's buyer-driven. Common drivers: - SaaS companies selling to enterprise / Fortune 500 - Cloud service providers, MSPs, MSSPs - Payment processors, fintech infrastructure - Healthcare-adjacent SaaS that also pursues HITRUST - Anyone responding to "send us your SOC 2" in a procurement RFP

What this template covers

The 2017 TSC has 5 categories. Only Security (CC1–CC9 Common Criteria) is mandatory for every audit; the other four (Availability, Processing Integrity, Confidentiality, Privacy) are optional and only in scope if the firm elects to include them.

The architectural surface lives mostly in CC6 (Logical Access), CC7 (System Operations), and CC8 (Change Management). CC1–CC5 are governance and process — document those in your SOC 2 readiness package, not in your CALM.

TSC Criterion Architectural surface Control alias
CC6.1 Logical access security access-control
CC6.3 Role-based authorization rbac
CC6.7 Transmission security (encryption in transit) soc2-transmission-security + edge protocol
CC6.8 / C1.1 (optional) Data encryption + confidentiality designation data-encryption

3 controls in the mandatory Security category + 1 control in the most common optional category (Confidentiality). Skip the optional one if you haven't elected that category.

About the control key names. Most snippets above use bare control keys (access-control, rbac, etc.) rather than soc2-* prefixes. That's because ArchRails ships dedicated SOC 2 framework validators that fire on these exact keys; using the bare name lets the validator find your control. The SOC 2 regulatory tag is preserved in each snippet's config as a soc2-citation field for audit pivot. One snippet retains the soc2-* prefix — that's a documentation tag whose enforcement keys off a different mechanism (transmission-security edges).

The audit-scope pattern

A node is SOC 2-in-scope if it is part of the system boundary defined in your auditor's report. Tag those nodes:

{
  "unique-id": "tenant-data-api",
  "node-type": "service",
  "name": "Tenant Data API",
  "metadata": {
    "soc2-in-scope": true,
    "soc2-categories": ["security", "availability", "confidentiality"],
    "data-classification": "customer-confidential"
  }
}

Then attach the relevant controls below.

Infrastructure verification. ArchRails now verifies the following controls against your infrastructure at PR review time and during code generation (AWS): data-encryption.

Control snippets

Copy each block under the controls key of the node it applies to.

CC6.1 — Logical access security (access-control)

Per-node. The control key access-control is what the SOC 2 CC6.1 framework validator looks for; the soc2-citation field preserves the regulatory tag for audit pivot.

"access-control": {
  "description": "SOC 2 TSC CC6.1 — logical access security software and procedures restrict access to information assets, data, software, and physical resources.",
  "requirements": [
    {
      "requirement-url": "https://archrails.io/catalog/req/soc2/logical-access",
      "config": {
        "control-id": "access-control",
        "soc2-citation": "CC6.1",
        "access-mechanism": "saml-sso-plus-mfa",
        "identity-provider": "okta",
        "session-timeout-minutes": 30,
        "access-review-frequency": "quarterly"
      }
    }
  ]
}

CC6.3 — RBAC (rbac)

Per-node. The control key rbac is an alias accepted by the CC6.1 access-control validator, so this snippet satisfies both CC6.1 (access control) and CC6.3 (role-based authorization) intent.

"rbac": {
  "description": "SOC 2 TSC CC6.3 — entity authorizes, modifies, or removes access to data, software, functions based on roles, responsibilities, or system design.",
  "requirements": [
    {
      "requirement-url": "https://archrails.io/catalog/req/soc2/rbac",
      "config": {
        "control-id": "rbac",
        "soc2-citation": "CC6.3",
        "principle": "least-privilege",
        "allowed-roles": ["tenant-read", "tenant-write", "tenant-admin", "support-read-only"],
        "review-frequency": "quarterly",
        "joiner-mover-leaver-process-url": "https://internal.example.com/soc2/jml"
      }
    }
  ]
}

CC6.7 — Transmission security (soc2-transmission-security)

Relationship-level. Attach to edges that cross trust boundaries.

// On a relationship:
"controls": {
  "soc2-transmission-security": {
    "description": "SOC 2 TSC CC6.7 — entity restricts transmission of information to authorized internal/external users and processes; in-transit encryption required across trust boundaries.",
    "requirements": [
      {
        "requirement-url": "https://archrails.io/catalog/req/soc2/transmission-security",
        "config": {
          "control-id": "soc2-transmission-security",
          "soc2-citation": "CC6.7",
          "minimum-tls-version": ["1.2", "1.3"],
          "forbidden-fields": ["http", "ftp", "telnet", "smtp-plain", "ws"],
          "mutual-auth-on-organization-boundary": true
        }
      }
    ]
  }
}
Where enforcement actually happens for this control. Unlike the per-node SOC 2 controls above, the CC6.7 framework validators don't look for a control key called soc2-transmission-security — they walk every edge in the graph and fire on (a) any edge using a plaintext protocol (http, ftp, telnet, ws, smtp, etc.) and (b) any edge pinning TLS < 1.2. So the substantive enforcement keys off the edge's protocol field, not this control snippet. The snippet records the regulatory tag against the edge for audit pivot and pins your TLS-version + forbidden-protocols intent so the constraint engine fires if an agent's declared_pattern claims to use a forbidden protocol.

CC6.8 / C1.1 — Data encryption + confidentiality (data-encryption)

Per-node (attach to data-store nodes). The control key data-encryption is what the CC6.8 + C1.1 framework validator looks for. The validator fires when a data-store node in SOC 2 scope doesn't declare this control.

"data-encryption": {
  "description": "SOC 2 TSC CC6.8 + C1.1 — entity identifies and maintains confidential information; data at rest and in transit are encrypted as a measure proportionate to the classification.",
  "requirements": [
    {
      "requirement-url": "https://archrails.io/catalog/req/soc2/confidentiality",
      "config": {
        "control-id": "data-encryption",
        "soc2-citation": "CC6.8 + C1.1",
        "data-classification-applied": "customer-confidential",
        "encryption-at-rest": "AES-256-GCM",
        "encryption-in-transit": "tls-1.2-or-1.3",
        "access-restricted-to-roles": ["tenant-admin", "support-escalation"],
        "data-retention-policy-url": "https://internal.example.com/soc2/data-retention",
        "data-disposal-procedure-url": "https://internal.example.com/soc2/data-disposal"
      }
    }
  ]
}

What the engine actually enforces

SOC 2 is the only framework in ArchRails with dedicated framework validators (12 of them) on top of the generic constraint engine that handles every framework template. Enforcement is graph-driven: you attach a control where you want it enforced, and the absence of an attach is opt-out by silence. To trigger the framework validators, the graph must declare metadata.compliance-frameworks: ["soc2"]; without that, only the constraint-engine attestation layer fires.

For the 4 SOC 2 controls above, here is the honest split:

Enforced via dedicated SOC 2 framework validators

When SOC 2 is declared on the graph and a node is in scope (soc2-in-scope: true or sensitive data-classification), the validator fires if the node doesn't declare the listed control. PR-time only.

Enforced via attestation only (constraint engine)

Every snippet's config block is read by the constraint engine: presence / exact / enum / set_required / set_forbidden shapes are inferred from what you authored, and the agent's declared_pattern must satisfy them. This applies to every snippet's value-level checks (TLS version, retention days, RPO/RTO, SLA uptime, forbidden protocols, required logging events) regardless of whether the control has a framework validator.

Documentation / audit metadata (no engine enforcement)

None today — every snippet on this page is covered by either a SOC 2 framework validator or the constraint engine (or both).

All checks are deterministic — pure function over your CALM JSON. Verdicts are replayable byte-for-byte. The same constraint engine handles PCI DSS, GDPR, HIPAA, MiFID II, ISO 27001:2022, NIST CSF 2, NYDFS Part 500, and any controls you author yourself.

Type I vs Type II

This template helps with both, but more so with Type I (design) because that's what an architecture declaration captures. Type II requires evidence over time (logs, exception records, test results), which is your SOC 2 readiness program's job — not architectural. Your auditor's testing of operating effectiveness is the Type II story.

Versioning

This is soc2-type-ii/v1.0.0 — the first stable cut. Each surviving control has per-validator firing tests + cross-language coverage across 11 Tier A languages (Python, Java, C#, TypeScript, Go, Kotlin, Scala, Rust, Ruby, Swift, PHP). Future bumps: v1.x.y for additive controls and substantive validator coverage; v2.0.0 for breaking changes (control retired, semantics changed). Updates as authoritative guidance or enforcement priorities materially shift.

Out of scope for this template

For those surfaces, pair this template with your SOC 2 readiness program and engage a CPA firm for the audit.