diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b2fd88..8e7e50b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,4 +45,4 @@ jobs: run: go install sigs.k8s.io/controller-runtime/tools/setup-envtest@4dbfa5c66aa24a35003c41507385c2a91e94d404 # release-0.23 - name: Test run: | - make test + make integration-test diff --git a/Makefile b/Makefile index 0bbc5c1..c520f37 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,10 @@ fmt: go fmt ./... test: - KUBEBUILDER_ASSETS=$$(setup-envtest use -p path) go test ./... + go test ./... + +integration-test: + KUBEBUILDER_ASSETS=$$(setup-envtest use -p path) go test -tags integration_test ./... test-short: go test -short ./... diff --git a/cmd/deployment-tracker/main.go b/cmd/deployment-tracker/main.go index 441d42c..c38481a 100644 --- a/cmd/deployment-tracker/main.go +++ b/cmd/deployment-tracker/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "encoding/base64" "flag" "fmt" "log" @@ -67,6 +68,16 @@ func main() { opts := slog.HandlerOptions{Level: slog.LevelInfo} slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &opts))) + var ghAppPrivateKey []byte + if b64Key := os.Getenv("GH_APP_PRIVATE_KEY"); b64Key != "" { + var err error + ghAppPrivateKey, err = base64.StdEncoding.DecodeString(b64Key) + if err != nil { + slog.Error("Failed to base64 decode GH_APP_PRIVATE_KEY", "error", err) + os.Exit(1) + } + } + var cntrlCfg = controller.Config{ Template: getEnvOrDefault("DN_TEMPLATE", defaultTemplate), LogicalEnvironment: os.Getenv("LOGICAL_ENVIRONMENT"), @@ -76,10 +87,16 @@ func main() { BaseURL: getEnvOrDefault("BASE_URL", "api.github.com"), GHAppID: getEnvOrDefault("GH_APP_ID", ""), GHInstallID: getEnvOrDefault("GH_INSTALL_ID", ""), - GHAppPrivateKey: getEnvOrDefault("GH_APP_PRIV_KEY", ""), + GHAppPrivateKey: ghAppPrivateKey, + GHAppPrivateKeyPath: getEnvOrDefault("GH_APP_PRIV_KEY_PATH", ""), Organization: os.Getenv("GITHUB_ORG"), } + if len(cntrlCfg.GHAppPrivateKey) > 0 && cntrlCfg.GHAppPrivateKeyPath != "" { + slog.Error("Both GH_APP_PRIVATE_KEY and GH_APP_PRIV_KEY_PATH are set. Only one can be used.") + os.Exit(1) + } + if !controller.ValidTemplate(cntrlCfg.Template) { slog.Error("Template must contain at least one placeholder", "template", cntrlCfg.Template, diff --git a/internal/controller/config.go b/internal/controller/config.go index 73e08d0..44f484d 100644 --- a/internal/controller/config.go +++ b/internal/controller/config.go @@ -20,12 +20,15 @@ type Config struct { PhysicalEnvironment string Cluster string //nolint:gosec - APIToken string - BaseURL string - GHAppID string - GHInstallID string - GHAppPrivateKey string - Organization string + APIToken string + BaseURL string + GHAppID string + GHInstallID string + // GHAppPrivateKey must be the PEM Encoding of the + // private key + GHAppPrivateKey []byte + GHAppPrivateKeyPath string + Organization string } // ValidTemplate verifies that at least one placeholder is present diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 73c4183..3749e56 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -87,8 +87,13 @@ func New(clientset kubernetes.Interface, metadataAggregator podMetadataAggregato } if cfg.GHAppID != "" && cfg.GHInstallID != "" && - cfg.GHAppPrivateKey != "" { - clientOpts = append(clientOpts, deploymentrecord.WithGHApp(cfg.GHAppID, cfg.GHInstallID, cfg.GHAppPrivateKey)) + (len(cfg.GHAppPrivateKey) > 0 || cfg.GHAppPrivateKeyPath != "") { + clientOpts = append(clientOpts, deploymentrecord.WithGHApp( + cfg.GHAppID, + cfg.GHInstallID, + cfg.GHAppPrivateKey, + cfg.GHAppPrivateKeyPath, + )) } apiClient, err := deploymentrecord.NewClient( diff --git a/internal/controller/controller_integration_test.go b/internal/controller/controller_integration_test.go index 4be8391..3263c97 100644 --- a/internal/controller/controller_integration_test.go +++ b/internal/controller/controller_integration_test.go @@ -1,3 +1,5 @@ +//go:build integration_test + package controller import ( diff --git a/pkg/deploymentrecord/client.go b/pkg/deploymentrecord/client.go index 791d299..c335e87 100644 --- a/pkg/deploymentrecord/client.go +++ b/pkg/deploymentrecord/client.go @@ -105,8 +105,12 @@ func WithAPIToken(token string) ClientOption { // WithGHApp configures a GitHub app to use for authentication. // If provided values are invalid, this will panic. // If an API token is also set, the GitHub App will take precedence. -func WithGHApp(id, installID, pk string) ClientOption { +func WithGHApp(id, installID string, pkBytes []byte, pkPath string) ClientOption { return func(c *Client) { + if len(pkBytes) > 0 && pkPath != "" { + panic("both GitHub App private key and private key path are set") + } + pid, err := strconv.Atoi(id) if err != nil { panic(err) @@ -115,11 +119,21 @@ func WithGHApp(id, installID, pk string) ClientOption { if err != nil { panic(err) } - c.transport, err = ghinstallation.NewKeyFromFile( - http.DefaultTransport, - int64(pid), - int64(piid), - pk) + + if len(pkBytes) > 0 { + c.transport, err = ghinstallation.New( + http.DefaultTransport, + int64(pid), + int64(piid), + pkBytes) + } else { + c.transport, err = ghinstallation.NewKeyFromFile( + http.DefaultTransport, + int64(pid), + int64(piid), + pkPath) + } + if err != nil { panic(err) }