byteor_app_kit/
actions.rs

1//! Helpers for integrating side-effecting action stages.
2//!
3//! Stage identity syntax (resolved via `StageOpV1::ResolverKey`):
4//! - `http_post:<url>`
5//! - `exec:<program>|<arg>|...`
6
7use byteor_core::config::Environment;
8use byteor_pipeline_exec::StageResolver;
9
10use crate::capabilities::{
11    prefix_stage_catalog_entry, ExecutionTarget, PolicyClassId, ReplaySupport,
12    RuntimeEnvironment, StageCatalogEntry,
13};
14
15/// Build an action-stage resolver configured for a product run.
16///
17/// This is thin glue around `byteor-actions` plus enterprise policy defaults.
18pub fn build_action_stages(
19    env: Environment,
20    approval_token_present: bool,
21    is_replay: bool,
22    dry_run: bool,
23    replay: byteor_policy::ReplayAccounting,
24) -> impl StageResolver {
25    let policy = byteor_policy::Policy::safe_defaults(env);
26
27    byteor_actions::resolver::ActionStages::new(
28        policy,
29        is_replay,
30        dry_run,
31        approval_token_present,
32        replay,
33    )
34}
35
36/// Build an action-stage resolver using default replay accounting.
37pub fn build_action_stages_default_replay(
38    env: Environment,
39    approval_token_present: bool,
40    is_replay: bool,
41    dry_run: bool,
42) -> impl StageResolver {
43    build_action_stages(
44        env,
45        approval_token_present,
46        is_replay,
47        dry_run,
48        byteor_policy::ReplayAccounting::default(),
49    )
50}
51
52/// Build stage-catalog entries for the action-stage families published by product runtimes.
53pub fn action_stage_catalog_entries() -> Vec<StageCatalogEntry> {
54    byteor_actions::resolver::stage_families()
55        .iter()
56        .map(|family| {
57            prefix_stage_catalog_entry(
58                format!("{}*", family.key_prefix),
59                family.description,
60                vec![ExecutionTarget::SingleRing, ExecutionTarget::LaneGraph],
61                PolicyClassId::SideEffecting,
62                ReplaySupport::DryRunOnly,
63                vec![
64                    RuntimeEnvironment::Dev,
65                    RuntimeEnvironment::Staging,
66                    RuntimeEnvironment::Prod,
67                ],
68                family
69                    .approval_capabilities
70                    .iter()
71                    .map(|capability| (*capability).to_string())
72                    .collect(),
73            )
74        })
75        .collect()
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn action_stage_catalog_entries_follow_resolver_families() {
84        let catalog = action_stage_catalog_entries();
85        let families = byteor_actions::resolver::stage_families();
86
87        assert_eq!(catalog.len(), families.len());
88        for (entry, family) in catalog.iter().zip(families.iter()) {
89            assert_eq!(entry.key, format!("{}*", family.key_prefix));
90            assert_eq!(entry.description, family.description);
91            assert_eq!(entry.policy_class, PolicyClassId::SideEffecting);
92            assert_eq!(entry.replay_support, ReplaySupport::DryRunOnly);
93        }
94    }
95}