diff --git a/.goreleaser.yml b/.goreleaser.yml index 7c1482b..a331147 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -41,4 +41,3 @@ release: # disable: true changelog: disable: true - diff --git a/Makefile b/Makefile index 09a926d..6c0dc29 100644 --- a/Makefile +++ b/Makefile @@ -48,4 +48,13 @@ go.build: chmod +x dist/$(BIN)_v$(VERSION)_$(OS_TYPE)_$(ARCH) build-linux: - GOOS=linux OS_TYPE=linux $(MAKE) go.build \ No newline at end of file + GOOS=linux OS_TYPE=linux $(MAKE) go.build + +run-docker-compose: + cp dist/anklet_v$(VERSION)*_linux_$(ARCH).zip docker/ + cd docker && \ + rm -f anklet_linux_$(ARCH) && \ + unzip anklet_v$(VERSION)*_linux_$(ARCH).zip && \ + mv anklet_v$(VERSION)*_linux_$(ARCH) anklet_linux_$(ARCH) && \ + rm -f anklet_v$(VERSION)*_linux_$(ARCH).zip && \ + docker-compose up --build --force-recreate diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index db7268e..cc7a475 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -12,8 +12,19 @@ services: - "8081:8081" environment: # - LOG_LEVEL=dev - - ANKLET_CONFIG_FILE_NAME=receiver-config.yml - # AGGREGATOR ################################################### + - ANKLET_CONFIG_FILE_NAME=org-receiver-config.yml + ################################################################################## + # ANKLET_GLOBAL_PRIVATE_KEY allows you to use the same private key for all runners + # instead of defining a different one in the config.yml file for each runner. + # You can also set it to be the PEM contents, vs pointing to a file. + # - ANKLET_GLOBAL_PRIVATE_KEY=/Users/nathanpierce/veertuinc-anklet.2024-07-19.private-key.pem + # - |- + # ANKLET_GLOBAL_PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY----- + # MIIEpAIBAAKCAQEAyqZDXOEzV5gRocWAhH73chGjn4HBh1UCG2Du4v9JmcjfyYT3 + # . . . + # -----END RSA PRIVATE KEY----- + ################################################################ + # AGGREGATOR # - ANKLET_METRICS_AGGREGATOR=true # - ANKLET_METRICS_PORT=8081 # - ANKLET_METRICS_URLS=http://host.docker.internal:8080/metrics # comma separation for multiple urls diff --git a/internal/config/config.go b/internal/config/config.go index 226b262..933054d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,12 +15,13 @@ import ( type ContextKey string type Config struct { - Plugins []Plugin `yaml:"plugins"` - Log Log `yaml:"log"` - PidFileDir string `yaml:"pid_file_dir"` - LogFileDir string `yaml:"log_file_dir"` - WorkDir string `yaml:"work_dir"` - Metrics Metrics `yaml:"metrics"` + Plugins []Plugin `yaml:"plugins"` + Log Log `yaml:"log"` + PidFileDir string `yaml:"pid_file_dir"` + LogFileDir string `yaml:"log_file_dir"` + WorkDir string `yaml:"work_dir"` + Metrics Metrics `yaml:"metrics"` + GlobalPrivateKey string `yaml:"global_private_key"` } type Log struct { @@ -146,6 +147,10 @@ func LoadInEnvs(config Config) (Config, error) { if workDir != "" { config.WorkDir = workDir } + envGlobalPrivateKey := os.Getenv("ANKLET_GLOBAL_PRIVATE_KEY") + if envGlobalPrivateKey != "" { + config.GlobalPrivateKey = envGlobalPrivateKey + } // pidFileDir := os.Getenv("ANKLET_PID_FILE_DIR") // if pidFileDir != "" { // config.PidFileDir = pidFileDir @@ -202,3 +207,11 @@ func GetIsRepoSetFromContext(ctx context.Context) bool { } return isRepoSet } + +func GetConfigFileNameFromContext(ctx context.Context) string { + configFileName, ok := ctx.Value(ContextKey("configFileName")).(string) + if !ok { + panic("GetConfigFileNameFromContext failed") + } + return configFileName +} diff --git a/main.go b/main.go index 2032b58..aee5321 100644 --- a/main.go +++ b/main.go @@ -71,11 +71,12 @@ func main() { if err != nil { panic(err) } + var configPath string + var configFileName string if *configFlag != "" { configPath = *configFlag } else { - var configFileName string envConfigFileName := os.Getenv("ANKLET_CONFIG_FILE_NAME") if envConfigFileName != "" { configFileName = envConfigFileName @@ -84,6 +85,7 @@ func main() { } configPath = filepath.Join(homeDir, ".config", "anklet", configFileName) } + parentCtx = context.WithValue(parentCtx, config.ContextKey("configFileName"), configFileName) // obtain config loadedConfig, err := config.LoadConfig(configPath) @@ -320,19 +322,24 @@ func worker(parentCtx context.Context, logger *slog.Logger, loadedConfig config. pluginCtx = context.WithValue(pluginCtx, config.ContextKey("isRepoSet"), true) } + if plugin.PrivateKey == "" && loadedConfig.GlobalPrivateKey != "" { + plugin.PrivateKey = loadedConfig.GlobalPrivateKey + } + pluginCtx = context.WithValue(pluginCtx, config.ContextKey("plugin"), plugin) pluginCtx = logging.AppendCtx(pluginCtx, slog.String("pluginName", plugin.Name)) pluginCtx = context.WithValue(pluginCtx, config.ContextKey("logger"), logger) - ankaCLI, err := anka.NewCLI(pluginCtx) - if err != nil { - pluginCancel() - logger.ErrorContext(pluginCtx, "unable to create anka cli", "error", err) - return + if !strings.Contains(plugin.Plugin, "_receiver") { + ankaCLI, err := anka.NewCLI(pluginCtx) + if err != nil { + pluginCancel() + logger.ErrorContext(pluginCtx, "unable to create anka cli", "error", err) + return + } + pluginCtx = context.WithValue(pluginCtx, config.ContextKey("ankacli"), ankaCLI) } - pluginCtx = context.WithValue(pluginCtx, config.ContextKey("ankacli"), ankaCLI) - if plugin.Database.Enabled { databaseClient, err := database.NewClient(pluginCtx, plugin.Database) if err != nil { diff --git a/plugins/handlers/github/github.go b/plugins/handlers/github/github.go index ff563c6..71ebb81 100644 --- a/plugins/handlers/github/github.go +++ b/plugins/handlers/github/github.go @@ -486,14 +486,16 @@ func Run( logger.InfoContext(pluginCtx, "checking for jobs....") + configFileName := config.GetConfigFileNameFromContext(pluginCtx) + if ctxPlugin.Token == "" && ctxPlugin.PrivateKey == "" { - logging.Panic(workerCtx, pluginCtx, "token and private_key are not set in anklet.yaml:plugins:"+ctxPlugin.Name+":token/private_key") + logging.Panic(workerCtx, pluginCtx, "token or private_key are not set at global level or in "+configFileName+":plugins:"+ctxPlugin.Name+"") } if ctxPlugin.PrivateKey != "" && (ctxPlugin.AppID == 0 || ctxPlugin.InstallationID == 0) { - logging.Panic(workerCtx, pluginCtx, "private_key, app_id, and installation_id must all be set in anklet.yaml:plugins:"+ctxPlugin.Name+"") + logging.Panic(workerCtx, pluginCtx, "private_key, app_id, and installation_id must all be set in "+configFileName+":plugins:"+ctxPlugin.Name+"") } if ctxPlugin.Owner == "" { - logging.Panic(workerCtx, pluginCtx, "owner is not set in anklet.yaml:plugins:"+ctxPlugin.Name+":owner") + logging.Panic(workerCtx, pluginCtx, "owner is not set in "+configFileName+":plugins:"+ctxPlugin.Name+"") } // if ctxPlugin.Repo == "" { // logging.Panic(workerCtx, pluginCtx, "repo is not set in anklet.yaml:plugins:"+ctxPlugin.Name+":repo") @@ -509,7 +511,15 @@ func Run( httpTransport := config.GetHttpTransportFromContext(pluginCtx) var githubClient *github.Client if ctxPlugin.PrivateKey != "" { - itr, err := ghinstallation.NewKeyFromFile(httpTransport, int64(ctxPlugin.AppID), int64(ctxPlugin.InstallationID), ctxPlugin.PrivateKey) + // support private key in a file or as text + var privateKey []byte + privateKeyData, err := os.ReadFile(ctxPlugin.PrivateKey) + if err == nil { + privateKey = privateKeyData + } else { + privateKey = []byte(ctxPlugin.PrivateKey) + } + itr, err := ghinstallation.New(httpTransport, int64(ctxPlugin.AppID), int64(ctxPlugin.InstallationID), privateKey) if err != nil { metricsData.IncrementTotalFailedRunsSinceStart() logger.ErrorContext(pluginCtx, "error creating github app installation token", "err", err) diff --git a/plugins/receivers/github/github.go b/plugins/receivers/github/github.go index df093e3..59b36d8 100644 --- a/plugins/receivers/github/github.go +++ b/plugins/receivers/github/github.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" "net/http" + "os" "strings" "sync" "time" @@ -135,6 +136,12 @@ func Run( StatusSince: time.Now(), }, ) + + if ctxPlugin.Token == "" && ctxPlugin.PrivateKey == "" { + configFileName := config.GetConfigFileNameFromContext(pluginCtx) + logging.Panic(workerCtx, pluginCtx, "token or private_key are not set at global level or in "+configFileName+":plugins:"+ctxPlugin.Name+"") + } + databaseContainer, err := database.GetDatabaseFromContext(pluginCtx) if err != nil { logger.ErrorContext(pluginCtx, "error getting database client from context", "error", err) @@ -144,7 +151,15 @@ func Run( httpTransport := config.GetHttpTransportFromContext(pluginCtx) var githubClient *github.Client if ctxPlugin.PrivateKey != "" { - itr, err := ghinstallation.NewKeyFromFile(httpTransport, int64(ctxPlugin.AppID), int64(ctxPlugin.InstallationID), ctxPlugin.PrivateKey) + // support private key in a file or as text + var privateKey []byte + privateKeyData, err := os.ReadFile(ctxPlugin.PrivateKey) + if err == nil { + privateKey = privateKeyData + } else { + privateKey = []byte(ctxPlugin.PrivateKey) + } + itr, err := ghinstallation.New(httpTransport, int64(ctxPlugin.AppID), int64(ctxPlugin.InstallationID), privateKey) if err != nil { logger.ErrorContext(pluginCtx, "error creating github app installation token", "err", err) return