Skip to main content

ephemeris_forge_github/plan/
actions.rs

1use ephemeris_forge::{FieldDiff, Report};
2
3use crate::config::actions::{Actions, AllowList};
4use crate::live::ActionsLive;
5use crate::operation::actions::{Group, GroupType};
6
7pub(super) fn plan(
8    config: Option<&Actions>,
9    live: &ActionsLive,
10    report: &mut Report,
11) -> Vec<Group> {
12    let Some(actions) = config else {
13        return Vec::new();
14    };
15    [
16        group(actions.permissions.as_ref(), live, report),
17        selected_actions(actions.selected_actions.as_ref(), live, report),
18        group(actions.workflow.as_ref(), live, report),
19        group(actions.access.as_ref(), live, report),
20        group(actions.artifact_and_log_retention.as_ref(), live, report),
21        group(actions.fork_pr_contributor_approval.as_ref(), live, report),
22        group(
23            actions.fork_pr_workflows_private_repos.as_ref(),
24            live,
25            report,
26        ),
27        group(actions.cache.as_ref(), live, report),
28        group(actions.oidc_subject.as_ref(), live, report),
29    ]
30    .into_iter()
31    .flatten()
32    .collect()
33}
34
35fn selected_actions(
36    desired: Option<&AllowList>,
37    live: &ActionsLive,
38    report: &mut Report,
39) -> Option<Group> {
40    let desired = desired?.clone().normalized();
41    let Some(live) = live.get::<AllowList>() else {
42        // The read is unavailable until the policy is "selected", so write the
43        // selection.
44        return Some(desired.into());
45    };
46    let live = live.clone().normalized();
47    compare(&desired, Some(&live), report)
48}
49
50fn group<G: GroupType>(
51    desired: Option<&G>,
52    live: &ActionsLive,
53    report: &mut Report,
54) -> Option<Group> {
55    compare(desired?, live.get::<G>(), report)
56}
57
58fn compare<G: GroupType>(desired: &G, live: Option<&G>, report: &mut Report) -> Option<Group> {
59    let Some(live) = live else {
60        report.limitations.push(G::limitation());
61        return None;
62    };
63    let mut diff = FieldDiff::default();
64    desired.compare(live, &mut diff);
65    let changed = diff.has_changes();
66    diff.record(&format!("actions {}", G::NAME), report);
67    changed.then(|| desired.clone().into())
68}