Skip to content

Commit 3281754

Browse files
support loading a raw private key from the environment. (#54)
* support loading a raw private key from the environment. Also made integration test a new target to simplify local unit testing * fail if both private key and key path are provided. added a comment to clarify how the private key should be encoded
1 parent 6b65745 commit 3281754

File tree

7 files changed

+61
-17
lines changed

7 files changed

+61
-17
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ jobs:
4545
run: go install sigs.k8s.io/controller-runtime/tools/setup-envtest@4dbfa5c66aa24a35003c41507385c2a91e94d404 # release-0.23
4646
- name: Test
4747
run: |
48-
make test
48+
make integration-test

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ fmt:
1919
go fmt ./...
2020

2121
test:
22-
KUBEBUILDER_ASSETS=$$(setup-envtest use -p path) go test ./...
22+
go test ./...
23+
24+
integration-test:
25+
KUBEBUILDER_ASSETS=$$(setup-envtest use -p path) go test -tags integration_test ./...
2326

2427
test-short:
2528
go test -short ./...

cmd/deployment-tracker/main.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"encoding/base64"
56
"flag"
67
"fmt"
78
"log"
@@ -67,6 +68,16 @@ func main() {
6768
opts := slog.HandlerOptions{Level: slog.LevelInfo}
6869
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &opts)))
6970

71+
var ghAppPrivateKey []byte
72+
if b64Key := os.Getenv("GH_APP_PRIVATE_KEY"); b64Key != "" {
73+
var err error
74+
ghAppPrivateKey, err = base64.StdEncoding.DecodeString(b64Key)
75+
if err != nil {
76+
slog.Error("Failed to base64 decode GH_APP_PRIVATE_KEY", "error", err)
77+
os.Exit(1)
78+
}
79+
}
80+
7081
var cntrlCfg = controller.Config{
7182
Template: getEnvOrDefault("DN_TEMPLATE", defaultTemplate),
7283
LogicalEnvironment: os.Getenv("LOGICAL_ENVIRONMENT"),
@@ -76,10 +87,16 @@ func main() {
7687
BaseURL: getEnvOrDefault("BASE_URL", "api.github.com"),
7788
GHAppID: getEnvOrDefault("GH_APP_ID", ""),
7889
GHInstallID: getEnvOrDefault("GH_INSTALL_ID", ""),
79-
GHAppPrivateKey: getEnvOrDefault("GH_APP_PRIV_KEY", ""),
90+
GHAppPrivateKey: ghAppPrivateKey,
91+
GHAppPrivateKeyPath: getEnvOrDefault("GH_APP_PRIV_KEY_PATH", ""),
8092
Organization: os.Getenv("GITHUB_ORG"),
8193
}
8294

95+
if len(cntrlCfg.GHAppPrivateKey) > 0 && cntrlCfg.GHAppPrivateKeyPath != "" {
96+
slog.Error("Both GH_APP_PRIVATE_KEY and GH_APP_PRIV_KEY_PATH are set. Only one can be used.")
97+
os.Exit(1)
98+
}
99+
83100
if !controller.ValidTemplate(cntrlCfg.Template) {
84101
slog.Error("Template must contain at least one placeholder",
85102
"template", cntrlCfg.Template,

internal/controller/config.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@ type Config struct {
2020
PhysicalEnvironment string
2121
Cluster string
2222
//nolint:gosec
23-
APIToken string
24-
BaseURL string
25-
GHAppID string
26-
GHInstallID string
27-
GHAppPrivateKey string
28-
Organization string
23+
APIToken string
24+
BaseURL string
25+
GHAppID string
26+
GHInstallID string
27+
// GHAppPrivateKey must be the PEM Encoding of the
28+
// private key
29+
GHAppPrivateKey []byte
30+
GHAppPrivateKeyPath string
31+
Organization string
2932
}
3033

3134
// ValidTemplate verifies that at least one placeholder is present

internal/controller/controller.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,13 @@ func New(clientset kubernetes.Interface, metadataAggregator podMetadataAggregato
8787
}
8888
if cfg.GHAppID != "" &&
8989
cfg.GHInstallID != "" &&
90-
cfg.GHAppPrivateKey != "" {
91-
clientOpts = append(clientOpts, deploymentrecord.WithGHApp(cfg.GHAppID, cfg.GHInstallID, cfg.GHAppPrivateKey))
90+
(len(cfg.GHAppPrivateKey) > 0 || cfg.GHAppPrivateKeyPath != "") {
91+
clientOpts = append(clientOpts, deploymentrecord.WithGHApp(
92+
cfg.GHAppID,
93+
cfg.GHInstallID,
94+
cfg.GHAppPrivateKey,
95+
cfg.GHAppPrivateKeyPath,
96+
))
9297
}
9398

9499
apiClient, err := deploymentrecord.NewClient(

internal/controller/controller_integration_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//go:build integration_test
2+
13
package controller
24

35
import (

pkg/deploymentrecord/client.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,12 @@ func WithAPIToken(token string) ClientOption {
105105
// WithGHApp configures a GitHub app to use for authentication.
106106
// If provided values are invalid, this will panic.
107107
// If an API token is also set, the GitHub App will take precedence.
108-
func WithGHApp(id, installID, pk string) ClientOption {
108+
func WithGHApp(id, installID string, pkBytes []byte, pkPath string) ClientOption {
109109
return func(c *Client) {
110+
if len(pkBytes) > 0 && pkPath != "" {
111+
panic("both GitHub App private key and private key path are set")
112+
}
113+
110114
pid, err := strconv.Atoi(id)
111115
if err != nil {
112116
panic(err)
@@ -115,11 +119,21 @@ func WithGHApp(id, installID, pk string) ClientOption {
115119
if err != nil {
116120
panic(err)
117121
}
118-
c.transport, err = ghinstallation.NewKeyFromFile(
119-
http.DefaultTransport,
120-
int64(pid),
121-
int64(piid),
122-
pk)
122+
123+
if len(pkBytes) > 0 {
124+
c.transport, err = ghinstallation.New(
125+
http.DefaultTransport,
126+
int64(pid),
127+
int64(piid),
128+
pkBytes)
129+
} else {
130+
c.transport, err = ghinstallation.NewKeyFromFile(
131+
http.DefaultTransport,
132+
int64(pid),
133+
int64(piid),
134+
pkPath)
135+
}
136+
123137
if err != nil {
124138
panic(err)
125139
}

0 commit comments

Comments
 (0)