Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ spec:
{{- if .Values.leaderElection.enabled }}
- --leader-elect
{{- end }}
- {{ printf "--drift-detection-interval=%s" .Values.reconciliation.driftDetectionInterval | quote }}
{{- if .Values.metrics.enabled }}
- --metrics-bind-address=:{{ .Values.metrics.port }}
{{- if not .Values.metrics.secure }}
Expand Down
16 changes: 16 additions & 0 deletions charts/github-platform-operator/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"serviceAccount",
"rbac",
"leaderElection",
"reconciliation",
"metrics",
"networkPolicy",
"resources"
Expand Down Expand Up @@ -124,6 +125,21 @@
}
}
},
"reconciliation": {
"description": "Periodic reconciliation configuration for detecting drift in GitHub.",
"type": "object",
"additionalProperties": false,
"required": [
"driftDetectionInterval"
],
"properties": {
"driftDetectionInterval": {
"description": "How often controllers poll GitHub for external drift. Watched Kubernetes events still reconcile immediately. The manager accepts Go duration syntax and enforces a range of 1m to 24h.",
"type": "string",
"minLength": 1
}
}
},
"metrics": {
"description": "Controller metrics endpoint configuration.",
"type": "object",
Expand Down
3 changes: 3 additions & 0 deletions charts/github-platform-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ rbac:
leaderElection:
enabled: true

reconciliation:
driftDetectionInterval: 5m

metrics:
enabled: true
secure: true
Expand Down
126 changes: 76 additions & 50 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"flag"
"os"
"path/filepath"
"time"

// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
Expand Down Expand Up @@ -64,6 +65,7 @@ func main() {
var probeAddr string
var secureMetrics bool
var enableHTTP2 bool
var driftDetectionInterval time.Duration
var tlsOpts []func(*tls.Config)
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
Expand All @@ -82,6 +84,13 @@ func main() {
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
flag.BoolVar(&enableHTTP2, "enable-http2", false,
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
flag.DurationVar(
&driftDetectionInterval,
"drift-detection-interval",
controller.DefaultDriftDetectionInterval,
"How often controllers poll GitHub to detect external configuration drift. "+
"Watched Kubernetes events still trigger reconciliation immediately.",
)
opts := zap.Options{
Development: true,
}
Expand All @@ -90,6 +99,13 @@ func main() {

ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

if err := controller.ValidateDriftDetectionInterval(driftDetectionInterval); err != nil {
setupLog.Error(err, "invalid drift detection interval")
os.Exit(1)
}

setupLog.Info("configured GitHub drift detection", "interval", driftDetectionInterval)

// if the enable-http2 flag is false (the default), http/2 should be disabled
// due to its vulnerabilities. More specifically, disabling http/2 will
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
Expand Down Expand Up @@ -219,110 +235,120 @@ func main() {
}

if err := (&controller.GitHubOrganizationMemberReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubOrganizationMember")
os.Exit(1)
}

if err := (&controller.GitHubTeamReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubTeam")
os.Exit(1)
}

if err := (&controller.GitHubTeamMembershipReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubTeamMembership")
os.Exit(1)
}

if err := (&controller.GitHubRepositoryReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubRepository")
os.Exit(1)
}

if err := (&controller.GitHubRepositoryRulesetReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubRepositoryRuleset")
os.Exit(1)
}

if err := (&controller.GitHubRepositoryTeamAccessReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubRepositoryTeamAccess")
os.Exit(1)
}

if err := (&controller.GitHubRepositoryCollaboratorReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubRepositoryCollaborator")
os.Exit(1)
}

if err := (&controller.GitHubEnvironmentReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubEnvironment")
os.Exit(1)
}

if err := (&controller.GitHubActionsSecretReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubActionsSecret")
os.Exit(1)
}

if err := (&controller.GitHubActionsVariableReconciler{
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
Client: mgr.GetClient(),
APIReader: mgr.GetAPIReader(),
Scheme: mgr.GetScheme(),
GitHubClientFactory: githubClientFactory,
GitHubTokenProvider: githubTokenProvider,
DriftDetectionInterval: driftDetectionInterval,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "GitHubActionsVariable")
os.Exit(1)
Expand Down
11 changes: 6 additions & 5 deletions internal/controller/githubactionssecret_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@ const (
// GitHubActionsSecretReconciler reconciles GitHubActionsSecret resources.
type GitHubActionsSecretReconciler struct {
client.Client
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.ActionsClientFactory
GitHubTokenProvider githubclient.TokenProvider
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.ActionsClientFactory
GitHubTokenProvider githubclient.TokenProvider
DriftDetectionInterval time.Duration
}

// +kubebuilder:rbac:groups=github.k8sready.com,resources=githubactionssecrets,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -167,7 +168,7 @@ func (r *GitHubActionsSecretReconciler) Reconcile(
); err != nil {
return ctrl.Result{}, fmt.Errorf("update GitHubActionsSecret status: %w", err)
}
return ctrl.Result{RequeueAfter: actionsRequeueInterval}, nil
return driftDetectionResult(r.DriftDetectionInterval), nil
}

func (r *GitHubActionsSecretReconciler) secretNeedsSynchronization(
Expand Down
12 changes: 7 additions & 5 deletions internal/controller/githubactionsvariable_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
"time"

corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
Expand All @@ -44,10 +45,11 @@ const (
// GitHubActionsVariableReconciler reconciles GitHubActionsVariable resources.
type GitHubActionsVariableReconciler struct {
client.Client
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.ActionsClientFactory
GitHubTokenProvider githubclient.TokenProvider
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.ActionsClientFactory
GitHubTokenProvider githubclient.TokenProvider
DriftDetectionInterval time.Duration
}

// +kubebuilder:rbac:groups=github.k8sready.com,resources=githubactionsvariables,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -157,7 +159,7 @@ func (r *GitHubActionsVariableReconciler) Reconcile(
); err != nil {
return ctrl.Result{}, fmt.Errorf("update GitHubActionsVariable status: %w", err)
}
return ctrl.Result{RequeueAfter: actionsRequeueInterval}, nil
return driftDetectionResult(r.DriftDetectionInterval), nil
}

func variableNeedsUpdate(
Expand Down
14 changes: 7 additions & 7 deletions internal/controller/githubenvironment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ import (

const (
githubEnvironmentFinalizer = "github.k8sready.com/environment-finalizer"
actionsRequeueInterval = 5 * time.Minute
)

// GitHubEnvironmentReconciler reconciles GitHubEnvironment resources.
type GitHubEnvironmentReconciler struct {
client.Client
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.ActionsClientFactory
GitHubTokenProvider githubclient.TokenProvider
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.ActionsClientFactory
GitHubTokenProvider githubclient.TokenProvider
DriftDetectionInterval time.Duration
}

// +kubebuilder:rbac:groups=github.k8sready.com,resources=githubenvironments,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -134,7 +134,7 @@ func (r *GitHubEnvironmentReconciler) Reconcile(
return ctrl.Result{}, fmt.Errorf("update GitHubEnvironment status: %w", err)
}

return ctrl.Result{RequeueAfter: actionsRequeueInterval}, nil
return driftDetectionResult(r.DriftDetectionInterval), nil
}

func (r *GitHubEnvironmentReconciler) reconcileDelete(
Expand Down Expand Up @@ -167,7 +167,7 @@ func (r *GitHubEnvironmentReconciler) reconcileDelete(
); err != nil {
return ctrl.Result{}, fmt.Errorf("update GitHubEnvironment deletion status: %w", err)
}
return ctrl.Result{RequeueAfter: actionsRequeueInterval}, nil
return driftDetectionResult(r.DriftDetectionInterval), nil
}

resolved, err := resolveRepositoryActionsTarget(
Expand Down
12 changes: 7 additions & 5 deletions internal/controller/githuborganizationmember_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
"time"

apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta"
Expand All @@ -39,10 +40,11 @@ const githubOrganizationMemberFinalizer = "github.k8sready.com/organization-memb
// GitHubOrganizationMemberReconciler reconciles direct organization membership.
type GitHubOrganizationMemberReconciler struct {
client.Client
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.OrganizationClientFactory
GitHubTokenProvider githubclient.TokenProvider
APIReader client.Reader
Scheme *runtime.Scheme
GitHubClientFactory githubclient.OrganizationClientFactory
GitHubTokenProvider githubclient.TokenProvider
DriftDetectionInterval time.Duration
}

// +kubebuilder:rbac:groups=github.k8sready.com,resources=githuborganizationmembers,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -145,7 +147,7 @@ func (r *GitHubOrganizationMemberReconciler) finish(
if err := r.setReadyCondition(ctx, resource, resolved, membership, status, reason, message); err != nil {
return ctrl.Result{}, fmt.Errorf("update GitHubOrganizationMember status: %w", err)
}
return ctrl.Result{RequeueAfter: organizationRequeueAfter}, nil
return driftDetectionResult(r.DriftDetectionInterval), nil
}

func (r *GitHubOrganizationMemberReconciler) reconcileDelete(
Expand Down
Loading