1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
4pub struct PermissionRequirement {
5 pub resource: &'static str,
6 pub operation: &'static str,
7}
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(tag = "state", rename_all = "kebab-case", deny_unknown_fields)]
11pub enum GitHubRemoteExpectation {
12 Absent,
13 Exact { commit_sha256: String },
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(tag = "type", rename_all = "kebab-case", deny_unknown_fields)]
18pub enum GitHubAction {
19 ObserveRepositoryMetadata,
20 ListIssues {
21 maximum_items: u16,
22 },
23 ListPullRequests {
24 maximum_items: u16,
25 },
26 ListReleases {
27 maximum_items: u16,
28 },
29 ListWorkflowRuns {
30 maximum_items: u16,
31 },
32 ListWorkflowArtifacts {
33 workflow_run_id: String,
34 maximum_items: u16,
35 },
36 DownloadWorkflowArtifact {
37 workflow_run_id: String,
38 artifact_id: String,
39 expected_digest_sha256: Option<String>,
40 },
41 CreatePrivateRepository {
42 default_branch: String,
43 },
44 PushRepositorySnapshot {
45 snapshot_ref: String,
46 snapshot_digest_sha256: String,
47 expected_remote: GitHubRemoteExpectation,
48 },
49 DeleteRepository {
50 expected_repository_id: String,
51 backup_digest_sha256: String,
52 },
53 CreateIssue {
54 title: String,
55 body_artifact_ref: String,
56 },
57 CreatePullRequest {
58 base: String,
59 head: String,
60 title: String,
61 body_artifact_ref: String,
62 },
63 DispatchWorkflow {
64 workflow_ref: String,
65 git_ref: String,
66 inputs_artifact_ref: Option<String>,
67 },
68}
69
70impl GitHubAction {
71 #[must_use]
72 pub const fn required_permission(&self) -> PermissionRequirement {
73 use GitHubAction::*;
74 match self {
75 ObserveRepositoryMetadata => {
76 permission("github-repository-metadata", "inspect-metadata")
77 }
78 ListIssues { .. } => permission("github-issue-observation", "list-records"),
79 ListPullRequests { .. } => {
80 permission("github-pull-request-observation", "list-records")
81 }
82 ListReleases { .. } => permission("github-release-observation", "list-records"),
83 ListWorkflowRuns { .. } => {
84 permission("github-workflow-run-observation", "list-records")
85 }
86 ListWorkflowArtifacts { .. } => {
87 permission("github-actions-artifact-observation", "list-records")
88 }
89 DownloadWorkflowArtifact { .. } => {
90 permission("github-actions-artifact", "download-artifact")
91 }
92 CreatePrivateRepository { .. } => {
93 permission("github-private-repository", "create-private-resource")
94 }
95 PushRepositorySnapshot { .. } => {
96 permission("github-repository-content", "publish-artifact")
97 }
98 DeleteRepository { .. } => {
99 permission("github-repository-administration", "delete-resource")
100 }
101 CreateIssue { .. } => permission("github-issue-creation", "create-work-item"),
102 CreatePullRequest { .. } => {
103 permission("github-pull-request-creation", "create-review-request")
104 }
105 DispatchWorkflow { .. } => permission("github-workflow", "dispatch-operation"),
106 }
107 }
108}
109
110const fn permission(resource: &'static str, operation: &'static str) -> PermissionRequirement {
111 PermissionRequirement {
112 resource,
113 operation,
114 }
115}
116
117impl GitHubAction {
118 pub fn kind(&self) -> &'static str {
119 match self {
120 Self::ObserveRepositoryMetadata => "observe-repository-metadata",
121 Self::ListIssues { .. } => "list-issues",
122 Self::ListPullRequests { .. } => "list-pull-requests",
123 Self::ListReleases { .. } => "list-releases",
124 Self::ListWorkflowRuns { .. } => "list-workflow-runs",
125 Self::ListWorkflowArtifacts { .. } => "list-workflow-artifacts",
126 Self::DownloadWorkflowArtifact { .. } => "download-workflow-artifact",
127 Self::CreatePrivateRepository { .. } => "create-private-repository",
128 Self::PushRepositorySnapshot { .. } => "push-repository-snapshot",
129 Self::DeleteRepository { .. } => "delete-repository",
130 Self::CreateIssue { .. } => "create-issue",
131 Self::CreatePullRequest { .. } => "create-pull-request",
132 Self::DispatchWorkflow { .. } => "dispatch-workflow",
133 }
134 }
135 pub fn is_read_only(&self) -> bool {
136 matches!(
137 self,
138 Self::ObserveRepositoryMetadata
139 | Self::ListIssues { .. }
140 | Self::ListPullRequests { .. }
141 | Self::ListReleases { .. }
142 | Self::ListWorkflowRuns { .. }
143 | Self::ListWorkflowArtifacts { .. }
144 | Self::DownloadWorkflowArtifact { .. }
145 )
146 }
147}