ISecretMaintenanceService
Namespace: Meshmakers.Octo.Runtime.Contracts.Secrets
Maintenance of the stored values of Secret attributes of a tenant (AB#5532, concept §5.2
phase 4, §5.3, §6): verify, encrypt legacy values, re-protect with the active key, the explicit
admin cleanup of unreadable values (unknown key id) and the engine-internal emergency decrypt.
Values whose key id is not in the ring are KEPT by every mode except
SecretSweepMode.CleanupUnreadable and reported in SecretSweepResult.Unreadable
as the re-entry list (decisions 2026-10-06, item 2). Implemented in
Runtime.Engine (SecretMaintenanceService) and registered by AddRuntimeEngine().
The bot SecretSweepJob (WP9), the system API and the octo-cli commands
(SecretStatus, ReprotectSecrets) build on it.
public interface ISecretMaintenanceService
Remarks:
The service walks every concrete CK type of the tenant that has a Secret attribute (top-level
or inside a record, at any nesting depth), reads the entities in batches through
IRuntimeRepository.GetRtEntitiesByTypeAsync (archived = deleted entities included: their
stored values are processed too, counted in SecretSweepResult.ArchivedEntitiesScanned, but
never listed as re-entry tasks) and rewrites
changed attributes through IRuntimeRepository.RewriteAttributeValueIfUnchangedForMigrationAsync
(a record-valued attribute is rewritten as a whole). The rewrite is conditional on the stored
value still being the one the sweep read; an attribute changed in between is skipped and
counted in SecretSweepResult.SkippedConcurrentlyModified. It works on the values as the
repository returns them: RtSecretValue.Protected for an enc:v2 sub-document,
RtSecretValue.LegacyPlaintext or a plain string for a legacy string slot.
Results carry counts and names only - never a value, never ciphertext. Every mode is idempotent; a second run of the same mode rewrites nothing.
Methods
SweepTenantAsync(String, SecretSweepMode, CancellationToken)
Runs a sweep over all Secret values of a tenant with the default options. SecretSweepMode.Decrypt and SecretSweepMode.CleanupUnreadable are refused here; they need SecretSweepOptions.ConfirmDecrypt / SecretSweepOptions.ConfirmCleanupUnreadable through the other overload.
Task<SecretSweepResult> SweepTenantAsync(string tenantId, SecretSweepMode mode, CancellationToken cancellationToken)
Parameters
tenantId String
Tenant to sweep
mode SecretSweepMode
What to do with the values found
cancellationToken CancellationToken
Cancellation token; a cancelled sweep keeps what it already rewrote
Returns
Task<SecretSweepResult>
Counts per form and per CK type / attribute, cleared values and failures
SweepTenantAsync(String, SecretSweepMode, SecretSweepOptions, CancellationToken)
Runs a sweep over all Secret values of a tenant.
Task<SecretSweepResult> SweepTenantAsync(string tenantId, SecretSweepMode mode, SecretSweepOptions options, CancellationToken cancellationToken)
Parameters
tenantId String
Tenant to sweep
mode SecretSweepMode
What to do with the values found
options SecretSweepOptions
Batch size, decrypt / cleanup confirmation, CK model filter
cancellationToken CancellationToken
Cancellation token; a cancelled sweep keeps what it already rewrote
Returns
Task<SecretSweepResult>
Counts per form and per CK type / attribute, cleared values and failures
Exceptions
InvalidOperationException
SecretSweepMode.Decrypt without SecretSweepOptions.ConfirmDecrypt, or
SecretSweepMode.CleanupUnreadable without SecretSweepOptions.ConfirmCleanupUnreadable
SecretEncryptionNotConfiguredException
A mode that writes or decrypts (everything but SecretSweepMode.Verify) on a host
without an active key
NormalizePlaceholdersAsync(String, String, CancellationToken)
CK migration hook (concept §5.2 phase 3): when a model switches attributes from String to
Secret, stored LEGACY strings in Secret slots that are exactly a placeholder
(: <...>, TODO_SET_...)
or empty become null ("not set"), once. Nothing is encrypted and no key is needed - the
encrypt sweep does that later. Called by the CK model migration service after a successful
migration of ckModelName.
Task<SecretSweepResult> NormalizePlaceholdersAsync(string tenantId, string ckModelName, CancellationToken cancellationToken)
Parameters
tenantId String
Tenant
ckModelName String
Only CK types of this model, or types whose Secret attributes are defined by it, are scanned;
null = every type with a Secret attribute
cancellationToken CancellationToken
Cancellation token
Returns
Task<SecretSweepResult>
The scan result; SecretSweepResult.PlaceholdersNormalized counts the normalised slots