use tracing::warn;
use vti_common::audit::{AuditEvent, SingleAdminModeData};
use vti_common::error::AppError;
use crate::server::AppState;
const LAST_SEEN_KEY: &[u8] = b"install:single_admin_mode";
pub async fn audit_on_boot(state: &AppState) -> Result<(), AppError> {
let on = state.config.read().await.acl.single_admin_mode;
let last: Option<bool> = state.install_ks.get(LAST_SEEN_KEY.to_vec()).await?;
let changed = match last {
Some(was) => was != on,
None => on,
};
if changed {
warn!(
enabled = on,
"single-administrator mode {} by host configuration (VTI-APV-022)",
if on { "enabled" } else { "disabled" }
);
write(state, if on { "enabled" } else { "disabled" }).await?;
}
if on {
warn!(
"single-administrator mode is in effect (VTI-APV-022): where no administrator but \
the requester is eligible to consent, the requester's operation-bound step-up \
authorizes the operation instead"
);
write(state, "inEffect").await?;
}
if last != Some(on) {
state.install_ks.insert(LAST_SEEN_KEY.to_vec(), &on).await?;
}
Ok(())
}
pub const SELF_EDIT_EVENT: &str = "selfEditWaived";
#[derive(Debug)]
pub enum SelfEditGate {
Authorized,
StepUpRequired(Box<crate::acl::bound_step_up::ApproveRequest>),
}
pub async fn authorize_self_edit(
state: &AppState,
requester: &str,
op: crate::acl::admin_consent::Operation<'_>,
) -> Result<SelfEditGate, AppError> {
use crate::acl::bound_step_up::{self, EvidencedGate};
match bound_step_up::redeem_or_request_with_evidence(
state,
requester,
op.type_uri,
op.payload,
"Edit your own ACL entry as an unrestricted administrator (single-administrator \
mode, VTI-ACL-052)",
)
.await?
{
EvidencedGate::Required(request) => return Ok(SelfEditGate::StepUpRequired(request)),
EvidencedGate::Satisfied(_) => {}
}
warn!(
requester,
task = op.type_uri,
"an unrestricted administrator edited its own ACL entry — single-administrator \
mode (VTI-ACL-052 item 3, VTI-APV-022), authorized by its operation-bound step-up"
);
if let Some(writer) = state.audit_writer.as_ref() {
writer
.write(
requester,
Some(requester),
AuditEvent::SingleAdminMode(SingleAdminModeData {
event: SELF_EDIT_EVENT.into(),
requirement: Some("VTI-ACL-052".into()),
task: Some(op.type_uri.to_string()),
digest: Some(vti_common::task_consent::payload_digest(
op.type_uri,
op.payload,
)?),
kind: Some("acl.self-edit".into()),
..Default::default()
}),
)
.await?;
}
Ok(SelfEditGate::Authorized)
}
async fn write(state: &AppState, event: &str) -> Result<(), AppError> {
let Some(writer) = state.audit_writer.as_ref() else {
return Ok(());
};
writer
.write(
"daemon",
None,
AuditEvent::SingleAdminMode(SingleAdminModeData {
event: event.into(),
..Default::default()
}),
)
.await?;
Ok(())
}