zixcel-github 0.1.1

Policy-neutral GitHub API wrapper boundary for Zixcel
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub struct PermissionRequirement {
    pub resource: &'static str,
    pub operation: &'static str,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "state", rename_all = "kebab-case", deny_unknown_fields)]
pub enum GitHubRemoteExpectation {
    Absent,
    Exact { commit_sha256: String },
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "kebab-case", deny_unknown_fields)]
pub enum GitHubAction {
    ObserveRepositoryMetadata,
    ListIssues {
        maximum_items: u16,
    },
    ListPullRequests {
        maximum_items: u16,
    },
    ListReleases {
        maximum_items: u16,
    },
    ListWorkflowRuns {
        maximum_items: u16,
    },
    ListWorkflowArtifacts {
        workflow_run_id: String,
        maximum_items: u16,
    },
    DownloadWorkflowArtifact {
        workflow_run_id: String,
        artifact_id: String,
        expected_digest_sha256: Option<String>,
    },
    CreatePrivateRepository {
        default_branch: String,
    },
    PushRepositorySnapshot {
        snapshot_ref: String,
        snapshot_digest_sha256: String,
        expected_remote: GitHubRemoteExpectation,
    },
    DeleteRepository {
        expected_repository_id: String,
        backup_digest_sha256: String,
    },
    CreateIssue {
        title: String,
        body_artifact_ref: String,
    },
    CreatePullRequest {
        base: String,
        head: String,
        title: String,
        body_artifact_ref: String,
    },
    DispatchWorkflow {
        workflow_ref: String,
        git_ref: String,
        inputs_artifact_ref: Option<String>,
    },
}

impl GitHubAction {
    #[must_use]
    pub const fn required_permission(&self) -> PermissionRequirement {
        use GitHubAction::*;
        match self {
            ObserveRepositoryMetadata => {
                permission("github-repository-metadata", "inspect-metadata")
            }
            ListIssues { .. } => permission("github-issue-observation", "list-records"),
            ListPullRequests { .. } => {
                permission("github-pull-request-observation", "list-records")
            }
            ListReleases { .. } => permission("github-release-observation", "list-records"),
            ListWorkflowRuns { .. } => {
                permission("github-workflow-run-observation", "list-records")
            }
            ListWorkflowArtifacts { .. } => {
                permission("github-actions-artifact-observation", "list-records")
            }
            DownloadWorkflowArtifact { .. } => {
                permission("github-actions-artifact", "download-artifact")
            }
            CreatePrivateRepository { .. } => {
                permission("github-private-repository", "create-private-resource")
            }
            PushRepositorySnapshot { .. } => {
                permission("github-repository-content", "publish-artifact")
            }
            DeleteRepository { .. } => {
                permission("github-repository-administration", "delete-resource")
            }
            CreateIssue { .. } => permission("github-issue-creation", "create-work-item"),
            CreatePullRequest { .. } => {
                permission("github-pull-request-creation", "create-review-request")
            }
            DispatchWorkflow { .. } => permission("github-workflow", "dispatch-operation"),
        }
    }
}

const fn permission(resource: &'static str, operation: &'static str) -> PermissionRequirement {
    PermissionRequirement {
        resource,
        operation,
    }
}

impl GitHubAction {
    pub fn kind(&self) -> &'static str {
        match self {
            Self::ObserveRepositoryMetadata => "observe-repository-metadata",
            Self::ListIssues { .. } => "list-issues",
            Self::ListPullRequests { .. } => "list-pull-requests",
            Self::ListReleases { .. } => "list-releases",
            Self::ListWorkflowRuns { .. } => "list-workflow-runs",
            Self::ListWorkflowArtifacts { .. } => "list-workflow-artifacts",
            Self::DownloadWorkflowArtifact { .. } => "download-workflow-artifact",
            Self::CreatePrivateRepository { .. } => "create-private-repository",
            Self::PushRepositorySnapshot { .. } => "push-repository-snapshot",
            Self::DeleteRepository { .. } => "delete-repository",
            Self::CreateIssue { .. } => "create-issue",
            Self::CreatePullRequest { .. } => "create-pull-request",
            Self::DispatchWorkflow { .. } => "dispatch-workflow",
        }
    }
    pub fn is_read_only(&self) -> bool {
        matches!(
            self,
            Self::ObserveRepositoryMetadata
                | Self::ListIssues { .. }
                | Self::ListPullRequests { .. }
                | Self::ListReleases { .. }
                | Self::ListWorkflowRuns { .. }
                | Self::ListWorkflowArtifacts { .. }
                | Self::DownloadWorkflowArtifact { .. }
        )
    }
}