FabricFabricHarness
Operating

Secrets, Retention, and Residency

Runtime secret providers, enforceable data retention, residency checks, and signed deletion evidence.

Runtime secret providers

Commands use secret('NAME') references. The model and session log see the reference name, never the resolved value. Compose providers in deployment order and pass one resolver into the agent:

import { chainSecretProviders, environmentSecretProvider, secretResolver } from '@fabric-harness/sdk';
import { vaultSecretProvider } from '@fabric-harness/node';

const secrets = chainSecretProviders(
  environmentSecretProvider({ allow: ['LOCAL_TOKEN'] }),
  vaultSecretProvider({
    address: process.env.VAULT_ADDR!,
    token: () => workloadIdentityVaultToken(),
    namespace: 'platform',
    pathForSecret: (name, tenantId) => `tenants/${tenantId}/${name}`,
  }),
);

const fabric = await init({ resolveSecret: secretResolver(secrets) });

Provider failures stop resolution instead of falling through to a less-governed provider. Use workload identity or a rotating token callback rather than embedding a provider credential in source.

Azure Key Vault

import { azureKeyVaultSecretProvider } from '@fabric-harness/azure';

const keyVault = azureKeyVaultSecretProvider({
  vaultUrl: 'https://my-vault.vault.azure.net',
  token: () => managedIdentityAccessToken(),
});

Databricks Secrets

import { databricksSecretsProvider } from '@fabric-harness/databricks';

const workspaceSecrets = databricksSecretsProvider({
  host: process.env.DATABRICKS_HOST!,
  token: () => appServicePrincipalToken(),
  scope: (_name, tenantId) => `fabric-${tenantId}`,
});

The Databricks adapter calls Secret Management at runtime and decodes the returned value inside the provider closure. Workspace tokens and secret values are not added to model messages, events, audit entries, or telemetry.

Retention policy

enforcePersistenceRetention() applies independent age limits to sessions, conversation streams, attachments, audit storage, and telemetry storage. External audit and telemetry systems provide a deleteBefore() adapter, so a configured rule cannot silently report success without deleting from that system.

import { enforcePersistenceRetention } from '@fabric-harness/node';

const result = await enforcePersistenceRetention(persistence, {
  sessions: { maxAgeDays: 30 },
  conversationStreams: { maxAgeDays: 14 },
  attachments: { maxAgeDays: 7 },
  audit: { maxAgeDays: 365, target: siemRetentionTarget },
  telemetry: { maxAgeDays: 30, target: tracingRetentionTarget },
  residency: { region: 'us-west-2', allowedRegions: ['us-west-2'] },
});

Run the coordinator from a singleton scheduled job. Session expiry uses the bundle's cascade deletion path, which removes submissions, conversation streams, and attachments together. Attachment timestamps are used when available; older stored references inherit their session update time.

Residency

assertDataResidency(region, allowedRegions) fails before data maintenance or export when the deployment region is not allowed. Use the same configured region for the database, object backup location, audit sink, telemetry sink, and Databricks workspace. Region labels are application policy inputs; cloud network and IAM controls must independently prevent cross-region endpoints.

Signed deletion evidence

Wrap a persistence bundle to emit an append-only completion record after each successful cascade deletion:

import {
  hmacDeletionEvidenceSigner,
  postgresDeletionEvidenceStore,
  postgresPersistence,
  withDeletionEvidence,
} from '@fabric-harness/node';

const base = postgresPersistence({ client: pool });
const persistence = withDeletionEvidence(base, {
  signer: hmacDeletionEvidenceSigner({
    key: process.env.DELETION_EVIDENCE_KEY!,
    keyId: 'retention-2026-01',
  }),
  store: postgresDeletionEvidenceStore(pool),
});

The receipt contains deletion counts, completion time, key id, signature, and a digest chained to the previous record. Session and tenant identifiers are stored only as keyed HMAC pseudonyms. Prompts, messages, filenames, attachment bytes, and other deleted content are never copied into the evidence record. Use ed25519DeletionEvidenceSigner() when verifiers must validate records without access to the signing key.