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
45 changes: 45 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: E2E Tests

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
e2e:
name: E2E Tests
runs-on: ubuntu-latest

env:
KIND_CLUSTER: e2e

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup go
uses: actions/setup-go@v5

- name: Setup ko
uses: ko-build/setup-ko@v0.9

- name: Setup helm
uses: azure/setup-helm@v4

- name: Setup kind
uses: helm/kind-action@v1
with:
cluster_name: ${{ env.KIND_CLUSTER }}

- name: Run E2E tests
env:
GTM_APP_ID: ${{ vars.GTM_APP_ID }}
GTM_INSTALLATION_ID: ${{ vars.GTM_INSTALLATION_ID }}
GTM_PROVIDER: file
GTM_KEY: ${{ secrets.GTM_KEY }}
run: |
make test-e2e
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
bin/*
Dockerfile.cross

# Secrets
test/e2e/values.yaml

# Test binary, built with `go test -c`
*.test

Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ cleanup-test-e2e:

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e
test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind.
KIND_CLUSTER=$(KIND_CLUSTER) go test ./test/e2e/ -v -ginkgo.v
test-e2e: fmt vet setup-test-e2e ## Run the e2e tests. Expected an isolated environment using Kind.
KUBE_CONTEXT=kind-$(KIND_CLUSTER) go test ./test/e2e/ -tags=e2e -v -ginkgo.v
$(MAKE) cleanup-test-e2e

.PHONY: lint
Expand Down Expand Up @@ -213,7 +213,7 @@ build-installer: manifests generate kustomize ## Generate a consolidated YAML wi
.PHONY: ko-build
ko-build: ## Build the manager image using ko.
KO_DOCKER_REPO=$(IMAGE_TAG_BASE) \
ko build --bare --platform=$(PLATFORMS) --image-label org.opencontainers.image.source=$(IMAGE_SOURCE) --tags "latest,$(VERSION)" --push ./cmd/manager
$(KO) build --bare --platform=$(PLATFORMS) --image-label org.opencontainers.image.source=$(IMAGE_SOURCE) --tags "latest,$(VERSION)" --push ./cmd/manager


##@ Deployment
Expand Down Expand Up @@ -249,6 +249,7 @@ $(LOCALBIN):
## Tool Binaries
KUBECTL ?= kubectl
KIND ?= kind
KO ?= ko
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[![CodeQL](https://github.com/isometry/github-token-manager/actions/workflows/codeql.yaml/badge.svg)](https://github.com/isometry/github-token-manager/actions/workflows/codeql.yaml)
[![E2E](https://github.com/isometry/github-token-manager/actions/workflows/e2e.yaml/badge.svg)](https://github.com/isometry/github-token-manager/actions/workflows/e2e.yaml)
[![Publish](https://github.com/isometry/github-token-manager/actions/workflows/publish.yaml/badge.svg)](https://github.com/isometry/github-token-manager/actions/workflows/publish.yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/isometry/github-token-manager)](https://goreportcard.com/report/github.com/isometry/github-token-manager)

Expand Down Expand Up @@ -158,8 +159,8 @@ More information can be found via the [Kubebuilder Documentation](https://book.k
make ko-build IMG=<some-registry>/github-token-manager:tag
```

**NOTE:** This image ought to be published in the personal registry you specified.
And it is required to have access to pull the image from the working environment.
**NOTE:** This image ought to be published in the personal registry you specified.
And it is required to have access to pull the image from the working environment.
Make sure you have the proper permission to the registry if the above commands don’t work.

#### Install the CRDs into the cluster:
Expand All @@ -174,7 +175,7 @@ make install
make deploy IMG=<some-registry>/github-token-manager:tag
```

> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin
> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin
privileges or be logged in as admin.

### To Uninstall
Expand Down
4 changes: 2 additions & 2 deletions api/v1/conditions.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package v1

const (
// ConditionTypeAvailable represents the status of the Secret reconciliation
ConditionTypeAvailable = "Available"
// ConditionTypeReady is used to signal whether a reconciliation has completed successfully.
ConditionTypeReady = "Ready"
)
8 changes: 3 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/isometry/github-token-manager

go 1.24.0

toolchain go1.24.5
go 1.24.5

require (
github.com/go-logr/logr v1.4.3
Expand All @@ -12,10 +10,12 @@ require (
github.com/onsi/gomega v1.37.0
github.com/spf13/viper v1.20.1
go.uber.org/automaxprocs v1.6.0
golang.org/x/oauth2 v0.30.0
k8s.io/api v0.33.2
k8s.io/apimachinery v0.33.2
k8s.io/client-go v0.33.2
sigs.k8s.io/controller-runtime v0.21.0
sigs.k8s.io/yaml v1.4.0
)

require (
Expand Down Expand Up @@ -127,7 +127,6 @@ require (
golang.org/x/crypto v0.40.0 // indirect
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect
golang.org/x/net v0.42.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
golang.org/x/term v0.33.0 // indirect
Expand All @@ -154,5 +153,4 @@ require (
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
14 changes: 7 additions & 7 deletions internal/controller/clustertoken_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ type ClusterTokenReconciler struct {
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.3/pkg/reconcile
func (r *ClusterTokenReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
log := log.FromContext(ctx)
logger := log.FromContext(ctx)

if app == nil {
app, err = ghapp.NewGHApp(ctx)
if err != nil {
log.Error(err, "failed to load GitHub App credentials")
logger.Error(err, "failed to load GitHub App credentials")
return ctrl.Result{RequeueAfter: time.Minute}, err
}
}
Expand All @@ -70,26 +70,26 @@ func (r *ClusterTokenReconciler) Reconcile(ctx context.Context, req ctrl.Request
options := []tm.Option{
tm.WithReconciler(r),
tm.WithGHApp(app),
tm.WithLogger(log),
tm.WithLogger(logger),
}

tokenSecret, err := tm.NewTokenSecret(ctx, req.NamespacedName, token, options...)
if err != nil {
log.Error(err, "failed to create ClusterToken reconciler")
logger.Error(err, "failed to create ClusterToken reconciler")
return ctrl.Result{}, err
}

if tokenSecret == nil {
log.Info("ClusterToken not found, skipping reconciliation")
logger.Info("ClusterToken not found, skipping reconciliation")
return ctrl.Result{}, nil
}

result, err = tokenSecret.Reconcile()
if err != nil {
log.Error(err, "failed to reconcile ClusterToken")
logger.Error(err, "failed to reconcile ClusterToken")
return result, err
}
log.Info("reconciled", "requeueAfter", result.RequeueAfter)
logger.Info("reconciled", "requeueAfter", result.RequeueAfter)
return result, nil
}

Expand Down
14 changes: 7 additions & 7 deletions internal/controller/token_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ type TokenReconciler struct {
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.3/pkg/reconcile
func (r *TokenReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) {
log := log.FromContext(ctx)
logger := log.FromContext(ctx)

if app == nil {
app, err = ghapp.NewGHApp(ctx)
if err != nil {
log.Error(err, "failed to load GitHub App credentials")
logger.Error(err, "failed to load GitHub App credentials")
return ctrl.Result{RequeueAfter: time.Minute}, err
}
}
Expand All @@ -69,26 +69,26 @@ func (r *TokenReconciler) Reconcile(ctx context.Context, req ctrl.Request) (resu
options := []tm.Option{
tm.WithReconciler(r),
tm.WithGHApp(app),
tm.WithLogger(log),
tm.WithLogger(logger),
}

tokenSecret, err := tm.NewTokenSecret(ctx, req.NamespacedName, token, options...)
if err != nil {
log.Error(err, "failed to create Token reconciler")
logger.Error(err, "failed to create Token reconciler")
return ctrl.Result{}, err
}

if tokenSecret == nil {
log.Info("Token not found, skipping reconciliation")
logger.Info("Token not found, skipping reconciliation")
return ctrl.Result{}, nil
}

result, err = tokenSecret.Reconcile()
if err != nil {
log.Error(err, "failed to reconcile Token")
logger.Error(err, "failed to reconcile Token")
return result, err
}
log.Info("reconciled", "requeueAfter", result.RequeueAfter)
logger.Info("reconciled", "requeueAfter", result.RequeueAfter)
return result, nil
}

Expand Down
4 changes: 2 additions & 2 deletions internal/ghapp/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (c *OperatorConfig) GetKey() string {
const TokenValidity = time.Hour

func LoadConfig(ctx context.Context) (*OperatorConfig, error) {
log := log.FromContext(ctx)
logger := log.FromContext(ctx)

viper.AutomaticEnv()
viper.SetEnvPrefix("GTM")
Expand All @@ -60,7 +60,7 @@ func LoadConfig(ctx context.Context) (*OperatorConfig, error) {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return nil, fmt.Errorf("error reading configuration file: %w", err)
} else {
log.Info("no configuration file found, continuing with environment variables only")
logger.Info("no configuration file found, continuing with environment variables only")
}
}

Expand Down
4 changes: 2 additions & 2 deletions internal/ghapp/ghapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import (
)

func NewGHApp(ctx context.Context) (ghait.GHAIT, error) {
log := log.FromContext(ctx)
logger := log.FromContext(ctx)

cfg, err := LoadConfig(ctx)
if err != nil {
return nil, fmt.Errorf("configuration: %w", err)
}

log.Info("loaded configuration", "config", cfg)
logger.Info("loaded configuration", "config", cfg)

ghapp, err := ghait.NewGHAIT(ctx, cfg)
if err != nil {
Expand Down
14 changes: 7 additions & 7 deletions internal/tokenmanager/token_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ func WithReconciler(reconciler tokenReconciler) Option {
}
}

func WithGHApp(ghait ghait.GHAIT) Option {
func WithGHApp(g ghait.GHAIT) Option {
return func(s *tokenSecret) {
s.ghait = ghait
s.ghait = g
}
}

Expand Down Expand Up @@ -83,7 +83,7 @@ func NewTokenSecret(ctx context.Context, key types.NamespacedName, owner tokenMa
s.log.Info("initializing token status conditions")

condition := metav1.Condition{
Type: githubv1.ConditionTypeAvailable,
Type: githubv1.ConditionTypeReady,
Status: metav1.ConditionUnknown,
Reason: "Reconciling",
Message: "Starting reconciliation",
Expand Down Expand Up @@ -152,7 +152,7 @@ func (s *tokenSecret) Reconcile() (result reconcile.Result, err error) {
// Secret was found, so update it
if !metav1.IsControlledBy(secret, s.owner) {
condition := metav1.Condition{
Type: githubv1.ConditionTypeAvailable,
Type: githubv1.ConditionTypeReady,
Status: metav1.ConditionFalse,
Reason: "Failed",
Message: "Secret already exists",
Expand Down Expand Up @@ -217,7 +217,7 @@ func (s *tokenSecret) CreateSecret() error {
}

condition := metav1.Condition{
Type: githubv1.ConditionTypeAvailable,
Type: githubv1.ConditionTypeReady,
Status: metav1.ConditionFalse,
Reason: "Creating",
Message: "Creating Secret",
Expand Down Expand Up @@ -263,7 +263,7 @@ func (s *tokenSecret) UpdateSecret() error {
s.Data = s.SecretData(installationToken.GetToken())

condition := metav1.Condition{
Type: githubv1.ConditionTypeAvailable,
Type: githubv1.ConditionTypeReady,
Status: metav1.ConditionUnknown,
Reason: "Updating",
Message: "Updating Secret",
Expand Down Expand Up @@ -300,7 +300,7 @@ func (s *tokenSecret) DeleteSecret(key types.NamespacedName) error {
log := s.log.WithValues("func", "DeleteSecret")

condition := metav1.Condition{
Type: githubv1.ConditionTypeAvailable,
Type: githubv1.ConditionTypeReady,
Status: metav1.ConditionFalse,
Reason: "Reconciling",
Message: "Deleting old Secret",
Expand Down
Loading
Loading