Skip to main content

ephemeris_forge_github/config/
actions.rs

1//! Desired GitHub Actions settings.
2
3use std::num::NonZeroU32;
4
5use facet::Facet;
6
7/// Desired GitHub Actions settings. A group that is `None` is left alone.
8#[derive(Clone, Debug, Eq, Facet, PartialEq)]
9#[facet(deny_unknown_fields)]
10pub struct Actions {
11    /// Whether Actions runs and which actions may run.
12    pub permissions: Option<Permissions>,
13    /// The allow list used when only selected actions may run.
14    pub selected_actions: Option<AllowList>,
15    /// The default token permissions of workflows.
16    pub workflow: Option<Workflow>,
17    /// Which repositories may use this repository's actions. Private
18    /// repositories only.
19    pub access: Option<Access>,
20    /// How long artifacts and logs are kept.
21    pub artifact_and_log_retention: Option<ArtifactAndLogRetention>,
22    /// Which fork pull request contributors need approval.
23    pub fork_pr_contributor_approval: Option<ForkPrContributorApproval>,
24    /// How workflows run for fork pull requests. Private repositories only.
25    pub fork_pr_workflows_private_repos: Option<ForkPrWorkflowsPrivateRepos>,
26    /// The limits of the Actions cache.
27    pub cache: Option<Cache>,
28    /// How the OIDC subject claim is built.
29    pub oidc_subject: Option<OidcSubject>,
30}
31
32/// Which actions and reusable workflows may run.
33#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
34#[repr(u8)]
35pub enum ActionScope {
36    /// Every action and reusable workflow.
37    #[facet(rename = "all")]
38    All,
39    /// Only those in the same repository or organization.
40    #[facet(rename = "local_only")]
41    LocalOnly,
42    /// Only those that match the allow list.
43    #[facet(rename = "selected")]
44    Selected,
45}
46
47/// The permissions a workflow token has by default.
48#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
49#[repr(u8)]
50pub enum TokenPermissions {
51    /// Read access to the repository contents.
52    #[facet(rename = "read")]
53    Read,
54    /// Read and write access to the repository.
55    #[facet(rename = "write")]
56    Write,
57}
58
59/// Who may use the actions and workflows of a private repository.
60#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
61#[repr(u8)]
62pub enum AccessLevel {
63    /// Only this repository.
64    #[facet(rename = "none")]
65    None,
66    /// Other repositories of the same user.
67    #[facet(rename = "user")]
68    User,
69    /// Other repositories of the same organization.
70    #[facet(rename = "organization")]
71    Organization,
72}
73
74/// Which fork pull request contributors need approval to run workflows.
75#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
76#[repr(u8)]
77pub enum ApprovalPolicy {
78    /// First-time contributors who are also new to GitHub.
79    #[facet(rename = "first_time_contributors_new_to_github")]
80    FirstTimeContributorsNewToGithub,
81    /// All first-time contributors.
82    #[facet(rename = "first_time_contributors")]
83    FirstTimeContributors,
84    /// All external contributors.
85    #[facet(rename = "all_external_contributors")]
86    AllExternalContributors,
87}
88
89/// Whether Actions runs and which actions may run.
90#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
91#[facet(deny_unknown_fields)]
92pub struct Permissions {
93    /// Whether Actions is enabled for the repository.
94    pub enabled: bool,
95    /// Which actions and reusable workflows may run.
96    pub allowed_actions: ActionScope,
97    /// Whether actions must be pinned to a full commit SHA.
98    pub sha_pinning_required: bool,
99}
100
101/// The allow list used when only selected actions may run.
102#[derive(Clone, Debug, Eq, Facet, PartialEq)]
103#[facet(deny_unknown_fields)]
104pub struct AllowList {
105    /// Whether actions created by GitHub are allowed.
106    pub github_owned_allowed: bool,
107    /// Whether actions from verified creators are allowed.
108    pub verified_allowed: bool,
109    /// Allowed action patterns.
110    pub patterns_allowed: Vec<String>,
111}
112
113impl AllowList {
114    pub(crate) fn normalized(mut self) -> Self {
115        self.patterns_allowed.sort_unstable();
116        self.patterns_allowed.dedup();
117        self
118    }
119}
120
121/// The default token permissions of workflows.
122#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
123#[facet(deny_unknown_fields)]
124pub struct Workflow {
125    /// The permissions the workflow token has by default.
126    pub default_workflow_permissions: TokenPermissions,
127    /// Whether workflows may approve pull request reviews.
128    pub can_approve_pull_request_reviews: bool,
129}
130
131/// Which repositories may use this repository's actions.
132#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
133#[facet(deny_unknown_fields)]
134pub struct Access {
135    /// Who may use the actions and workflows of this private repository.
136    pub access_level: AccessLevel,
137}
138
139/// How long artifacts and logs are kept.
140#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
141#[facet(deny_unknown_fields)]
142pub struct ArtifactAndLogRetention {
143    /// The number of days to keep artifacts and logs.
144    pub days: NonZeroU32,
145}
146
147/// Which fork pull request contributors need approval.
148#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
149#[facet(deny_unknown_fields)]
150pub struct ForkPrContributorApproval {
151    /// The contributors who need approval.
152    pub approval_policy: ApprovalPolicy,
153}
154
155/// How workflows run for fork pull requests.
156#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
157#[facet(deny_unknown_fields)]
158#[expect(
159    clippy::struct_excessive_bools,
160    reason = "these are independent GitHub switches"
161)]
162pub struct ForkPrWorkflowsPrivateRepos {
163    /// Whether workflows run for fork pull requests.
164    pub run_workflows_from_fork_pull_requests: bool,
165    /// Whether fork pull request workflows get write tokens.
166    pub send_write_tokens_to_workflows: bool,
167    /// Whether fork pull request workflows get secrets and variables.
168    pub send_secrets_and_variables: bool,
169    /// Whether fork pull request workflows need approval to run.
170    pub require_approval_for_fork_pr_workflows: bool,
171}
172
173/// The limits of the Actions cache.
174#[derive(Clone, Copy, Debug, Eq, Facet, PartialEq)]
175#[facet(deny_unknown_fields)]
176pub struct Cache {
177    /// The number of days a cache entry is kept.
178    pub max_cache_retention_days: NonZeroU32,
179    /// The cache size limit in gigabytes.
180    pub max_cache_size_gb: NonZeroU32,
181}
182
183/// How the OIDC subject claim is built.
184#[derive(Clone, Debug, Eq, Facet, PartialEq)]
185#[facet(deny_unknown_fields)]
186pub struct OidcSubject {
187    /// Whether the default subject claim is used.
188    pub use_default: bool,
189    /// The claim keys of a custom subject, in order.
190    pub include_claim_keys: Vec<String>,
191    /// Whether the subject uses immutable repository and owner IDs.
192    pub use_immutable_subject: bool,
193}