Secret Encryption Key Ring
Values of Secret attributes are encrypted with a key ring that every engine-hosting service receives through its configuration. This guide is for operators: what the key is, how it is delivered, how to back it up and rotate it, how existing plaintext credentials are migrated, and how to monitor the result.
The key ring is used from System CK model 2.5.0 and the engine release that ships the Secret value type, together with the bot services secret sweep, the octo-cli commands SecretStatus / ReprotectSecrets / DeleteSecretSweepDump and the MCP tools get_secret_status / start_secret_sweep.
All examples on this page use <base64-32-bytes> as a stand-in. A key is 32 random bytes, base64-encoded (openssl rand -base64 32).
The Key
- Algorithm: AES-256-GCM with a random nonce per value.
- Stored form:
enc:v2:<kid>:<base64url(nonce ‖ tag ‖ ciphertext)>. The headerenc:v2:<kid>:names the key id (kid) and is authenticated as additional data. The tenant id and the entity id are not part of it, so restores into a renamed database, tenant copies and child-tenant restores keep working. - First key
k1: the existing per-cluster instance secret key (Vaultinstance_secret_key). It already encrypts secret-flagged value overrides and Helm repository passwords in the older formatenc:v1:(no key id). No new key has to be generated to start. - Legacy key: values in the old
enc:v1:format are decrypted withLegacyV1Key, which is the same instance secret key. - Helm value overrides: the communication controller's
encrypt-valueendpoint keeps returningenc:v1and refusesenc:v2input. Secret Helm overrides belong in the Secret record memberValueOverride.SecretValue(System.Communication 3.41, record keyPath, unique among overrides that carry aSecretValue; clients write plaintext there and no longer callencrypt-value). Legacy entries that keep anenc:v1value inValuestill deploy but are deprecated.
Because k1 reuses the instance secret key, a leak of that key exposes both the old enc:v1 data and the new secrets. The key id in the new format makes it possible to move to a new key with one re-protect sweep (see Rotation).
Configuration
The key ring is bound from the configuration section SecretEncryption by every engine host (asset repository, communication controller, mesh adapter, bot, identity, platform, report, AI and MCP services).
| Configuration key | Environment variable | Value |
|---|---|---|
SecretEncryption:Keys:<kid> | OCTO_SECRETENCRYPTION__KEYS__<kid> (e.g. OCTO_SECRETENCRYPTION__KEYS__k1) | Base64, 32 bytes. One entry per key id |
SecretEncryption:ActiveKeyId | OCTO_SECRETENCRYPTION__ACTIVEKEYID | Key id used to encrypt new values, e.g. k1. Must name a key of the ring |
SecretEncryption:LegacyV1Key | OCTO_SECRETENCRYPTION__LEGACYV1KEY | Base64, 32 bytes. Decrypts enc:v1: values. Remove once no enc:v1 value remains |
SecretEncryption:StrictMode | OCTO_SECRETENCRYPTION__STRICTMODE | true / false (default false). Rejects reads of legacy clear text, see Strict mode |
Notes:
- Key ids are 1–32 lowercase letters or digits (enforced by the Helm charts). The key id keeps its case in the variable name because it is the id written into the envelope header.
- Without a key ring a service still starts and answers "is set" queries (stored protected values then report
keyMissing). Writing a secret fails withSecretEncryptionNotConfiguredException. Clients readkeyRingConfiguredfrom the environment status to disable secret inputs. - All services of one installation must use the same ring. A service that does not know a key id cannot read values written with it: such values stay stored, read as not set with
keyMissing: trueand become readable once the key id is added (see Unreadable secrets).
Delivery
Kubernetes: core services (octo-mesh chart)
No new value is required. The chart derives the ring from the existing secrets.communicationInstanceSecretKey (from Vault instance_secret_key): k1 = that key, active key k1, legacy key = that key. The variables are rendered into the shared octo-mesh.system-env block, so identity, asset repository, bot, communication controller, platform services and AI services all receive them. The key values are stored in the backend Secret (secretEncryptionKey-<kid>).
For a rotation the chart accepts an override that replaces the derived ring:
secrets:
communicationInstanceSecretKey: <base64-32-bytes> # unchanged, stays k1 and the legacy key
secretEncryptionKeys:
k1: <base64-32-bytes> # list k1 as long as it is still needed
k2: <base64-32-bytes>
secretEncryptionActiveKeyId: k2 # empty = k1
Kubernetes: operator-deployed workloads
Workloads that the communication operator deploys (mesh adapter and other adapters) receive the ring only when their adapter has ReceivesClusterSecrets=true. Set the operator chart value to the same instance secret key:
operator:
clusterSecrets:
instanceSecretKey: <base64-32-bytes> # same value as the core chart; becomes k1 and the legacy key
# optional rotation override, replaces the derived ring:
secretEncryptionKeys: {}
secretEncryptionActiveKeyId: ""
The operator binds these as OPERATOR__CLUSTERSECRETS__SECRETENCRYPTIONKEYS__<kid>, OPERATOR__CLUSTERSECRETS__SECRETENCRYPTIONACTIVEKEYID and OPERATOR__CLUSTERSECRETS__SECRETENCRYPTIONLEGACYV1KEY (ClusterSecretsOptions) and injects them into the workload as secrets.secretEncryption.keys.<kid>, secrets.secretEncryption.activeKeyId and secrets.secretEncryption.legacyV1Key; the mesh adapter chart renders the OCTO_SECRETENCRYPTION__* variables from them. If instanceSecretKey is empty, no ring is injected: adapters start, but reading or writing a Secret attribute fails.
Kubernetes: reporting, MCP and AI charts
The separately packaged reporting (octo-mesh-reporting ≥ 0.3.0), MCP (octo-mesh-mcp ≥ 0.2.0) and AI (octo-mesh-ai ≥ 0.24.0) charts host the runtime engine too and render the same variables. Set the same value as the core chart:
secrets:
communicationInstanceSecretKey: <base64-32-bytes> # same value as the octo-mesh chart; becomes k1 and the legacy key
secretEncryptionKeys: {} # optional rotation override, replaces the derived ring
secretEncryptionActiveKeyId: "" # empty = k1
The values are stored in the chart's backend Secret. If the key is empty nothing is rendered: the service starts, and only reading or writing a Secret attribute fails. The AI chart falls back to aiInstanceSecretKey (documented as the same value).
Edge operator pipelines and engine hosts deployed by other charts need the same variables. Check every engine host of an installation before Secret attributes are used there.
Local development
Start-Octo (octo-tools) sets the ring for host-run services from the shared development key (Get-OctoDevInstanceSecretKey): OCTO_SECRETENCRYPTION__KEYS__k1, OCTO_SECRETENCRYPTION__ACTIVEKEYID=k1 and OCTO_SECRETENCRYPTION__LEGACYV1KEY. It removes any other OCTO_SECRETENCRYPTION__KEYS__* variable left over from an earlier session. Deploy-OctoOperator passes the same key as operator.clusterSecrets.instanceSecretKey, so adapters in the local kind cluster read what the host services wrote. Test-OctoEncryption checks that the ring is present and consistent. The development key is for local use only.
Backup and the Provisioning Guard
Losing the key means every Secret value on the cluster must be re-entered. Only external credentials are affected — no business data is lost — but every connection that uses them stops working until then. The communication controller's encrypted values (enc:v1) depend on the same key.
Disaster recovery = database dump + key ring backup. A dump alone restores the secrets only as unreadable (KEY_MISSING) values; together with the key ring from Vault or Keeper they are readable again.
- Keep a copy of every cluster's instance secret key, and of every additional key id, in Vault and in Keeper. Create the Keeper record when the key is generated and re-check it whenever the Vault entry changes. A Vault restore alone is not a sufficient backup.
- The Vault provisioning playbook refuses to overwrite an existing
instance_secret_keywith a different value. Keep that guard. Never rotate by overwriting the key in place — that makes everyenc:v1andenc:v2:k1value unreadable at once.
Rotation
Rotation never replaces the instance secret key; it adds a new key next to it.
- Add
k2. Generate a new key, store it in Vault and Keeper, and deploy it to every engine host withk1still active (core chart and operator chart override maps listk1andk2,secretEncryptionActiveKeyId: k1). Verify all services restarted with both keys. - Switch the active key. Set
secretEncryptionActiveKeyId: k2on both charts and deploy. New values are written asenc:v2:k2:;k1values keep decrypting. - Re-protect. Run the
Reprotectsweep over all tenants (octo-cli -c ReprotectSecrets -a -y -w), then checkocto-cli -c SecretStatus -auntil no tenant reports a value withkid=k1(octo.secrets.values{kid="k1"}= 0). - Remove
k1. Dropk1from both override maps and deploy. Restoring a dump taken before the rotation brings backk1values — keepk1until no such restore is expected. - Remove
LegacyV1Keyonly when aVerifysweep shows that noenc:v1value remains, and no other component (such as the communication controller's ownenc:v1data) still depends on it.
Never deploy step 2 before step 1 has reached every engine host, including operator-deployed workloads. A service that does not know k2 cannot read values written with it.
Sweep
The sweep walks all Secret attributes of a tenant and reports counts per stored form (notSet, placeholder (legacy clear-text placeholders), plaintext, encV1, encV2 per key id, unknownKeyId per key id, failed) — in total and per CK type and attribute path — plus the list of unreadable values (key id not in the ring) as re-entry tasks. It runs per tenant, including the system tenant and child tenants, and is executed by the bot services.
| Mode | Effect | Confirmation |
|---|---|---|
Verify | Read-only. Reports counts per form and key id and the unreadable values | — |
Encrypt | Encrypts plaintext and enc:v1 values with the active key (enc:v2:<active kid>). Legacy clear-text values that are exactly a placeholder (TODO_SET_<UPPER_SNAKE> or a single <…>) are converted once to "not set" (placeholdersNormalized). Unreadable values are reported, never cleared | Required |
Reprotect | Re-encrypts every value whose key id is not the active key (after a rotation or after adding a source key for a restore). CLI / ops only, not offered in Studio | Required |
CleanupUnreadable | Removes values whose key id the ring does not know and lists them in cleared[]. Irreversible except via the pre-sweep dump. enc:v1 values that are unreadable only because LegacyV1Key is not configured are kept (configure the legacy key instead) and stay in unreadable[]. Needs the SecretManagement role | Required |
There is no decrypt or plaintext export mode in any API (bot, octo-cli, MCP); a Decrypt request is refused with 400. See Rollback.
Every sweep that writes (Encrypt, Reprotect, CleanupUnreadable) first takes a fresh dump of the tenant (except the Encrypt step after a restore, whose pre-state is the restored backup itself). If that dump cannot be taken, the tenant is skipped with the reason in its report. These pre-sweep dumps hold the secrets as they were before the sweep (possibly clear text): they are kept in their own directory, are never downloadable (no endpoint), appear with their state in the list of sweep runs, and are deleted after BackupRetentionDays (7 days) or earlier by a user with SecretManagement.
Bot configuration
Section Bot:SecretSweep of the bot services (environment OCTO_BOT__SECRETSWEEP__*). The key ring itself is the engine section SecretEncryption above.
| Key | Default | Meaning |
|---|---|---|
VerifyCron | 0 3 * * * | Cron (UTC) of the recurring Verify sweep over all tenants. Empty disables it |
RequirePreSweepBackup | true | Take a tenant dump before every writing sweep; skip the tenant if that fails. Set false only deliberately (e.g. local environments without the MongoDB database tools) |
BackupStoragePath | <temp>/octo-bot/secret-backups | Directory of the pre-sweep dumps. Must not lie inside the tus or dump directories; use a persistent volume in Kubernetes |
BackupRetentionDays | 7 | Days a pre-sweep dump is kept before the hourly cleanup deletes it |
BatchSize | 500 | Entities read per repository call |
RunAfterRestore | true | Run the secret steps after a repository restore (see Restore across environments) |
StrictModeSince | empty | Start of strict mode for this environment (UTC, e.g. 2026-11-15T00:00:00Z). From then on every sweep that still finds legacy values logs an error and reports the tenant in octo.secrets.strict_mode.violations |
Bot endpoints
| Endpoint | Role | Response | SDK (IBotServicesClient) |
|---|---|---|---|
GET {tenantId}/v1/secrets/status | Any user with tenant access | SecretEnvironmentStatusDto | GetSecretEnvironmentStatusAsync |
POST {tenantId}/v1/jobs/secret-sweep?mode=Verify|Encrypt|Reprotect|CleanupUnreadable&confirm=true | SecretManagement | JobResponseDto { id }; 400 ConfirmationRequired for a writing mode without confirm=true; 400 for Decrypt | StartSecretSweepAsync(tenantId, mode, confirm) |
GET {tenantId}/v1/jobs/secret-sweep/report | AdminPanelManagement | Last report of the tenant; 404 if none | GetSecretSweepReportAsync |
GET {tenantId}/v1/secrets/sweep-runs?limit=20 | AdminPanelManagement | SecretSweepRunDto[], newest first (last 50 kept per tenant) | GetSecretSweepRunsAsync |
DELETE {tenantId}/v1/secrets/sweep-runs/{runId}/dump | SecretManagement | 204; 404 unknown run or no dump; 409 dump already deleted | DeleteSecretSweepDumpAsync |
POST system/v1/secrets/sweep?mode=… | System tenant admins | JobResponseDto (all tenants) | StartSecretSweepAllTenantsAsync |
GET system/v1/secrets/reports | System tenant admins | Last report of every tenant | GetSecretSweepReportsAsync |
A missing role is answered with 403. Job status: GET system/v1/jobs?id=…. Enums are serialized as names, JSON in camelCase.
Environment status (SecretEnvironmentStatusDto, identical in every tenant except lastVerifyAt):
{
"keyRingConfigured": true, // false: secret writes fail with SecretEncryptionNotConfigured
"activeKeyId": "k1", // null when not configured
"knownKeyIds": ["k1"],
"legacyV1KeyConfigured": true,
"strictMode": false,
"strictModeSince": null, // ISO-8601 when strict mode is scheduled or active
"recurringVerifyCron": "0 3 * * *", // null when disabled
"lastVerifyAt": "2026-10-06T03:00:12Z", // this tenant's last Verify run, null if none
"warnings": [] // "NoKeyRing", "NoLegacyV1Key" (see below)
}
warnings lists codes: NoKeyRing when no key ring is configured (keyRingConfigured: false; Studio shows a prominent banner, secret inputs are disabled, Encrypt is skipped) and NoLegacyV1Key when the tenant's last completed sweep found enc:v1 values but LegacyV1Key is not configured.
Sweep run (SecretSweepRunDto):
{
"runId": "<job id>",
"mode": "Encrypt", // Verify | Encrypt | Reprotect | CleanupUnreadable
"trigger": "Manual", // Manual | Recurring | Restore
"outcome": "Succeeded", // Succeeded | CompletedWithFailures | Skipped | Failed | Running
"startedAt": "…", "completedAt": "…",
"triggeredBy": "user name or null",
"totals": { /* form counts as in the report */ },
"placeholdersNormalized": 0,
"unreadableCount": 0,
"dump": { // null for Verify (no dump)
"fileName": "…presweep.tar.gz",
"exists": true,
"sizeBytes": 123456,
"createdAt": "…",
"expiresAt": "…", // createdAt + 7 days
"deletedAt": null, // set when deleted early or expired
"deletedBy": null
}
}
Report (SecretSweepReport): tenantId, mode, trigger, outcome, reason, startedAt, completedAt, backupFileName, activeKeyId, strictModeActive, strictModeViolation, remainingLegacyValues, placeholdersNormalized, steps[] (per step: totals, slots[], cleared[], failures[]), unreadable[] (ckTypeId, rtId, attributePath, keyId — the re-entry list) and cleared[] (filled only by CleanupUnreadable). It never contains values.
octo-cli commands
The generated command reference has the full help.
SecretStatus — prints the environment status (key ring configured, active key id, known key ids, legacy v1 key, strict mode and since when, recurring Verify cron, last Verify), the last 10 sweep runs with their dump state (exists, size, expiry, deleted), and the last sweep report: counts per form and key id, a table per CK type and attribute path, strict-mode flags, placeholdersNormalized and the unreadable values to re-enter. Never prints values.
| Argument | Required | Description |
|---|---|---|
-tid, --tenantId | No | Tenant to report on (default: tenant of the context) |
-a, --all | No | One line per tenant (system API, run against the system tenant). Not together with -tid |
-j, --json | No | JSON output: { environment, recentRuns, report } for one tenant, the raw reports with -a |
octo-cli -c SecretStatus -tid "mytenant"
octo-cli -c SecretStatus -a
ReprotectSecrets — starts a sweep job and prints the job id.
| Argument | Required | Description |
|---|---|---|
-tid, --tenantId | No | Tenant to sweep (default: tenant of the context) |
-a, --all | No | All tenants (system endpoint system/v1/secrets/sweep). Not together with -tid |
-m, --mode | No | Reprotect (default), Encrypt, CleanupUnreadable or Verify. Decrypt is refused |
-y, --yes | No | Confirm a writing mode. Verify needs no confirmation; Reprotect and Encrypt ask interactively unless -y is given; CleanupUnreadable is refused without -y (no prompt). After confirmation the CLI sends confirm=true to the bot |
-w, --wait | No | Wait for the job and print the resulting report |
# after switching the active key
octo-cli -c ReprotectSecrets -tid "mytenant" -w
# fresh status of one tenant (read-only, no confirmation)
octo-cli -c ReprotectSecrets -tid "mytenant" -m Verify -w
# encrypt remaining legacy values in all tenants (CI/CD)
octo-cli -c ReprotectSecrets -a -m Encrypt -y
# remove values whose key id is unknown (irreversible except via the pre-sweep dump)
octo-cli -c ReprotectSecrets -tid "mytenant" -m CleanupUnreadable -y -w
DeleteSecretSweepDump — deletes the pre-sweep dump of a sweep run before it expires (role SecretManagement).
| Argument | Required | Description |
|---|---|---|
-tid, --tenantId | No | Tenant of the run (default: tenant of the context) |
-r, --runId | Yes | Run id as listed by SecretStatus |
-y, --yes | No | Skip the confirmation prompt |
An unknown run or a run without a dump is an error; a dump that is already deleted only produces a warning.
octo-cli -c DeleteSecretSweepDump -tid "mytenant" -r "1234" -y
MCP tools
get_secret_status(low risk) —allTenants(defaultfalse),tenantId. Returns the environment status, the 10 most recent sweep runs with their dump state, the last report(s) with the unreadable values, and a compact summary per tenant.start_secret_sweep(high risk) —mode(Verifydefault,Encrypt,Reprotect,CleanupUnreadable),allTenants,confirm(required forEncrypt,ReprotectandCleanupUnreadable; passed to the server),waitForCompletion,waitTimeoutMinutes(default 30),tenantId.Decryptis refused.- The secrets overview (inventory) is available through the asset repository GraphQL query
secrets { inventory … }; an MCP tool for it is planned.
Strict mode
Strict mode is phase 5 of the migration, enabled per environment 14 days after the sweep reported zero plaintext:
- Engine hosts:
SecretEncryption:StrictMode=true. A read of a Secret value that is still clear text fails (LegacyPlaintextSecretRejectedException) and incrementsocto.secrets.strict_mode.rejected_reads.enc:v1stays readable as long asLegacyV1Keyis configured. The encrypt / reprotect sweep and the write path still convert remaining clear text. - Bot services:
Bot:SecretSweep:StrictModeSince=<date>. Sweeps that still find legacy values (clear text orenc:v1) report the tenant in the gaugeocto.secrets.strict_mode.violations{tenant}and setstrictModeViolationin the report.
Migration of Existing Credentials
Credential attributes that are still String are converted to Secret in phases. Each environment goes through the phases in the order local → test → staging → production, and proceeds only when the sweep reports zero plaintext.
| Phase | Content |
|---|---|
| 0 | Rotate credentials that were committed to source control, replace them with empty values |
| 1 | Engine release with the Secret value type, key ring (k1 = instance secret key), legacy read, write rules, sweep, System 2.5 gate. Deploy the key ring to every engine host |
| 2 | Consumers handle ciphertext before any model changes: the communication controller decrypts secrets for adapter configuration, the mesh adapter handles Secret attributes and offers RevealSecret@1, Studio and other clients stop selecting secret values. All clients run the new engine |
| 3 | Model changes (Minor): credential attributes become valueType: Secret. From here on nothing projects the value, even if it is still stored as plaintext |
| 4 | Sweep: Encrypt once over all tenants (ReprotectSecrets -a -m Encrypt), then the recurring Verify (VerifyCron). Each writing run starts with a fresh tenant dump (kept 7 days). Adapter service accounts switch to impersonation with an installation-level adapter credential (follow-up AB#5551); their stored secrets are cleared |
| 5 | Strict mode, 14 days after the sweep reported zero plaintext: legacy plaintext is no longer readable |
| 6 | Rotation of credentials that were exposed before the migration |
Gates:
- Phase 2 before phase 3. Clients that still select a secret as a string break when the model changes. The phase 2 code must have shipped one release before phase 4.
- Strict mode is enabled per environment 14 days after the sweep reported zero plaintext.
- Pre-sweep dumps are kept 7 days, treated as secret material, then deleted.
- Pipelines that read credentials with
GetRtEntities*receive only an is-set marker after phase 3; switch them toRevealSecret@1in phase 2. - Adapter configuration is cached until the next deployment: after changing a secret, redeploy the data flow (except where
RevealSecret@1reads the value on demand).
Rollback
Phases 1–3 are code-only and can be rolled back with the binaries. After phase 4, older binaries cannot read the encrypted values. The emergency path is then an engine-internal decrypt with the key, not a binary rollback. No API (bot endpoints, octo-cli, MCP) offers decryption or a plaintext export: it is an engine-level operation (ISecretMaintenanceService with explicit decrypt confirmation) that has to be run as a planned emergency change.
Restore Across Environments
Dumps keep their format and contain the encrypted values after phase 4. A restore keeps the ciphertext: nothing is decrypted or cleared. With Bot:SecretSweep:RunAfterRestore=true (default) every repository restore runs these steps on the restored tenant and stores the result as a report with trigger Restore:
Verify— counts the forms as restored.Encrypt— converts plaintext andenc:v1values from older dumps to the active key. No extra dump is taken: the uploaded backup that was restored is the pre-sweep state.Verify— the final counts and the list of unreadable values.
Values whose key id is not in the target ring stay stored encrypted with the form KEY_MISSING: they read as isSet: false, keyMissing: true, appear in the report's unreadable[] and in the secrets overview as re-entry tasks, and become readable automatically when the key id is added to the ring.
- Same environment: nothing to do; the steps find no unknown key id.
- Bot without key ring: only a key-free
Verifyruns. It classifies without decrypting: everyenc:v2value (its key id is not in the empty ring) and everyenc:v1value while noLegacyV1Keyis configured (key idenc:v1) counts as key missing and is listed inunreadable[]for re-entry; clear text stays clear text. Nothing is written. The run endsSucceededwith the reason "No key ring configured: secrets were classified only; set the key ring and run Encrypt" — configure the key ring, then runEncrypt. - Other environment, tenant copy, child-tenant restore (default): the secrets arrive unreadable and are re-entered (Studio, API,
set_entity_secrets). Checkocto-cli -c SecretStatus -tid <tenant>orsecrets { inventory(needsReEntry: true) }. Once everything is re-entered, the remaining unreadable values can be removed with the admin sweepCleanupUnreadable(octo-cli -c ReprotectSecrets -tid <tenant> -m CleanupUnreadable -y; a pre-sweep dump is taken first). - Optional ops step instead of re-entry: temporarily add the source environment's key to the target ring (deployed to every engine host, not active), restore, run
Reprotect(octo-cli -c ReprotectSecrets -tid <tenant> -y -w) so the values move to the active key, checkSecretStatusuntil no value with the source key id remains, then remove the source key from the ring again.
See also Repository Backup & Restore.
Monitoring
Metrics are emitted on the meter Meshmakers.Octo.Secrets. None of them carries a value.
| Metric | Type | Labels | Meaning |
|---|---|---|---|
octo.secrets.decrypt | Counter | tenant, ckType, attribute, service, form | Every server-side decryption (adapter configuration, RevealSecret@1) |
octo.secrets.plaintext_reads | Counter | tenant, ckType, attribute, service, form | A legacy plaintext value was read from a Secret attribute. Must stay at 0 after the sweep |
octo.secrets.envelope_not_allowed | Counter | tenant, ckType, attribute, service | An enc:v2 envelope stored as a plain string in a Secret slot was refused instead of decrypted. Nothing legitimate produces one — investigate any count |
octo.secrets.strict_mode.rejected_reads | Counter | tenant, ckType, attribute, service | Reads of legacy clear text rejected by strict mode |
octo.secrets.unreadable | Counter | reason (unknown_key_id, corrupt, decrypt_failed), tenant, ckType, attribute, service | A stored value could not be read and was treated as not set (e.g. after a restore from another environment) |
octo.secrets.sweep.rewritten | Counter | tenant, mode (verify, encrypt, reprotect, cleanup_unreadable) | Values changed by the sweep |
octo.secrets.sweep.failed | Counter | tenant, mode | Values the sweep could not process |
octo.secrets.values | Gauge | tenant, model, form (not_set, placeholder, plaintext, enc_v1, enc_v2, unknown_kid), kid | Forms found by the last sweep of each tenant (reported by the bot services; env comes from the OTel resource) |
octo.secrets.strict_mode.violations | Gauge | tenant | Legacy values found by the last sweep while StrictModeSince is in force (0 = compliant) |
Alerts: octo.secrets.strict_mode.violations > 0 (equivalent: octo.secrets.values{form="plaintext"} > 0 after strict mode), and any increase of octo.secrets.strict_mode.rejected_reads or octo.secrets.sweep.failed. During a rotation, octo.secrets.values{kid="k1"} shows the progress of the re-protect sweep.
See Also
- Secret Attributes — the value type
- Secret Attributes in the API — GraphQL semantics
- Repository Backup & Restore