diff --git a/config/config.example.yaml b/config/config.example.yaml index 6d81f06..a3c2639 100644 --- a/config/config.example.yaml +++ b/config/config.example.yaml @@ -11,10 +11,10 @@ gitea: # request will be ignored. # The bot looks for `X-Gitea-Signature` header containing the sha256 hmac hash of the plain text secret. If the header # exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be validated. - webhookSecret: - value: "" + webhook: + secret: "" # # or path to file containing the plain text secret - # file: /path/to/gitea/webhook/secret + # secretFile: /path/to/gitea/webhook/secret # List of repository the used Gitea account has access to and shall be handled by the bot. Other repository webhooks # will be ignored. @@ -42,10 +42,10 @@ sonarqube: # The bot looks for `X-Sonar-Webhook-HMAC-SHA256` header containing the sha256 hmac hash of the plain text secret. # If the header exists and no webhookSecret is defined here, the bot will ignore the request, because it cannot be # validated. - webhookSecret: - value: "" + webhook: + secret: "" # # or path to file containing the plain text secret - # file: /path/to/sonarqube/webhook/secret + # secretFile: /path/to/sonarqube/webhook/secret # List of project keys from inside SonarQube that should be handled. Webhooks containing other projects will be ignored. # If empty array given, don't filter requests for repositories and proceed them all. diff --git a/internal/settings/settings.go b/internal/settings/settings.go index 7894119..7ab2c5c 100644 --- a/internal/settings/settings.go +++ b/internal/settings/settings.go @@ -13,22 +13,22 @@ type GiteaRepository struct { Name string } -type WebhookSecret struct { - Value string - File string +type Webhook struct { + Secret string + SecretFile string } type GiteaConfig struct { Url string Token string - WebhookSecret WebhookSecret `mapstructure:"webhookSecret"` + Webhook Webhook `mapstructure:"webhook"` Repositories []GiteaRepository } type SonarQubeConfig struct { Url string Token string - WebhookSecret WebhookSecret `mapstructure:"webhookSecret"` + Webhook Webhook `mapstructure:"webhook"` Projects []string } @@ -51,13 +51,13 @@ func init() { func ApplyConfigDefaults() { viper.SetDefault("gitea.url", "") viper.SetDefault("gitea.token", "") - viper.SetDefault("gitea.webhookSecret.value", "") - viper.SetDefault("gitea.webhookSecret.file", "") + viper.SetDefault("gitea.webhook.secret", "") + viper.SetDefault("gitea.webhook.secretFile", "") viper.SetDefault("gitea.repositories", []GiteaRepository{}) viper.SetDefault("sonarqube.url", "") viper.SetDefault("sonarqube.token", "") - viper.SetDefault("sonarqube.webhookSecret.value", "") - viper.SetDefault("sonarqube.webhookSecret.file", "") + viper.SetDefault("sonarqube.webhook.secret", "") + viper.SetDefault("sonarqube.webhook.secretFile", "") viper.SetDefault("sonarqube.projects", []string{}) } @@ -91,11 +91,11 @@ func Load(configPath string) { Gitea = fullConfig.Gitea SonarQube = fullConfig.SonarQube - if Gitea.WebhookSecret.File != "" { - Gitea.WebhookSecret.Value = ReadSecretFile(Gitea.WebhookSecret.File) + if Gitea.Webhook.SecretFile != "" { + Gitea.Webhook.Secret = ReadSecretFile(Gitea.Webhook.SecretFile) } - if SonarQube.WebhookSecret.File != "" { - SonarQube.WebhookSecret.Value = ReadSecretFile(SonarQube.WebhookSecret.File) + if SonarQube.Webhook.SecretFile != "" { + SonarQube.Webhook.Secret = ReadSecretFile(SonarQube.Webhook.SecretFile) } } diff --git a/internal/settings/settings_test.go b/internal/settings/settings_test.go index 342d26d..e6d1efb 100644 --- a/internal/settings/settings_test.go +++ b/internal/settings/settings_test.go @@ -13,25 +13,16 @@ var defaultConfigInlineSecrets []byte = []byte( `gitea: url: https://example.com/gitea token: d0fcdeb5eaa99c506831f9eb4e63fc7cc484a565 - webhookSecret: - value: haxxor-gitea-secret - repositories: [] -sonarqube: - url: https://example.com/sonarqube - token: a09eb5785b25bb2cbacf48808a677a0709f02d8e - webhookSecret: - value: haxxor-sonarqube-secret - projects: [] -`) - -var incompleteConfig []byte = []byte( -`gitea: - url: https://example.com/gitea - webhookSecret: - value: haxxor-gitea-secret + webhook: + secret: haxxor-gitea-secret + repositories: + - owner: some-owner + name: a-repository-name sonarqube: url: https://example.com/sonarqube token: a09eb5785b25bb2cbacf48808a677a0709f02d8e + webhook: + secret: haxxor-sonarqube-secret projects: [] `) @@ -63,17 +54,22 @@ func TestLoadGiteaStructure(t *testing.T) { expected := GiteaConfig{ Url: "https://example.com/gitea", Token: "d0fcdeb5eaa99c506831f9eb4e63fc7cc484a565", - WebhookSecret: WebhookSecret{ - Value: "haxxor-gitea-secret", + Webhook: Webhook{ + Secret: "haxxor-gitea-secret", + }, + Repositories: []GiteaRepository{ + GiteaRepository{ + Owner: "some-owner", + Name: "a-repository-name", + }, }, - Repositories: []GiteaRepository{}, } assert.EqualValues(t, expected, Gitea) } -func TestLoadGiteaStructureWithEnvInjectedWebhookSecret(t *testing.T) { - os.Setenv("PRBOT_GITEA_WEBHOOKSECRET_VALUE", "injected-secret") +func TestLoadGiteaStructureInjectedEnvs(t *testing.T) { + os.Setenv("PRBOT_GITEA_WEBHOOK_SECRET", "injected-webhook-secret") os.Setenv("PRBOT_GITEA_TOKEN", "injected-token") WriteConfigFile(t, defaultConfigInlineSecrets) Load(os.TempDir()) @@ -81,37 +77,90 @@ func TestLoadGiteaStructureWithEnvInjectedWebhookSecret(t *testing.T) { expected := GiteaConfig{ Url: "https://example.com/gitea", Token: "injected-token", - WebhookSecret: WebhookSecret{ - Value: "injected-secret", + Webhook: Webhook{ + Secret: "injected-webhook-secret", + }, + Repositories: []GiteaRepository{ + GiteaRepository{ + Owner: "some-owner", + Name: "a-repository-name", + }, }, - Repositories: []GiteaRepository{}, } assert.EqualValues(t, expected, Gitea) t.Cleanup(func() { - os.Unsetenv("PRBOT_GITEA_WEBHOOKSECRET_VALUE") + os.Unsetenv("PRBOT_GITEA_WEBHOOK_SECRET") os.Unsetenv("PRBOT_GITEA_TOKEN") }) } -func TestLoadStructureWithResolvedWebhookFileFromEnvInjected(t *testing.T) { - secretFile := path.Join(os.TempDir(), "webhook-secret-sonarqube") - _ = ioutil.WriteFile(secretFile, []byte(`totally-secret`),0444) - - os.Setenv("PRBOT_GITEA_WEBHOOKSECRET_FILE", secretFile) - os.Setenv("PRBOT_SONARQUBE_WEBHOOKSECRET_FILE", secretFile) - os.Setenv("PRBOT_GITEA_TOKEN", "injected-token") - - WriteConfigFile(t, incompleteConfig) +func TestLoadSonarQubeStructure(t *testing.T) { + WriteConfigFile(t, defaultConfigInlineSecrets) Load(os.TempDir()) + expected := SonarQubeConfig{ + Url: "https://example.com/sonarqube", + Token: "a09eb5785b25bb2cbacf48808a677a0709f02d8e", + Webhook: Webhook{ + Secret: "haxxor-sonarqube-secret", + }, + Projects: []string{}, + } + + assert.EqualValues(t, expected, SonarQube) +} + +func TestLoadSonarQubeStructureInjectedEnvs(t *testing.T) { + os.Setenv("PRBOT_SONARQUBE_WEBHOOK_SECRET", "injected-webhook-secret") + os.Setenv("PRBOT_SONARQUBE_TOKEN", "injected-token") + WriteConfigFile(t, defaultConfigInlineSecrets) + Load(os.TempDir()) + + expected := SonarQubeConfig{ + Url: "https://example.com/sonarqube", + Token: "injected-token", + Webhook: Webhook{ + Secret: "injected-webhook-secret", + }, + Projects: []string{}, + } + + assert.EqualValues(t, expected, SonarQube) + + t.Cleanup(func() { + os.Unsetenv("PRBOT_SONARQUBE_WEBHOOK_SECRET") + os.Unsetenv("PRBOT_SONARQUBE_TOKEN") + }) +} + +func TestLoadStructureWithFileReferenceResolving(t *testing.T) { + giteaSecretFile := path.Join(os.TempDir(), "webhook-secret-gitea") + sonarqubeSecretFile := path.Join(os.TempDir(), "webhook-secret-sonarqube") + + _ = ioutil.WriteFile(giteaSecretFile, []byte(`gitea-totally-secret`),0444) + _ = ioutil.WriteFile(sonarqubeSecretFile, []byte(`sonarqube-totally-secret`),0444) + + WriteConfigFile(t, []byte( +`gitea: + url: https://example.com/gitea + token: d0fcdeb5eaa99c506831f9eb4e63fc7cc484a565 + repositories: [] +sonarqube: + url: https://example.com/sonarqube + token: a09eb5785b25bb2cbacf48808a677a0709f02d8e + projects: [] +`)) + os.Setenv("PRBOT_GITEA_WEBHOOK_SECRETFILE", giteaSecretFile) + os.Setenv("PRBOT_SONARQUBE_WEBHOOK_SECRETFILE", sonarqubeSecretFile) + expectedGitea := GiteaConfig{ Url: "https://example.com/gitea", - Token: "injected-token", - WebhookSecret: WebhookSecret{ - Value: "totally-secret", - File: secretFile, + Token: "d0fcdeb5eaa99c506831f9eb4e63fc7cc484a565", + Webhook: Webhook{ + Secret: "gitea-totally-secret", + SecretFile: giteaSecretFile, }, Repositories: []GiteaRepository{}, } @@ -119,38 +168,21 @@ func TestLoadStructureWithResolvedWebhookFileFromEnvInjected(t *testing.T) { expectedSonarQube := SonarQubeConfig{ Url: "https://example.com/sonarqube", Token: "a09eb5785b25bb2cbacf48808a677a0709f02d8e", - WebhookSecret: WebhookSecret{ - Value: "totally-secret", - File: secretFile, + Webhook: Webhook{ + Secret: "sonarqube-totally-secret", + SecretFile: sonarqubeSecretFile, }, Projects: []string{}, } + Load(os.TempDir()) assert.EqualValues(t, expectedGitea, Gitea) assert.EqualValues(t, expectedSonarQube, SonarQube) t.Cleanup(func() { - os.Remove(secretFile) - os.Unsetenv("PRBOT_SONARQUBE_WEBHOOKSECRET_FILE") - os.Unsetenv("PRBOT_GITEA_TOKEN") - }) -} - -func TestReadSecretFileWhenDirectoryProvided(t *testing.T) { - assert.Panics(t, func() { ReadSecretFile(os.TempDir()) }, "No panic while trying to read content from directory") -} - -func TestReadSecretFileWhenMissingFileProvided(t *testing.T) { - assert.Panics(t, func() { ReadSecretFile(path.Join(os.TempDir(), "secret-file")) }, "No panic while trying to read missing file") -} - -func TestReadSecretFile(t *testing.T) { - secretFile := path.Join(os.TempDir(), "secret-file") - _ = ioutil.WriteFile(secretFile, []byte(`awesome-secret-content`),0444) - - assert.Equal(t, "awesome-secret-content", ReadSecretFile(secretFile)) - - t.Cleanup(func() { - os.Remove(secretFile) + os.Remove(giteaSecretFile) + os.Remove(sonarqubeSecretFile) + os.Unsetenv("PRBOT_GITEA_WEBHOOK_SECRETFILE") + os.Unsetenv("PRBOT_SONARQUBE_WEBHOOK_SECRETFILE") }) }