Repository: openshift-pipelines/pipelines-as-code
Pull request #945 (2022-10-26 07:34:18)

Exposes config validation and defaulting func & uses same internally
this exposes 2 func validation and set defaults which operator webhook can use to expose configuration and uses same func internally to read and validate configurations.

Signed-off-by: Shivam Mukhade <smukhade@redhat.com>

<!-- 🎉🎉🎉 Thank you for the PR!!! 🎉🎉🎉 -->

# Changes

<!-- Describe your changes here- ideally you can get that description straight from
your descriptive commit message(s)! -->

# Submitter Checklist

- [ ] ♽  Run `make test lint` before submitting a PR (ie: with [pre-commit](https://pipelinesascode.com/dev/tools), no need to waste CPU cycle on CI
- [ ] 📖 If you are adding a user facing feature or make a change of the behavior, please verify that you have documented it
- [ ] 🧪 100% coverage is not a target but most of the time we would rather have a unit test if you make a code change.
- [ ] 🎁 If that's something that is possible to do please ensure to check if we can add a e2e test.
- [ ] 🔎 If there is a flakiness in the CI tests then don't *necessary* ignore it, better get the flakyness fixed before merging or if that's not possible there is a good reason to bypass it. (token rate limitation may be a good reason to skip).


chmouel: /retest
codecov-commenter: # [Codecov](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#945](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (bd1119a) into [main](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/commit/f0b69257fccbabf41721610613a1414548cb5fd4?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (f0b6925) will **decrease** coverage by `0.14%`.
> The diff coverage is `40.50%`.

```diff
@@            Coverage Diff             @@
##             main     #945      +/-   ##
==========================================
- Coverage   63.68%   63.53%   -0.15%     
==========================================
  Files          80       83       +3     
  Lines        5174     5282     +108     
==========================================
+ Hits         3295     3356      +61     
- Misses       1568     1614      +46     
- Partials      311      312       +1     
```


| [Impacted Files](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [pkg/params/settings/config.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3BhcmFtcy9zZXR0aW5ncy9jb25maWcuZ28=) | `0.00% <0.00%> (ø)` | |
| [pkg/params/settings/validation.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3BhcmFtcy9zZXR0aW5ncy92YWxpZGF0aW9uLmdv) | `90.47% <90.47%> (ø)` | |
| [pkg/params/settings/default.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3BhcmFtcy9zZXR0aW5ncy9kZWZhdWx0Lmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/sync/semaphore.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/945/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3N5bmMvc2VtYXBob3JlLmdv) | `100.00% <0.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

chmouel: need to fix timeout issue on ci first (not related to this pr)

![image](https://user-images.githubusercontent.com/98980/199722396-902e3b3e-091a-43c9-84f3-85d0a8c25473.png)


Patch:
diff --git a/pkg/adapter/adapter.go b/pkg/adapter/adapter.go
index 44db5600..ee041bc2 100644
--- a/pkg/adapter/adapter.go
+++ b/pkg/adapter/adapter.go
@@ -128,7 +128,7 @@ func (l listener) handleEvent() http.HandlerFunc {
 		l.event = info.NewEvent()
 
 		// if repository auto configuration is enabled then check if its a valid event
-		if l.run.Info.Pac.AutoConfigureNewRepo {
+		if l.run.Info.Pac.AutoConfigureNewGitHubRepo {
 			detected, configuring, err := github.ConfigureRepository(ctx, l.run, request, string(payload), l.logger)
 			if detected {
 				if configuring && err == nil {
diff --git a/pkg/params/info/defaults.go b/pkg/params/info/defaults.go
deleted file mode 100644
index 8fea6cb2..00000000
--- a/pkg/params/info/defaults.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package info
-
-const (
-	PACConfigmapName   = "pipelines-as-code"
-	PACApplicationName = "Pipelines as Code CI"
-	HubURL             = "https://api.hub.tekton.dev/v1"
-	HubCatalogName     = "tekton"
-)
diff --git a/pkg/params/info/pac.go b/pkg/params/info/pac.go
index 16f9d606..c9eb4805 100644
--- a/pkg/params/info/pac.go
+++ b/pkg/params/info/pac.go
@@ -4,29 +4,16 @@ import (
 	"os"
 	"strings"
 
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	"github.com/spf13/cobra"
 )
 
 type PacOpts struct {
-	LogURL                string
-	ApplicationName       string // the Application Name for example "Pipelines as Code"
-	SecretAutoCreation    bool   // secret auto creation in target namespace
-	WebhookType           string
-	PayloadFile           string
-	TektonDashboardURL    string
-	HubURL                string
-	HubCatalogName        string
-	RemoteTasks           bool
-	MaxKeepRunsUpperLimit int
-	DefaultMaxKeepRuns    int
-
-	// bitbucket cloud specific fields
-	BitbucketCloudCheckSourceIP      bool
-	BitbucketCloudAdditionalSourceIP string
-
-	// GitHub App specific
-	AutoConfigureNewRepo               bool
-	AutoConfigureRepoNamespaceTemplate string
+	*settings.Settings
+	LogURL             string
+	WebhookType        string
+	PayloadFile        string
+	TektonDashboardURL string
 }
 
 func (p *PacOpts) AddFlags(cmd *cobra.Command) error {
@@ -51,7 +38,7 @@ func (p *PacOpts) AddFlags(cmd *cobra.Command) error {
 	cmd.Flags().BoolVar(&p.SecretAutoCreation,
 		"secret-auto-creation",
 		secretAutoCreation,
-		"Wether to create automatically secrets.")
+		"Whether to create automatically secrets.")
 
 	return nil
 }
diff --git a/pkg/params/run.go b/pkg/params/run.go
index 8f450b24..a5a46e64 100644
--- a/pkg/params/run.go
+++ b/pkg/params/run.go
@@ -4,16 +4,20 @@ import (
 	"context"
 	"fmt"
 	"os"
-	"strconv"
 	"strings"
 
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/consoleui"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/watch"
 )
 
+const (
+	PACConfigmapName = "pipelines-as-code"
+)
+
 type Run struct {
 	Clients clients.Clients
 	Info    info.Info
@@ -34,7 +38,7 @@ func (r *Run) WatchConfigMapChanges(ctx context.Context, run *Run) error {
 		return fmt.Errorf("failed to find pipelines-as-code installation namespace")
 	}
 	watcher, err := r.Clients.Kube.CoreV1().ConfigMaps(ns).Watch(ctx, v1.SingleObject(v1.ObjectMeta{
-		Name:      info.PACConfigmapName,
+		Name:      PACConfigmapName,
 		Namespace: ns,
 	}))
 	if err != nil {
@@ -76,78 +80,23 @@ func (r *Run) UpdatePACInfo(ctx context.Context) error {
 		return fmt.Errorf("failed to find pipelines-as-code installation namespace")
 	}
 	// TODO: move this to kubeinteractions class so we can add unittests.
-	cfg, err := r.Clients.Kube.CoreV1().ConfigMaps(ns).Get(ctx, info.PACConfigmapName, v1.GetOptions{})
+	cfg, err := r.Clients.Kube.CoreV1().ConfigMaps(ns).Get(ctx, PACConfigmapName, v1.GetOptions{})
 	if err != nil {
 		return err
 	}
 
-	if r.Info.Pac.ApplicationName == "" {
-		if applicationName, ok := cfg.Data["application-name"]; ok {
-			r.Info.Pac.ApplicationName = applicationName
-		} else {
-			r.Info.Pac.ApplicationName = info.PACApplicationName
-		}
-	}
-
-	if secretAutoCreation, ok := cfg.Data["secret-auto-create"]; ok {
-		r.Info.Pac.SecretAutoCreation = StringToBool(secretAutoCreation)
+	if err = settings.ConfigToSettings(r.Clients.Log, r.Info.Pac.Settings, cfg.Data); err != nil {
+		return err
 	}
 
-	if tektonDashboardURL, ok := cfg.Data["tekton-dashboard-url"]; ok {
-		r.Clients.Log.Infof("using tekton dashboard url on: %s", tektonDashboardURL)
-		r.Clients.ConsoleUI = &consoleui.TektonDashboard{BaseURL: tektonDashboardURL}
+	if r.Info.Pac.Settings.TektonDashboardURL != r.Clients.ConsoleUI.URL() {
+		r.Clients.Log.Infof("updating console url to: %s", r.Info.Pac.Settings.TektonDashboardURL)
+		r.Clients.ConsoleUI = &consoleui.TektonDashboard{BaseURL: r.Info.Pac.Settings.TektonDashboardURL}
 	}
 	if os.Getenv("PAC_TEKTON_DASHBOARD_URL") != "" {
 		r.Clients.Log.Infof("using tekton dashboard url on: %s", os.Getenv("PAC_TEKTON_DASHBOARD_URL"))
 		r.Clients.ConsoleUI = &consoleui.TektonDashboard{BaseURL: os.Getenv("PAC_TEKTON_DASHBOARD_URL")}
 	}
-
-	if hubURL, ok := cfg.Data["hub-url"]; ok {
-		r.Info.Pac.HubURL = hubURL
-	} else {
-		r.Info.Pac.HubURL = info.HubURL
-	}
-
-	if hubCatalogName, ok := cfg.Data["hub-catalog-name"]; ok {
-		r.Info.Pac.HubCatalogName = hubCatalogName
-	} else {
-		r.Info.Pac.HubCatalogName = info.HubCatalogName
-	}
-
-	if remoteTask, ok := cfg.Data["remote-tasks"]; ok {
-		r.Info.Pac.RemoteTasks = StringToBool(remoteTask)
-	}
-
-	if check, ok := cfg.Data["bitbucket-cloud-check-source-ip"]; ok {
-		r.Info.Pac.BitbucketCloudCheckSourceIP = StringToBool(check)
-	}
-
-	if sourceIP, ok := cfg.Data["bitbucket-cloud-additional-source-ip"]; ok {
-		r.Info.Pac.BitbucketCloudAdditionalSourceIP = sourceIP
-	}
-
-	if runs, ok := cfg.Data["max-keep-run-upper-limit"]; ok && runs != "" {
-		r.Info.Pac.MaxKeepRunsUpperLimit, err = strconv.Atoi(runs)
-		if err != nil {
-			return fmt.Errorf("failed to convert max-keep-run-upper-limit value to int: %w", err)
-		}
-	}
-
-	if runs, ok := cfg.Data["default-max-keep-runs"]; ok && runs != "" {
-		r.Info.Pac.DefaultMaxKeepRuns, err = strconv.Atoi(runs)
-		if err != nil {
-			return fmt.Errorf("failed to convert default-max-keep-run value to int: %w", err)
-		}
-	}
-
-	if autoConfigure, ok := cfg.Data["auto-configure-new-github-repo"]; ok {
-		r.Info.Pac.AutoConfigureNewRepo = StringToBool(autoConfigure)
-	}
-
-	if nsTemplate, ok := cfg.Data["auto-configure-repo-namespace-template"]; ok {
-		r.Info.Pac.AutoConfigureRepoNamespaceTemplate = nsTemplate
-	}
-
 	return nil
 }
 
@@ -155,8 +104,10 @@ func New() *Run {
 	return &Run{
 		Info: info.Info{
 			Pac: &info.PacOpts{
-				ApplicationName: info.PACApplicationName,
-				HubURL:          info.HubURL,
+				Settings: &settings.Settings{
+					ApplicationName: settings.PACApplicationNameDefaultValue,
+					HubURL:          settings.HubURLDefaultValue,
+				},
 			},
 		},
 	}
diff --git a/pkg/params/settings/config.go b/pkg/params/settings/config.go
new file mode 100644
index 00000000..2aa431de
--- /dev/null
+++ b/pkg/params/settings/config.go
@@ -0,0 +1,121 @@
+package settings
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"go.uber.org/zap"
+)
+
+const (
+	ApplicationNameKey                    = "application-name"
+	SecretAutoCreateKey                   = "secret-auto-create"
+	HubURLKey                             = "hub-url"
+	HubCatalogNameKey                     = "hub-catalog-name"
+	MaxKeepRunUpperLimitKey               = "max-keep-run-upper-limit"
+	DefaultMaxKeepRunsKey                 = "default-max-keep-runs"
+	RemoteTasksKey                        = "remote-tasks"
+	BitbucketCloudCheckSourceIPKey        = "bitbucket-cloud-check-source-ip"
+	BitbucketCloudAdditionalSourceIPKey   = "bitbucket-cloud-additional-source-ip"
+	TektonDashboardURLKey                 = "tekton-dashboard-url"
+	AutoConfigureNewGitHubRepoKey         = "auto-configure-new-github-repo"
+	AutoConfigureRepoNamespaceTemplateKey = "auto-configure-repo-namespace-template"
+
+	secretAutoCreateDefaultValue            = "true"
+	remoteTasksDefaultValue                 = "true"
+	bitbucketCloudCheckSourceIPDefaultValue = "true"
+	PACApplicationNameDefaultValue          = "Pipelines as Code CI"
+	HubURLDefaultValue                      = "https://api.hub.tekton.dev/v1"
+	hubCatalogNameDefaultValue              = "tekton"
+	AutoConfigureNewGitHubRepoDefaultValue  = "true"
+)
+
+type Settings struct {
+	ApplicationName                    string
+	SecretAutoCreation                 bool
+	HubURL                             string
+	HubCatalogName                     string
+	RemoteTasks                        bool
+	MaxKeepRunsUpperLimit              int
+	DefaultMaxKeepRuns                 int
+	BitbucketCloudCheckSourceIP        bool
+	BitbucketCloudAdditionalSourceIP   string
+	TektonDashboardURL                 string
+	AutoConfigureNewGitHubRepo         bool
+	AutoConfigureRepoNamespaceTemplate string
+}
+
+func ConfigToSettings(logger *zap.SugaredLogger, setting *Settings, config map[string]string) error {
+	// pass through defaulting
+	SetDefaults(config)
+
+	// validate fields
+	if err := Validate(config); err != nil {
+		return fmt.Errorf("config validation failed: %w", err)
+	}
+
+	if setting.ApplicationName != config[ApplicationNameKey] {
+		logger.Infof("CONFIG: application name updated to %v", config[ApplicationNameKey])
+		setting.ApplicationName = config[ApplicationNameKey]
+	}
+	secretAutoCreate := StringToBool(config[SecretAutoCreateKey])
+	if setting.SecretAutoCreation != secretAutoCreate {
+		logger.Infof("CONFIG: secret auto create updated to %v", secretAutoCreate)
+		setting.SecretAutoCreation = secretAutoCreate
+	}
+	if setting.HubURL != config[HubURLKey] {
+		logger.Infof("CONFIG: hub URL updated to %v", config[HubURLKey])
+		setting.HubURL = config[HubURLKey]
+	}
+	if setting.HubCatalogName != config[HubCatalogNameKey] {
+		logger.Infof("CONFIG: hub catalog name updated to %v", config[HubCatalogNameKey])
+		setting.HubCatalogName = config[HubCatalogNameKey]
+	}
+	remoteTask := StringToBool(config[RemoteTasksKey])
+	if setting.RemoteTasks != remoteTask {
+		logger.Infof("CONFIG: remote tasks setting updated to %v", remoteTask)
+		setting.RemoteTasks = remoteTask
+	}
+	maxKeepRunUpperLimit, _ := strconv.Atoi(config[MaxKeepRunUpperLimitKey])
+	if setting.MaxKeepRunsUpperLimit != maxKeepRunUpperLimit {
+		logger.Infof("CONFIG: max keep runs upper limit updated to %v", maxKeepRunUpperLimit)
+		setting.MaxKeepRunsUpperLimit = maxKeepRunUpperLimit
+	}
+	defaultMaxKeepRun, _ := strconv.Atoi(config[DefaultMaxKeepRunsKey])
+	if setting.DefaultMaxKeepRuns != defaultMaxKeepRun {
+		logger.Infof("CONFIG: default keep runs updated to %v", defaultMaxKeepRun)
+		setting.DefaultMaxKeepRuns = defaultMaxKeepRun
+	}
+	check := StringToBool(config[BitbucketCloudCheckSourceIPKey])
+	if setting.BitbucketCloudCheckSourceIP != check {
+		logger.Infof("CONFIG: bitbucket cloud check source ip setting updated to %v", check)
+		setting.BitbucketCloudCheckSourceIP = check
+	}
+	if setting.BitbucketCloudAdditionalSourceIP != config[BitbucketCloudAdditionalSourceIPKey] {
+		logger.Infof("CONFIG: bitbucket cloud additional source ip updated to %v", config[BitbucketCloudAdditionalSourceIPKey])
+		setting.BitbucketCloudAdditionalSourceIP = config[BitbucketCloudAdditionalSourceIPKey]
+	}
+	if setting.TektonDashboardURL != config[TektonDashboardURLKey] {
+		logger.Infof("CONFIG: tekton dashboard url updated to %v", config[TektonDashboardURLKey])
+		setting.TektonDashboardURL = config[TektonDashboardURLKey]
+	}
+	autoConfigure := StringToBool(config[AutoConfigureNewGitHubRepoKey])
+	if setting.AutoConfigureNewGitHubRepo != autoConfigure {
+		logger.Infof("CONFIG: auto configure GitHub repo setting updated to %v", autoConfigure)
+		setting.AutoConfigureNewGitHubRepo = autoConfigure
+	}
+	if setting.AutoConfigureRepoNamespaceTemplate != config[AutoConfigureRepoNamespaceTemplateKey] {
+		logger.Infof("CONFIG: auto configure repo namespace template updated to %v", config[AutoConfigureRepoNamespaceTemplateKey])
+		setting.AutoConfigureRepoNamespaceTemplate = config[AutoConfigureRepoNamespaceTemplateKey]
+	}
+	return nil
+}
+
+func StringToBool(s string) bool {
+	if strings.ToLower(s) == "true" ||
+		strings.ToLower(s) == "yes" || s == "1" {
+		return true
+	}
+	return false
+}
diff --git a/pkg/params/settings/default.go b/pkg/params/settings/default.go
new file mode 100644
index 00000000..9ff0acc1
--- /dev/null
+++ b/pkg/params/settings/default.go
@@ -0,0 +1,31 @@
+package settings
+
+func SetDefaults(config map[string]string) {
+	if appName, ok := config[ApplicationNameKey]; !ok || appName == "" {
+		config[ApplicationNameKey] = PACApplicationNameDefaultValue
+	}
+
+	if secretAutoCreation, ok := config[SecretAutoCreateKey]; !ok || secretAutoCreation == "" {
+		config[SecretAutoCreateKey] = secretAutoCreateDefaultValue
+	}
+
+	if hubURL, ok := config[HubURLKey]; !ok || hubURL == "" {
+		config[HubURLKey] = HubURLDefaultValue
+	}
+
+	if hubCatalogName, ok := config[HubCatalogNameKey]; !ok || hubCatalogName == "" {
+		config[HubCatalogNameKey] = hubCatalogNameDefaultValue
+	}
+
+	if remoteTasks, ok := config[RemoteTasksKey]; !ok || remoteTasks == "" {
+		config[RemoteTasksKey] = remoteTasksDefaultValue
+	}
+
+	if check, ok := config[BitbucketCloudCheckSourceIPKey]; !ok || check == "" {
+		config[BitbucketCloudCheckSourceIPKey] = bitbucketCloudCheckSourceIPDefaultValue
+	}
+
+	if autoConfigure, ok := config[AutoConfigureNewGitHubRepoKey]; !ok || autoConfigure == "" {
+		config[AutoConfigureNewGitHubRepoKey] = AutoConfigureNewGitHubRepoDefaultValue
+	}
+}
diff --git a/pkg/params/settings/validation.go b/pkg/params/settings/validation.go
new file mode 100644
index 00000000..536faa05
--- /dev/null
+++ b/pkg/params/settings/validation.go
@@ -0,0 +1,51 @@
+package settings
+
+import (
+	"fmt"
+	"strconv"
+)
+
+func Validate(config map[string]string) error {
+	if secretAutoCreation, ok := config[SecretAutoCreateKey]; ok {
+		if !isValidBool(secretAutoCreation) {
+			return fmt.Errorf("invalid value for key %v, acceptable values: true or false", SecretAutoCreateKey)
+		}
+	}
+
+	if remoteTask, ok := config[RemoteTasksKey]; ok {
+		if !isValidBool(remoteTask) {
+			return fmt.Errorf("invalid value for key %v, acceptable values: true or false", RemoteTasksKey)
+		}
+	}
+
+	if check, ok := config[BitbucketCloudCheckSourceIPKey]; ok {
+		if !isValidBool(check) {
+			return fmt.Errorf("invalid value for key %v, acceptable values: true or false", BitbucketCloudCheckSourceIPKey)
+		}
+	}
+
+	if runs, ok := config[MaxKeepRunUpperLimitKey]; ok && runs != "" {
+		_, err := strconv.Atoi(runs)
+		if err != nil {
+			return fmt.Errorf("failed to convert %v value to int: %w", MaxKeepRunUpperLimitKey, err)
+		}
+	}
+
+	if runs, ok := config[DefaultMaxKeepRunsKey]; ok && runs != "" {
+		_, err := strconv.Atoi(runs)
+		if err != nil {
+			return fmt.Errorf("failed to convert %v value to int: %w", DefaultMaxKeepRunsKey, err)
+		}
+	}
+
+	if check, ok := config[AutoConfigureNewGitHubRepoKey]; ok {
+		if !isValidBool(check) {
+			return fmt.Errorf("invalid value for key %v, acceptable values: true or false", AutoConfigureNewGitHubRepoKey)
+		}
+	}
+	return nil
+}
+
+func isValidBool(value string) bool {
+	return value == "true" || value == "false"
+}


Test patch:
diff --git a/pkg/adapter/adapter_test.go b/pkg/adapter/adapter_test.go
index 1b906988..4bdb37af 100644
--- a/pkg/adapter/adapter_test.go
+++ b/pkg/adapter/adapter_test.go
@@ -12,6 +12,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
 	"go.uber.org/zap"
 	zapobserver "go.uber.org/zap/zaptest/observer"
@@ -35,7 +36,11 @@ func TestHandleEvent(t *testing.T) {
 				PipelineAsCode: cs.PipelineAsCode,
 			},
 			Info: info.Info{
-				Pac: &info.PacOpts{AutoConfigureNewRepo: false},
+				Pac: &info.PacOpts{
+					Settings: &settings.Settings{
+						AutoConfigureNewGitHubRepo: false,
+					},
+				},
 			},
 		},
 		logger: getLogger(),
diff --git a/pkg/cmd/tknpac/resolve/resolve_test.go b/pkg/cmd/tknpac/resolve/resolve_test.go
index 52df837b..86b27860 100644
--- a/pkg/cmd/tknpac/resolve/resolve_test.go
+++ b/pkg/cmd/tknpac/resolve/resolve_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
 	"go.uber.org/zap"
 	zapobserver "go.uber.org/zap/zaptest/observer"
@@ -54,7 +55,7 @@ func TestCommandFilenameSetProperly(t *testing.T) {
 			Kube:              stdata.Kube,
 			ClientInitialized: true,
 		},
-		Info: info.Info{Pac: &info.PacOpts{}},
+		Info: info.Info{Pac: &info.PacOpts{Settings: &settings.Settings{}}},
 	}
 	cmd := Command(cs, io)
 	e := bytes.NewBufferString("")
diff --git a/pkg/hub/get_test.go b/pkg/hub/get_test.go
index 2c60d838..2a803b89 100644
--- a/pkg/hub/get_test.go
+++ b/pkg/hub/get_test.go
@@ -7,6 +7,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	httptesthelper "github.com/openshift-pipelines/pipelines-as-code/pkg/test/http"
 	rtesting "knative.dev/pkg/reconciler/testing"
 )
@@ -83,7 +84,7 @@ func TestGetTask(t *testing.T) {
 				Clients: clients.Clients{
 					HTTP: *httpTestClient,
 				},
-				Info: info.Info{Pac: &info.PacOpts{HubURL: testHubURL, HubCatalogName: testCatalogHubName}},
+				Info: info.Info{Pac: &info.PacOpts{Settings: &settings.Settings{HubURL: testHubURL, HubCatalogName: testCatalogHubName}}},
 			}
 			got, err := GetTask(ctx, cs, tt.task)
 			if (err != nil) != tt.wantErr {
diff --git a/pkg/matcher/annotation_tasks_install_test.go b/pkg/matcher/annotation_tasks_install_test.go
index 6d76bc56..e5eb7a68 100644
--- a/pkg/matcher/annotation_tasks_install_test.go
+++ b/pkg/matcher/annotation_tasks_install_test.go
@@ -9,6 +9,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	httptesthelper "github.com/openshift-pipelines/pipelines-as-code/pkg/test/http"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/test/provider"
 	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
@@ -225,8 +226,10 @@ func TestRemoteTasksGetTaskFromAnnotations(t *testing.T) {
 				},
 				Info: info.Info{
 					Pac: &info.PacOpts{
-						HubURL:         testHubURL,
-						HubCatalogName: testCatalogHubName,
+						Settings: &settings.Settings{
+							HubURL:         testHubURL,
+							HubCatalogName: testCatalogHubName,
+						},
 					},
 				},
 			}
@@ -348,8 +351,10 @@ func TestGetPipelineFromAnnotations(t *testing.T) {
 				},
 				Info: info.Info{
 					Pac: &info.PacOpts{
-						HubURL:         testHubURL,
-						HubCatalogName: testCatalogHubName,
+						Settings: &settings.Settings{
+							HubURL:         testHubURL,
+							HubCatalogName: testCatalogHubName,
+						},
 					},
 				},
 			}
diff --git a/pkg/params/settings/default_test.go b/pkg/params/settings/default_test.go
new file mode 100644
index 00000000..dd598d69
--- /dev/null
+++ b/pkg/params/settings/default_test.go
@@ -0,0 +1,18 @@
+package settings
+
+import (
+	"testing"
+
+	"gotest.tools/v3/assert"
+)
+
+func TestSetDefaults(t *testing.T) {
+	config := make(map[string]string)
+	SetDefaults(config)
+	assert.Equal(t, config[RemoteTasksKey], remoteTasksDefaultValue)
+	assert.Equal(t, config[SecretAutoCreateKey], secretAutoCreateDefaultValue)
+	assert.Equal(t, config[BitbucketCloudCheckSourceIPKey], bitbucketCloudCheckSourceIPDefaultValue)
+	assert.Equal(t, config[ApplicationNameKey], PACApplicationNameDefaultValue)
+	assert.Equal(t, config[HubURLKey], HubURLDefaultValue)
+	assert.Equal(t, config[HubCatalogNameKey], hubCatalogNameDefaultValue)
+}
diff --git a/pkg/params/settings/validation_test.go b/pkg/params/settings/validation_test.go
new file mode 100644
index 00000000..9f6492dd
--- /dev/null
+++ b/pkg/params/settings/validation_test.go
@@ -0,0 +1,65 @@
+package settings
+
+import (
+	"testing"
+
+	"gotest.tools/v3/assert"
+)
+
+func TestValidate(t *testing.T) {
+	tests := []struct {
+		name    string
+		config  map[string]string
+		wantErr string
+	}{
+		{
+			name: "valid config",
+			config: map[string]string{
+				SecretAutoCreateKey:            "true",
+				RemoteTasksKey:                 "false",
+				BitbucketCloudCheckSourceIPKey: "false",
+				MaxKeepRunUpperLimitKey:        "7",
+				DefaultMaxKeepRunsKey:          "8",
+			},
+			wantErr: "",
+		},
+		{
+			name: "invalid bool",
+			config: map[string]string{
+				SecretAutoCreateKey: "random",
+			},
+			wantErr: "invalid value for key secret-auto-create, acceptable values: true or false",
+		},
+		{
+			name: "invalid max keep run upper limit",
+			config: map[string]string{
+				MaxKeepRunUpperLimitKey: "random",
+			},
+			wantErr: "failed to convert max-keep-run-upper-limit value to int: strconv.Atoi: parsing \"random\": invalid syntax",
+		},
+		{
+			name: "invalid max keep run default",
+			config: map[string]string{
+				DefaultMaxKeepRunsKey: "1as",
+			},
+			wantErr: "failed to convert default-max-keep-runs value to int: strconv.Atoi: parsing \"1as\": invalid syntax",
+		},
+		{
+			name: "invalid check source ip value",
+			config: map[string]string{
+				BitbucketCloudCheckSourceIPKey: "tru",
+			},
+			wantErr: "invalid value for key bitbucket-cloud-check-source-ip, acceptable values: true or false",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := Validate(tt.config)
+			if tt.wantErr != "" {
+				assert.Error(t, err, tt.wantErr)
+				return
+			}
+			assert.NilError(t, err)
+		})
+	}
+}
diff --git a/pkg/pipelineascode/pipelinesascode_github_test.go b/pkg/pipelineascode/pipelinesascode_github_test.go
index 5ac2282b..918d1ca2 100644
--- a/pkg/pipelineascode/pipelinesascode_github_test.go
+++ b/pkg/pipelineascode/pipelinesascode_github_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	ghprovider "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/github"
 	testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
 	testDynamic "github.com/openshift-pipelines/pipelines-as-code/pkg/test/dynamic"
@@ -426,7 +427,9 @@ func TestRun(t *testing.T) {
 				},
 				Info: info.Info{
 					Pac: &info.PacOpts{
-						SecretAutoCreation: true,
+						Settings: &settings.Settings{
+							SecretAutoCreation: true,
+						},
 					},
 				},
 			}
diff --git a/pkg/provider/bitbucketcloud/bitbucket_test.go b/pkg/provider/bitbucketcloud/bitbucket_test.go
index 2badd377..b355b23e 100644
--- a/pkg/provider/bitbucketcloud/bitbucket_test.go
+++ b/pkg/provider/bitbucketcloud/bitbucket_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/ktrysmt/go-bitbucket"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
 	bbcloudtest "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketcloud/test"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketcloud/types"
@@ -278,7 +279,9 @@ func TestCreateStatus(t *testing.T) {
 			bbcloudtest.MuxCreateComment(t, mux, event, tt.expectedCommentSubstr)
 
 			err := v.CreateStatus(ctx, nil, event, &info.PacOpts{
-				ApplicationName: "HELLO APP",
+				Settings: &settings.Settings{
+					ApplicationName: "HELLO APP",
+				},
 			}, tt.status)
 			assert.NilError(t, err)
 		})
diff --git a/pkg/provider/bitbucketcloud/events_test.go b/pkg/provider/bitbucketcloud/events_test.go
index 3dcab45d..173aaad1 100644
--- a/pkg/provider/bitbucketcloud/events_test.go
+++ b/pkg/provider/bitbucketcloud/events_test.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	bbcloudtest "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketcloud/test"
 	httptesthelper "github.com/openshift-pipelines/pipelines-as-code/pkg/test/http"
 	"gotest.tools/v3/assert"
@@ -160,8 +161,10 @@ func TestParsePayload(t *testing.T) {
 			run := &params.Run{
 				Info: info.Info{
 					Pac: &info.PacOpts{
-						BitbucketCloudCheckSourceIP:      false,
-						BitbucketCloudAdditionalSourceIP: "",
+						Settings: &settings.Settings{
+							BitbucketCloudCheckSourceIP:      false,
+							BitbucketCloudAdditionalSourceIP: "",
+						},
 					},
 				},
 			}
diff --git a/pkg/provider/bitbucketserver/bitbucketserver_test.go b/pkg/provider/bitbucketserver/bitbucketserver_test.go
index 55370c72..213f7dbe 100644
--- a/pkg/provider/bitbucketserver/bitbucketserver_test.go
+++ b/pkg/provider/bitbucketserver/bitbucketserver_test.go
@@ -18,6 +18,7 @@ import (
 
 	bbv1 "github.com/gfleury/go-bitbucket-v1"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
 	bbtest "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketserver/test"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/provider/bitbucketserver/types"
@@ -76,7 +77,9 @@ func TestGetTektonDir(t *testing.T) {
 
 func TestCreateStatus(t *testing.T) {
 	pacopts := info.PacOpts{
-		ApplicationName: "HELLO APP",
+		Settings: &settings.Settings{
+			ApplicationName: "HELLO APP",
+		},
 	}
 	pullRequestNumber := 10
 
diff --git a/pkg/provider/github/repository_test.go b/pkg/provider/github/repository_test.go
index f98bde91..d341f717 100644
--- a/pkg/provider/github/repository_test.go
+++ b/pkg/provider/github/repository_test.go
@@ -12,6 +12,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
 	"go.uber.org/zap"
 	zapobserver "go.uber.org/zap/zaptest/observer"
@@ -119,7 +120,9 @@ func TestConfigureRepository(t *testing.T) {
 				},
 				Info: info.Info{
 					Pac: &info.PacOpts{
-						AutoConfigureRepoNamespaceTemplate: tt.nsTemplate,
+						Settings: &settings.Settings{
+							AutoConfigureRepoNamespaceTemplate: tt.nsTemplate,
+						},
 					},
 				},
 			}
diff --git a/pkg/provider/github/status_test.go b/pkg/provider/github/status_test.go
index 2eee3646..464ec189 100644
--- a/pkg/provider/github/status_test.go
+++ b/pkg/provider/github/status_test.go
@@ -14,6 +14,7 @@ import (
 	"github.com/google/go-github/v47/github"
 	apipac "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
 	ghtesthelper "github.com/openshift-pipelines/pipelines-as-code/pkg/test/github"
 	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
@@ -43,7 +44,7 @@ func TestGithubProviderCreateCheckRun(t *testing.T) {
 		SHA:          "createCheckRunSHA",
 	}
 
-	err := cnx.getOrUpdateCheckRunStatus(ctx, nil, event, &info.PacOpts{LogURL: "http://nowhere"}, provider.StatusOpts{
+	err := cnx.getOrUpdateCheckRunStatus(ctx, nil, event, &info.PacOpts{LogURL: "http://nowhere", Settings: &settings.Settings{}}, provider.StatusOpts{
 		PipelineRunName: "pr1",
 		Status:          "hello moto",
 	})
@@ -251,7 +252,8 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 				DetailsURL:      tt.args.detailsURL,
 			}
 			pacopts := &info.PacOpts{
-				LogURL: "https://log",
+				LogURL:   "https://log",
+				Settings: &settings.Settings{},
 			}
 			if tt.notoken {
 				tt.args.runevent = info.NewEvent()
@@ -350,7 +352,7 @@ func TestGithubProvidercreateStatusCommit(t *testing.T) {
 				Client: fakeclient,
 			}
 
-			if err := provider.createStatusCommit(ctx, tt.event, &info.PacOpts{}, tt.status); (err != nil) != tt.wantErr {
+			if err := provider.createStatusCommit(ctx, tt.event, &info.PacOpts{Settings: &settings.Settings{}}, tt.status); (err != nil) != tt.wantErr {
 				t.Errorf("GetCommitInfo() error = %v, wantErr %v", err, tt.wantErr)
 			}
 		})
@@ -373,7 +375,7 @@ func TestGetCheckName(t *testing.T) {
 				status: provider.StatusOpts{
 					OriginalPipelineRunName: "HELLO",
 				},
-				pacopts: &info.PacOpts{ApplicationName: ""},
+				pacopts: &info.PacOpts{Settings: &settings.Settings{ApplicationName: ""}},
 			},
 			want: "HELLO",
 		},
@@ -383,7 +385,7 @@ func TestGetCheckName(t *testing.T) {
 				status: provider.StatusOpts{
 					OriginalPipelineRunName: "MOTO",
 				},
-				pacopts: &info.PacOpts{ApplicationName: "HELLO"},
+				pacopts: &info.PacOpts{Settings: &settings.Settings{ApplicationName: "HELLO"}},
 			},
 			want: "HELLO / MOTO",
 		},
@@ -393,7 +395,7 @@ func TestGetCheckName(t *testing.T) {
 				status: provider.StatusOpts{
 					OriginalPipelineRunName: "",
 				},
-				pacopts: &info.PacOpts{ApplicationName: "PAC"},
+				pacopts: &info.PacOpts{Settings: &settings.Settings{ApplicationName: "PAC"}},
 			},
 			want: "PAC",
 		},
diff --git a/pkg/provider/gitlab/gitlab_test.go b/pkg/provider/gitlab/gitlab_test.go
index 3a6f8ffd..1103c1d7 100644
--- a/pkg/provider/gitlab/gitlab_test.go
+++ b/pkg/provider/gitlab/gitlab_test.go
@@ -11,6 +11,7 @@ import (
 
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
 	thelp "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/gitlab/test"
 	"github.com/xanzy/go-gitlab"
@@ -168,7 +169,7 @@ func TestCreateStatus(t *testing.T) {
 				thelp.MuxNotePost(t, mux, v.targetProjectID, tt.args.event.PullRequestNumber, tt.args.postStr)
 			}
 
-			pacOpts := &info.PacOpts{ApplicationName: "Test me"}
+			pacOpts := &info.PacOpts{Settings: &settings.Settings{ApplicationName: "Test me"}}
 			if err := v.CreateStatus(ctx, nil, tt.args.event, pacOpts, tt.args.statusOpts); (err != nil) != tt.wantErr {
 				t.Errorf("CreateStatus() error = %v, wantErr %v", err, tt.wantErr)
 			}
diff --git a/pkg/reconciler/cleanup_test.go b/pkg/reconciler/cleanup_test.go
index 1ea89891..8933bb7d 100644
--- a/pkg/reconciler/cleanup_test.go
+++ b/pkg/reconciler/cleanup_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
 	tektontest "github.com/openshift-pipelines/pipelines-as-code/pkg/test/tekton"
 	"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
@@ -148,8 +149,10 @@ func TestCleanupPipelineRuns(t *testing.T) {
 				run: &params.Run{
 					Info: info.Info{
 						Pac: &info.PacOpts{
-							MaxKeepRunsUpperLimit: tt.maxkeepruns,
-							DefaultMaxKeepRuns:    tt.defaultmaxkeepruns,
+							Settings: &settings.Settings{
+								MaxKeepRunsUpperLimit: tt.maxkeepruns,
+								DefaultMaxKeepRuns:    tt.defaultmaxkeepruns,
+							},
 						},
 					},
 				},
diff --git a/pkg/reconciler/reconciler_test.go b/pkg/reconciler/reconciler_test.go
index 7d3a4b83..3c6bd9b1 100644
--- a/pkg/reconciler/reconciler_test.go
+++ b/pkg/reconciler/reconciler_test.go
@@ -19,6 +19,7 @@ import (
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
+	"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
 	ghprovider "github.com/openshift-pipelines/pipelines-as-code/pkg/provider/github"
 	"github.com/openshift-pipelines/pipelines-as-code/pkg/sync"
 	testclient "github.com/openshift-pipelines/pipelines-as-code/pkg/test/clients"
@@ -166,7 +167,9 @@ func TestReconciler_ReconcileKind(t *testing.T) {
 					},
 					Info: info.Info{
 						Pac: &info.PacOpts{
-							SecretAutoCreation: true,
+							Settings: &settings.Settings{
+								SecretAutoCreation: true,
+							},
 						},
 					},
 				},