liminal-server 0.24.9

Standalone server for the liminal messaging bus
Documentation
//! The approved-draft executor: approvals are checked, then committed once.

use super::{AtomicDraftStore, SiteDraftStore, storage_error};
use crate::auth_lys::live::drafts::{ApprovalTransition, DraftError};
use lys_pass::drafts::{ApprovedDraft, Execution, Executor};
use std::collections::BTreeSet;

impl Executor for SiteDraftStore {
    type Error = DraftError;
    fn receipt(&self, draft: &str) -> Result<Option<Execution>, DraftError> {
        AtomicDraftStore::receipt(self, draft)
    }
    fn execute_and_record(&mut self, draft: &ApprovedDraft) -> Result<Execution, DraftError> {
        let evidence = self.approval(draft)?;
        let needed = match evidence.mode {
            crate::auth_lys::GrantMode::ByDraft => 1,
            crate::auth_lys::GrantMode::ByTwo => 2,
            crate::auth_lys::GrantMode::Outright => return Err(DraftError::ApprovalUnavailable),
        };
        let bound = self
            .lifecycle
            .site_bindings()
            .map_err(storage_error)?
            .limits
            .text_bytes
            .get();
        let mut people = BTreeSet::new();
        if evidence.draft != draft.id
            || evidence.digest != draft.request_digest
            || evidence.approved_by.len() != needed
            || evidence.approved_by.iter().any(|person| {
                person.is_empty()
                    || person.len() > bound
                    || person.chars().any(char::is_control)
                    || !people.insert(person)
            })
        {
            return Err(DraftError::ApprovalUnavailable);
        }
        self.commit(
            draft,
            &ApprovalTransition {
                draft: draft.id.clone(),
                digest: draft.request_digest.clone(),
                approved_by: evidence.approved_by,
                executed_at_ms: self.at_ms,
            },
        )
    }
}