use serde_json::Value;
pub(crate) const SEALED: &str = "$sealed";
#[must_use]
pub fn is_sealed(value: &Value) -> bool {
value
.as_object()
.is_some_and(|o| o.len() == 1 && o.get(SEALED).is_some_and(serde_json::Value::is_string))
}
#[must_use]
pub fn is_sealed_text(text: &str) -> bool {
text.strip_prefix(SEALED)
.and_then(|rest| rest.strip_prefix(':'))
.is_some_and(|encoded| crate::core::b64::decode(encoded).is_some())
}
#[cfg(feature = "keyring")]
pub(crate) fn wrap(envelope: &[u8]) -> Value {
serde_json::json!({ SEALED: crate::core::b64::encode(envelope) })
}
#[cfg(feature = "keyring")]
pub(crate) fn unwrap(value: &Value) -> Option<Vec<u8>> {
if !is_sealed(value) {
return None;
}
let encoded = value.as_object()?.get(SEALED)?.as_str()?;
crate::core::b64::decode(encoded)
}
#[cfg(feature = "keyring")]
pub(crate) fn wrap_text(envelope: &[u8]) -> String {
format!("{SEALED}:{}", crate::core::b64::encode(envelope))
}
#[cfg(feature = "keyring")]
pub(crate) fn unwrap_text(text: &str) -> Option<Vec<u8>> {
let encoded = text.strip_prefix(SEALED)?.strip_prefix(':')?;
crate::core::b64::decode(encoded)
}
pub(crate) enum SealedField<'a> {
Value(&'a mut Value),
Text(&'a mut String),
}
#[allow(clippy::too_many_lines)]
pub(crate) fn payloads(kind: &mut super::RecordKind) -> Vec<SealedField<'_>> {
use super::RecordKind as K;
match kind {
K::RunAdmitted {
input,
capability: _,
governed_by: _,
input_label: _,
policy_bundle: _,
canon: _,
idempotency_key: _,
admitted_by: _,
served_unchained: _,
} => vec![SealedField::Value(input)],
K::PlanFrozen { plan, steps: _ } => vec![SealedField::Value(plan)],
K::EffectStarted {
descriptor,
recovery: _,
mutates: _,
attempt: _,
backoff_ms: _,
outbound_label: _,
outbound_bytes: _,
} => {
let crate::core::EffectDescriptor { kind: _, args } = descriptor;
vec![SealedField::Value(args)]
}
K::EffectDone {
output,
source: _,
by: _,
spend: _,
declared: _,
} => vec![SealedField::Value(output)],
K::EffectReconciled {
output,
detail,
disposition: _,
spend: _,
declared: _,
asserted_by: _,
note: _,
} => output
.as_mut()
.map(SealedField::Value)
.into_iter()
.chain(detail.as_mut().map(SealedField::Text))
.collect(),
K::GroupSettled {
detail,
group: _,
outcome: _,
} => {
detail.as_mut().map(SealedField::Text).into_iter().collect()
}
K::StepCompensated {
outcome,
compensation: _,
} => vec![SealedField::Text(outcome)],
K::EffectFailed {
error,
spend: _,
disposition: _,
permanent: _,
} => vec![SealedField::Text(error)],
K::Note { text } => vec![SealedField::Text(text)],
K::Observed {
detail,
session: _,
reported: _,
} => detail.as_mut().map(SealedField::Text).into_iter().collect(),
K::RunConcluded {
reason,
outcome: _,
exhaustion: _,
live_spend: _,
chain_head: _,
} => reason.as_mut().map(SealedField::Text).into_iter().collect(),
K::QuotaPassStarted {
period: _,
release_slot: _,
}
| K::StepStarted { skill: _ }
| K::StepFinished { outcome: _ }
| K::CaseBound {
case_kind: _,
opened: _,
correlation: _,
}
| K::DeadlineRegistered {
name: _,
resolved_at: _,
calendar_digest: _,
}
| K::DeadlineTransition {
name: _,
from: _,
to: _,
}
| K::RunSuspended { reason: _ }
| K::BudgetRefused { limit: _, used: _ }
| K::BudgetReadmitted { limit: _ }
| K::AuthorityWithheld {
subject: _,
reason: _,
by: _,
}
| K::AuthorityRestored { subject: _ }
| K::IdentityBound { chain: _ }
| K::PolicyDenied {
reason: _,
action: _,
resource: _,
}
| K::GroupOpened {
group: _,
resources: _,
}
| K::Released {
releaser: _,
release: _,
label: _,
field_labels: _,
value: _,
}
| K::RunCancelled {
actor: _,
reason: _,
}
| K::QuarantineDecided {
decider: _,
reason: _,
decision: _,
}
| K::BreakGlass {
actor: _,
roles: _,
reason: _,
}
| K::Swept {
subject: _,
action: _,
detail: _,
} => Vec::new(),
}
}