Skip to main content

Compliance

You are the data controller; the processor runs in your environment.

This page covers the GDPR / SOC 2 controls the system ships — the data it stores, the data-subject-request endpoints, retention, and audit trails. It pairs with Security and Data boundary, which own the access and privacy mechanics.

Roles, responsibilities & posture

The controller/processor model, the shared-responsibility split, and Anyray's regulatory standing are on the Anyray compliance page. This page documents the shipped controls.

SOC 2 Type I attested

Anyray holds an independent SOC 2 Type I attestation of its own program (as of 6 July 2026), examined by Securance Pro Assurance PLLC against the Security, Availability, and Confidentiality Trust Services Criteria. A SOC 2 Type II examination is in progress. The report is available under NDA — contact security@anyray.ai. Because Anyray is self-hosted, the attestation program for your deployment stays yours; Anyray supplies the control inventory and audit evidence to support it.

What data your deployment stores

Every store below lives on your volumes — none on a vendor system. The one exception is the Billing app account plane (last two rows), which carries content-free metadata only (counts, aggregates, pseudonymous seat hashes), never prompt/response content.

StoreDataWhere
Spend storePer-request metadata: user/team, model, provider, tokens, cost, latency. Never content.Your Postgres (anyray_spend)
Connector observations (when configured)Official vendor usage metadata: timestamps, user/model identifiers, vendor-native quantities, and reported cost. Never prompts, responses, source code, or attachments. Kept separate from request spend.Your Postgres (anyray_spend_connector_events)
Observability tracesAttribution + token/cost/latency metadata; content only per the content mode (ciphertext in encrypted, none in off, raw only in deploy-gated plaintext).Your Postgres (anyray_traces / anyray_observations)
Client keys & enrollment linksUsernames bound to records — token hashes only (SHA-256), never raw values.Gateway data volume
Optimizer ephemeral storesSemantic-cache responses and stashed originals, in memory, TTL-bounded, keyed by content-free hashes.Optimizer memory
Audit logsAdmin/GDPR actions: actor + action + timestamp. Metadata only.Your Postgres (anyray_audit_log); per-pod files as fallback
Anyray Billing app planeOperator emails/names (Google sign-in), tenant memberships, content-free usage rollups, seat hashes, and the deployment heartbeat (health, counts, error class names, env-var names — never values, content, or user identities).Vendor Billing backend
Support bundles (explicitly pushed)Only when an admin clicks Send: the redacted, content-free diagnostic bundle plus its analysis. Never automatic, never pullable by Anyray.Vendor Billing backend (newest 20, 90-day retention)
Seat hashes are pseudonymous, not anonymous

Seat identifiers sent to the Billing app are HMAC-SHA256'd with ANYRAY_PSEUDONYM_SALT, which never leaves your environment — so they're re-identifiable only with a salt the vendor never holds. Set the salt: unset, the gateway falls back to an empty-key HMAC, making the digests dictionary-checkable. Drop service/bot accounts before pseudonymization with ANYRAY_SEAT_EXCLUDE.

Rotating the content key has no migration path

Content at rest is AES-256-GCM, keyed by ANYRAY_CONTENT_KEY (see Encryption at rest). There is no keyring: set a new key and blobs written under the old one become permanently undecryptable unless you re-encrypt them offline first. Store the key in your secret manager, not the repo.

Data subject requests

The gateway exposes admin-gated endpoints for erasure and export. All are capability-gated under RBAC (security_admin or owner; the break-glass ANYRAY_ADMIN_TOKEN always works), and each call is itself audit-logged.

Erasure (GDPR Art. 17)

StoreEndpointRemoves
Gatewaydelete /admin/gdpr/users/:userEvery spend row, cap counter, client key, and enrollment link for the user (which also cuts their access), plus their trace rows. An owner-level request also removes connector observations whose exact attribution.user or userId matches. Returns per-store counts.
Optimizerpost /admin/optimizer/purgeDrops the whole semantic cache and stash from memory.
Anyray Billing appdelete /portal/meA portal operator self-erases their account, memberships, and sessions. Refuses (409) if they're a tenant's sole owner.
The optimizer purge is all-or-nothing

Its stores are keyed by content-free hashes with no per-user index, so one user can't be selectively purged — the call clears everything (entries expire on their own within an hour anyway).

Access & portability (GDPR Art. 20)

ScopeEndpointReturns
Gatewayget /admin/gdpr/users/:user/exportEverything the gateway holds for the user as JSON — spend rows and, for an owner-level request, matching connector observations (all metadata only; content stripped defensively even in plaintext) plus key/link metadata (hashes stripped).
Anyray Billing appget /portal/me/exportA portal operator's own account data: profile, memberships, and audit-log entries.
Connector observations cover the deployment

Tenant SSO users cannot export or delete connector rows. Only the deployment owner or ANYRAY_ADMIN_TOKEN can. This prevents cross-tenant access.

Retention (GDPR Art. 5(1)(e))

Storage limitation is per-store. Only the spend/trace window is a knob you set directly.

StoreDefaultConfigurable?
Spend storeUnset = kept indefinitely (ANYRAY_SPEND_RETENTION_DAYS prunes at boot and daily)Yes
Connector observations90 days maximum; a shorter positive ANYRAY_SPEND_RETENTION_DAYS applies. Cleanup continues without active connectors.No
Observability traces90 days (overridden by ANYRAY_SPEND_RETENTION_DAYS when set)Yes
Optimizer cache / stashIn-memory, lost on restart (cache 3600s, stash 1800s); durable stash rows swept hourlyNo
Optimizer decision pinsPruned after 30d idleNo
Audit logsKept indefinitely in Postgres (unpruned by spend retention); fallback files until rotatedVia your Postgres retention
Billing app planeSessions expire; invites pruned after 90d; usage rollups tiered (30d / 90d / 365d)ANYRAY_CP_RETENTION_TIERS
Support bundles (vendor side)Newest 20 per deployment, 90dNo

Audit trails (SOC 2 CC6/CC7)

Every admin mutation is recorded as an append-only, metadata-only event ({ ts, actor, action, category } — never content). The actor is the SSO operator's IdP email, or break-glass for anything done with the shared admin key. Trails are written to the shared spend Postgres (anyray_audit_log), so they're durable across restarts and centralized across replicas; per-pod files under ANYRAY_DATA_DIR are the dev fallback and outlive spend rows (compliance evidence).

Covered domains include GDPR/DSAR operations, content-mode changes, client- and provider-key and enrollment-link changes, user caps, routing and model aliases, optimizer config and purges, admin sessions, and the Billing app lifecycle. The access controls behind these trails — admin-token auth, console SSO with RBAC, the auth-failure throttle, and signed sessions — live in Security.