- Kubernetes 1.30 or newer
- Helm 3 with OCI registry support
kubectl- either a GitHub token or an installed GitHub App with access to the target organization and the resources that the operator will manage
Use a disposable repository or organization while evaluating destructive deletion policies.
helm upgrade --install github-platform-operator \
oci://ghcr.io/pierinho13/charts/github-platform-operator \
--version 0.1.0 \
--namespace github-platform-operator-system \
--create-namespaceCheck the installation:
kubectl rollout status \
deployment/github-platform-operator \
--namespace github-platform-operator-system
kubectl get crd | grep github.k8sready.comThe Helm chart installs these resources:
githubproviderconfigs.github.k8sready.com
githuborganizationmembers.github.k8sready.com
githubteams.github.k8sready.com
githubteammemberships.github.k8sready.com
githubrepositories.github.k8sready.com
githubrepositoryrulesets.github.k8sready.com
githubrepositoryteamaccesses.github.k8sready.com
githubrepositorycollaborators.github.k8sready.com
githubenvironments.github.k8sready.com
githubactionssecrets.github.k8sready.com
githubactionsvariables.github.k8sready.com
A provider must configure exactly one authentication method:
- an existing GitHub token through
credentials.secretRef - a GitHub App installation through
credentials.githubApp
Create a Kubernetes Secret containing the GitHub token:
kubectl create secret generic github-credentials \
--namespace default \
--from-literal=token="${GITHUB_TOKEN}"Create a cluster-scoped GitHubProviderConfig:
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubProviderConfig
metadata:
name: default
spec:
organization: k8sready
apiURL: https://api.github.com
credentials:
secretRef:
namespace: default
name: github-credentials
key: tokenkubectl apply -f provider.yaml
kubectl get ghprovider defaultCreate a Secret from the PEM private key downloaded for the GitHub App:
kubectl create secret generic github-app-credentials \
--namespace github-platform-operator-system \
--from-file=private-key.pem=/path/to/github-app.private-key.pemCreate the provider:
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubProviderConfig
metadata:
name: github-app
spec:
organization: k8sready
apiURL: https://api.github.com
credentials:
githubApp:
appID: Iv1.REPLACE_ME
installationID: 12345678
privateKeySecretRef:
namespace: github-platform-operator-system
name: github-app-credentials
key: private-key.pemappID accepts the GitHub App client ID or numeric app ID. The operator creates
short-lived installation access tokens and refreshes them before expiration.
PKCS#1 and PKCS#8 RSA private keys are supported.
For GitHub Enterprise Server, set spec.apiURL to the REST API base URL, for
example:
apiURL: https://github.example.com/api/v3Organization membership and team management require GitHub organization
Members: write permission.
Create a team, ensure a user belongs to the organization and assign that user to the team:
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubOrganizationMember
metadata:
name: octocat
namespace: default
spec:
providerConfigRef: default
username: octocat
role: member
deletionPolicy: Orphan
---
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubTeam
metadata:
name: platform
namespace: default
spec:
providerConfigRef: default
name: Platform
privacy: closed
deletionPolicy: Orphan
---
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubTeamMembership
metadata:
name: platform-octocat
namespace: default
spec:
teamRef:
name: platform
username: octocat
role: member
deletionPolicy: Orphankubectl apply -f organization-access.yaml
kubectl get ghorgmember,ghteam,ghteammember -AA new organization or team member can remain pending until the GitHub invitation is accepted.
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubRepository
metadata:
name: example-repository
namespace: default
spec:
providerConfigRef: default
name: example-repository
visibility: private
deletionPolicy: Orphankubectl apply -f repository.yaml
kubectl wait \
--for=condition=Ready \
ghrepo/example-repository \
--timeout=90sIf the repository already exists in the provider organization, the operator adopts it. Optional fields that are omitted remain unmanaged and retain their existing GitHub values.
Inspect the observed state:
kubectl get ghrepo example-repository
kubectl get ghrepo example-repository -o yamlCreate a disabled ruleset first so its payload and status can be inspected without enforcing it immediately:
apiVersion: github.k8sready.com/v1alpha1
kind: GitHubRepositoryRuleset
metadata:
name: example-repository-protect-main
namespace: default
spec:
repositoryRef:
name: example-repository
name: protect-main
target: branch
enforcement: disabled
bypassActors:
- actorType: Team
teamSlug: platform
bypassMode: always
conditions:
refName:
include:
- "~DEFAULT_BRANCH"
exclude: []
rules:
- type: deletion
- type: non_fast_forward
deletionPolicy: Orphankubectl apply -f ruleset.yaml
kubectl wait \
--for=condition=Ready \
ghruleset/example-repository-protect-main \
--timeout=90s
kubectl get ghruleset example-repository-protect-main -o yamlAfter validating the observed state, activate it:
kubectl patch ghruleset example-repository-protect-main \
--type merge \
-p '{"spec":{"enforcement":"active"}}'The operator resolves team slugs and usernames to numeric GitHub actor IDs. A
GitHub App or fine-grained token using teamSlug needs organization
Members: read permission in addition to the permissions required to manage
rulesets. Classic personal access tokens need read:org. Existing actorID manifests remain valid.
GitHub may return 403 when the repository or organization plan does not
support rulesets. Testing against a disposable repository is recommended.
- Manage organization members and teams.
- Review the complete
GitHubRepositoryRulesetAPI. - Add team or collaborator repository access.
- Create an environment.
- Synchronize Actions secrets and variables.
- Review deletion policies and upgrades.