github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/alertmanager/api_test.go (about)

     1  package alertmanager
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"testing"
    11  
    12  	"github.com/go-kit/log"
    13  	"github.com/gorilla/mux"
    14  	"github.com/grafana/dskit/flagext"
    15  	"github.com/grafana/dskit/services"
    16  	"github.com/pkg/errors"
    17  	"github.com/prometheus/alertmanager/config"
    18  	"github.com/prometheus/client_golang/prometheus"
    19  	commoncfg "github.com/prometheus/common/config"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  	"github.com/thanos-io/thanos/pkg/objstore"
    23  	"github.com/weaveworks/common/user"
    24  	"gopkg.in/yaml.v2"
    25  
    26  	"github.com/cortexproject/cortex/pkg/alertmanager/alertspb"
    27  	"github.com/cortexproject/cortex/pkg/alertmanager/alertstore/bucketclient"
    28  	util_log "github.com/cortexproject/cortex/pkg/util/log"
    29  )
    30  
    31  func TestAMConfigValidationAPI(t *testing.T) {
    32  	testCases := []struct {
    33  		name            string
    34  		cfg             string
    35  		maxConfigSize   int
    36  		maxTemplates    int
    37  		maxTemplateSize int
    38  
    39  		response string
    40  		err      error
    41  	}{
    42  		{
    43  			name: "Should return error if the alertmanager config contains no receivers",
    44  			cfg: `
    45  alertmanager_config: |
    46    route:
    47      receiver: 'default-receiver'
    48      group_wait: 30s
    49      group_interval: 5m
    50      repeat_interval: 4h
    51      group_by: [cluster, alertname]
    52  `,
    53  			err: fmt.Errorf("error validating Alertmanager config: undefined receiver \"default-receiver\" used in route"),
    54  		},
    55  		{
    56  			name: "Should pass if the alertmanager config is valid",
    57  			cfg: `
    58  alertmanager_config: |
    59    route:
    60      receiver: 'default-receiver'
    61      group_wait: 30s
    62      group_interval: 5m
    63      repeat_interval: 4h
    64      group_by: [cluster, alertname]
    65    receivers:
    66      - name: default-receiver
    67  `,
    68  		},
    69  		{
    70  			name: "Should return error if the config is empty due to wrong indentation",
    71  			cfg: `
    72  alertmanager_config: |
    73  route:
    74    receiver: 'default-receiver'
    75    group_wait: 30s
    76    group_interval: 5m
    77    repeat_interval: 4h
    78    group_by: [cluster, alertname]
    79  receivers:
    80    - name: default-receiver
    81  template_files:
    82    "good.tpl": "good-templ"
    83    "not/very/good.tpl": "bad-template"
    84  `,
    85  			err: fmt.Errorf("error validating Alertmanager config: configuration provided is empty, if you'd like to remove your configuration please use the delete configuration endpoint"),
    86  		},
    87  		{
    88  			name: "Should return error if the alertmanager config is empty due to wrong key",
    89  			cfg: `
    90  XWRONGalertmanager_config: |
    91    route:
    92      receiver: 'default-receiver'
    93      group_wait: 30s
    94      group_interval: 5m
    95      repeat_interval: 4h
    96      group_by: [cluster, alertname]
    97    receivers:
    98      - name: default-receiver
    99  template_files:
   100    "good.tpl": "good-templ"
   101  `,
   102  			err: fmt.Errorf("error validating Alertmanager config: configuration provided is empty, if you'd like to remove your configuration please use the delete configuration endpoint"),
   103  		},
   104  		{
   105  			name: "Should return error if the external template file name contains an absolute path",
   106  			cfg: `
   107  alertmanager_config: |
   108    route:
   109      receiver: 'default-receiver'
   110      group_wait: 30s
   111      group_interval: 5m
   112      repeat_interval: 4h
   113      group_by: [cluster, alertname]
   114    receivers:
   115      - name: default-receiver
   116  template_files:
   117    "/absolute/filepath": "a simple template"
   118  `,
   119  			err: fmt.Errorf(`error validating Alertmanager config: invalid template name "/absolute/filepath": the template name cannot contain any path`),
   120  		},
   121  		{
   122  			name: "Should return error if the external template file name contains a relative path",
   123  			cfg: `
   124  alertmanager_config: |
   125    route:
   126      receiver: 'default-receiver'
   127      group_wait: 30s
   128      group_interval: 5m
   129      repeat_interval: 4h
   130      group_by: [cluster, alertname]
   131    receivers:
   132      - name: default-receiver
   133  template_files:
   134    "../filepath": "a simple template"
   135  `,
   136  			err: fmt.Errorf(`error validating Alertmanager config: invalid template name "../filepath": the template name cannot contain any path`),
   137  		},
   138  		{
   139  			name: "Should return error if the external template file name is not a valid filename",
   140  			cfg: `
   141  alertmanager_config: |
   142    route:
   143      receiver: 'default-receiver'
   144      group_wait: 30s
   145      group_interval: 5m
   146      repeat_interval: 4h
   147      group_by: [cluster, alertname]
   148    receivers:
   149      - name: default-receiver
   150  template_files:
   151    "good.tpl": "good-templ"
   152    ".": "bad-template"
   153  `,
   154  			err: fmt.Errorf("error validating Alertmanager config: unable to store template file '.'"),
   155  		},
   156  		{
   157  			name: "Should return error if the referenced template contains the root /",
   158  			cfg: `
   159  alertmanager_config: |
   160    route:
   161      receiver: 'default-receiver'
   162      group_wait: 30s
   163      group_interval: 5m
   164      repeat_interval: 4h
   165      group_by: [cluster, alertname]
   166    receivers:
   167      - name: default-receiver
   168    templates:
   169      - "/"
   170  `,
   171  			err: fmt.Errorf(`error validating Alertmanager config: invalid template name "/": the template name cannot contain any path`),
   172  		},
   173  		{
   174  			name: "Should return error if the referenced template contains the root with repeated separators ///",
   175  			cfg: `
   176  alertmanager_config: |
   177    route:
   178      receiver: 'default-receiver'
   179      group_wait: 30s
   180      group_interval: 5m
   181      repeat_interval: 4h
   182      group_by: [cluster, alertname]
   183    receivers:
   184      - name: default-receiver
   185    templates:
   186      - "///"
   187  `,
   188  			err: fmt.Errorf(`error validating Alertmanager config: invalid template name "///": the template name cannot contain any path`),
   189  		},
   190  		{
   191  			name: "Should return error if the referenced template contains an absolute path",
   192  			cfg: `
   193  alertmanager_config: |
   194    route:
   195      receiver: 'default-receiver'
   196      group_wait: 30s
   197      group_interval: 5m
   198      repeat_interval: 4h
   199      group_by: [cluster, alertname]
   200    receivers:
   201      - name: default-receiver
   202    templates:
   203      - "/absolute/filepath"
   204  `,
   205  			err: fmt.Errorf(`error validating Alertmanager config: invalid template name "/absolute/filepath": the template name cannot contain any path`),
   206  		},
   207  		{
   208  			name: "Should return error if the referenced template contains a relative path",
   209  			cfg: `
   210  alertmanager_config: |
   211    route:
   212      receiver: 'default-receiver'
   213      group_wait: 30s
   214      group_interval: 5m
   215      repeat_interval: 4h
   216      group_by: [cluster, alertname]
   217    receivers:
   218      - name: default-receiver
   219    templates:
   220      - "../filepath"
   221  `,
   222  			err: fmt.Errorf(`error validating Alertmanager config: invalid template name "../filepath": the template name cannot contain any path`),
   223  		},
   224  		{
   225  			name: "Should pass if the referenced template is valid filename",
   226  			cfg: `
   227  alertmanager_config: |
   228    route:
   229      receiver: 'default-receiver'
   230      group_wait: 30s
   231      group_interval: 5m
   232      repeat_interval: 4h
   233      group_by: [cluster, alertname]
   234    receivers:
   235      - name: default-receiver
   236    templates:
   237      - "something.tmpl"
   238  `,
   239  		},
   240  		{
   241  			name: "Should return error if global HTTP password_file is set",
   242  			cfg: `
   243  alertmanager_config: |
   244    global:
   245      http_config:
   246        basic_auth:
   247          password_file: /secrets
   248  
   249    route:
   250      receiver: 'default-receiver'
   251    receivers:
   252      - name: default-receiver
   253  `,
   254  			err: errors.Wrap(errPasswordFileNotAllowed, "error validating Alertmanager config"),
   255  		},
   256  		{
   257  			name: "Should return error if global HTTP bearer_token_file is set",
   258  			cfg: `
   259  alertmanager_config: |
   260    global:
   261      http_config:
   262        bearer_token_file: /secrets
   263  
   264    route:
   265      receiver: 'default-receiver'
   266    receivers:
   267      - name: default-receiver
   268  `,
   269  			err: errors.Wrap(errPasswordFileNotAllowed, "error validating Alertmanager config"),
   270  		},
   271  		{
   272  			name: "Should return error if global HTTP credentials_file is set",
   273  			cfg: `
   274  alertmanager_config: |
   275    global:
   276      http_config:
   277        authorization:
   278          credentials_file: /secrets
   279  
   280    route:
   281      receiver: 'default-receiver'
   282    receivers:
   283      - name: default-receiver
   284  `,
   285  			err: errors.Wrap(errPasswordFileNotAllowed, "error validating Alertmanager config"),
   286  		},
   287  		{
   288  			name: "Should return error if global OAuth2 client_secret_file is set",
   289  			cfg: `
   290  alertmanager_config: |
   291    global:
   292      http_config:
   293        oauth2:
   294          client_id: test
   295          token_url: http://example.com
   296          client_secret_file: /secrets
   297  
   298    route:
   299      receiver: 'default-receiver'
   300    receivers:
   301      - name: default-receiver
   302  `,
   303  			err: errors.Wrap(errOAuth2SecretFileNotAllowed, "error validating Alertmanager config"),
   304  		},
   305  		{
   306  			name: "Should return error if receiver's HTTP password_file is set",
   307  			cfg: `
   308  alertmanager_config: |
   309    receivers:
   310      - name: default-receiver
   311        webhook_configs:
   312          - url: http://localhost
   313            http_config:
   314              basic_auth:
   315                password_file: /secrets
   316  
   317    route:
   318      receiver: 'default-receiver'
   319  `,
   320  			err: errors.Wrap(errPasswordFileNotAllowed, "error validating Alertmanager config"),
   321  		},
   322  		{
   323  			name: "Should return error if receiver's HTTP bearer_token_file is set",
   324  			cfg: `
   325  alertmanager_config: |
   326    receivers:
   327      - name: default-receiver
   328        webhook_configs:
   329          - url: http://localhost
   330            http_config:
   331              bearer_token_file: /secrets
   332  
   333    route:
   334      receiver: 'default-receiver'
   335  `,
   336  			err: errors.Wrap(errPasswordFileNotAllowed, "error validating Alertmanager config"),
   337  		},
   338  		{
   339  			name: "Should return error if receiver's HTTP credentials_file is set",
   340  			cfg: `
   341  alertmanager_config: |
   342    receivers:
   343      - name: default-receiver
   344        webhook_configs:
   345          - url: http://localhost
   346            http_config:
   347              authorization:
   348                credentials_file: /secrets
   349  
   350    route:
   351      receiver: 'default-receiver'
   352  `,
   353  			err: errors.Wrap(errPasswordFileNotAllowed, "error validating Alertmanager config"),
   354  		},
   355  		{
   356  			name: "Should return error if receiver's OAuth2 client_secret_file is set",
   357  			cfg: `
   358  alertmanager_config: |
   359    receivers:
   360      - name: default-receiver
   361        webhook_configs:
   362          - url: http://localhost
   363            http_config:
   364              oauth2:
   365                client_id: test
   366                token_url: http://example.com
   367                client_secret_file: /secrets
   368  
   369    route:
   370      receiver: 'default-receiver'
   371  `,
   372  			err: errors.Wrap(errOAuth2SecretFileNotAllowed, "error validating Alertmanager config"),
   373  		},
   374  		{
   375  			name: "Should return error if receiver's HTTP proxy_url is set",
   376  			cfg: `
   377  alertmanager_config: |
   378    receivers:
   379      - name: default-receiver
   380        webhook_configs:
   381          - url: http://localhost
   382            http_config:
   383              proxy_url: http://localhost
   384  
   385    route:
   386      receiver: 'default-receiver'
   387  `,
   388  			err: errors.Wrap(errProxyURLNotAllowed, "error validating Alertmanager config"),
   389  		},
   390  		{
   391  			name: "Should return error if global slack_api_url_file is set",
   392  			cfg: `
   393  alertmanager_config: |
   394    global:
   395      slack_api_url_file: /secrets
   396  
   397    receivers:
   398      - name: default-receiver
   399        webhook_configs:
   400          - url: http://localhost
   401  
   402    route:
   403      receiver: 'default-receiver'
   404  `,
   405  			err: errors.Wrap(errSlackAPIURLFileNotAllowed, "error validating Alertmanager config"),
   406  		},
   407  		{
   408  			name: "Should return error if Slack api_url_file is set",
   409  			cfg: `
   410  alertmanager_config: |
   411    receivers:
   412      - name: default-receiver
   413        slack_configs:
   414          - api_url_file: /secrets
   415  
   416    route:
   417      receiver: 'default-receiver'
   418  `,
   419  			err: errors.Wrap(errSlackAPIURLFileNotAllowed, "error validating Alertmanager config"),
   420  		},
   421  		{
   422  			name: "Should return error if VictorOps api_key_file is set",
   423  			cfg: `
   424  alertmanager_config: |
   425    receivers:
   426      - name: default-receiver
   427        victorops_configs:
   428          - api_key_file: /secrets
   429            api_key: my-key
   430            routing_key: test
   431  
   432    route:
   433      receiver: 'default-receiver'
   434  `,
   435  			err: errors.Wrap(errVictorOpsAPIKeyFileNotAllowed, "error validating Alertmanager config"),
   436  		},
   437  		{
   438  			name: "should return error if template is wrong",
   439  			cfg: `
   440  alertmanager_config: |
   441    route:
   442      receiver: 'default-receiver'
   443      group_wait: 30s
   444      group_interval: 5m
   445      repeat_interval: 4h
   446      group_by: [cluster, alertname]
   447    receivers:
   448      - name: default-receiver
   449    templates:
   450      - "*.tmpl"
   451  template_files:
   452    "test.tmpl": "{{ invalid Go template }}"
   453  `,
   454  			err: fmt.Errorf(`error validating Alertmanager config: template: test.tmpl:1: function "invalid" not defined`),
   455  		},
   456  		{
   457  			name: "config too big",
   458  			cfg: `
   459  alertmanager_config: |
   460    route:
   461      receiver: 'default-receiver'
   462      group_wait: 30s
   463      group_interval: 5m
   464      repeat_interval: 4h
   465      group_by: [cluster, alertname]
   466    receivers:
   467      - name: default-receiver
   468  `,
   469  			maxConfigSize: 10,
   470  			err:           fmt.Errorf(errConfigurationTooBig, 10),
   471  		},
   472  		{
   473  			name: "config size OK",
   474  			cfg: `
   475  alertmanager_config: |
   476    route:
   477      receiver: 'default-receiver'
   478      group_wait: 30s
   479      group_interval: 5m
   480      repeat_interval: 4h
   481      group_by: [cluster, alertname]
   482    receivers:
   483      - name: default-receiver
   484  `,
   485  			maxConfigSize: 1000,
   486  			err:           nil,
   487  		},
   488  		{
   489  			name: "templates limit reached",
   490  			cfg: `
   491  alertmanager_config: |
   492    route:
   493      receiver: 'default-receiver'
   494    receivers:
   495      - name: default-receiver
   496  template_files:
   497    "t1.tmpl": "Some template"
   498    "t2.tmpl": "Some template"
   499    "t3.tmpl": "Some template"
   500    "t4.tmpl": "Some template"
   501    "t5.tmpl": "Some template"
   502  `,
   503  			maxTemplates: 3,
   504  			err:          errors.Wrap(fmt.Errorf(errTooManyTemplates, 5, 3), "error validating Alertmanager config"),
   505  		},
   506  		{
   507  			name: "templates limit not reached",
   508  			cfg: `
   509  alertmanager_config: |
   510    route:
   511      receiver: 'default-receiver'
   512    receivers:
   513      - name: default-receiver
   514  template_files:
   515    "t1.tmpl": "Some template"
   516    "t2.tmpl": "Some template"
   517    "t3.tmpl": "Some template"
   518    "t4.tmpl": "Some template"
   519    "t5.tmpl": "Some template"
   520  `,
   521  			maxTemplates: 10,
   522  			err:          nil,
   523  		},
   524  		{
   525  			name: "template size limit reached",
   526  			cfg: `
   527  alertmanager_config: |
   528    route:
   529      receiver: 'default-receiver'
   530    receivers:
   531      - name: default-receiver
   532  template_files:
   533    "t1.tmpl": "Very big template"
   534  `,
   535  			maxTemplateSize: 5,
   536  			err:             errors.Wrap(fmt.Errorf(errTemplateTooBig, "t1.tmpl", 17, 5), "error validating Alertmanager config"),
   537  		},
   538  		{
   539  			name: "template size limit ok",
   540  			cfg: `
   541  alertmanager_config: |
   542    route:
   543      receiver: 'default-receiver'
   544    receivers:
   545      - name: default-receiver
   546  template_files:
   547    "t1.tmpl": "Very big template"
   548  `,
   549  			maxTemplateSize: 20,
   550  			err:             nil,
   551  		},
   552  	}
   553  
   554  	limits := &mockAlertManagerLimits{}
   555  	am := &MultitenantAlertmanager{
   556  		store:  prepareInMemoryAlertStore(),
   557  		logger: util_log.Logger,
   558  		limits: limits,
   559  	}
   560  	for _, tc := range testCases {
   561  		t.Run(tc.name, func(t *testing.T) {
   562  			limits.maxConfigSize = tc.maxConfigSize
   563  			limits.maxTemplatesCount = tc.maxTemplates
   564  			limits.maxSizeOfTemplate = tc.maxTemplateSize
   565  
   566  			req := httptest.NewRequest(http.MethodPost, "http://alertmanager/api/v1/alerts", bytes.NewReader([]byte(tc.cfg)))
   567  			ctx := user.InjectOrgID(req.Context(), "testing")
   568  			w := httptest.NewRecorder()
   569  			am.SetUserConfig(w, req.WithContext(ctx))
   570  			resp := w.Result()
   571  
   572  			body, err := ioutil.ReadAll(resp.Body)
   573  			require.NoError(t, err)
   574  
   575  			if tc.err == nil {
   576  				require.Equal(t, http.StatusCreated, resp.StatusCode)
   577  				require.Equal(t, "", string(body))
   578  			} else {
   579  				require.Equal(t, http.StatusBadRequest, resp.StatusCode)
   580  				require.Equal(t, tc.err.Error()+"\n", string(body))
   581  			}
   582  		})
   583  	}
   584  }
   585  
   586  func TestMultitenantAlertmanager_DeleteUserConfig(t *testing.T) {
   587  	storage := objstore.NewInMemBucket()
   588  	alertStore := bucketclient.NewBucketAlertStore(storage, nil, log.NewNopLogger())
   589  
   590  	am := &MultitenantAlertmanager{
   591  		store:  alertStore,
   592  		logger: util_log.Logger,
   593  	}
   594  
   595  	require.NoError(t, alertStore.SetAlertConfig(context.Background(), alertspb.AlertConfigDesc{
   596  		User:      "test_user",
   597  		RawConfig: "config",
   598  	}))
   599  
   600  	require.Equal(t, 1, len(storage.Objects()))
   601  
   602  	req := httptest.NewRequest("POST", "/multitenant_alertmanager/delete_tenant_config", nil)
   603  	// Missing user returns error 401. (DeleteUserConfig does this, but in practice, authentication middleware will do it first)
   604  	{
   605  		rec := httptest.NewRecorder()
   606  		am.DeleteUserConfig(rec, req)
   607  		require.Equal(t, http.StatusUnauthorized, rec.Code)
   608  		require.Equal(t, 1, len(storage.Objects()))
   609  	}
   610  
   611  	// With user in the context.
   612  	ctx := user.InjectOrgID(context.Background(), "test_user")
   613  	req = req.WithContext(ctx)
   614  	{
   615  		rec := httptest.NewRecorder()
   616  		am.DeleteUserConfig(rec, req)
   617  		require.Equal(t, http.StatusOK, rec.Code)
   618  		require.Equal(t, 0, len(storage.Objects()))
   619  	}
   620  
   621  	// Repeating the request still reports 200
   622  	{
   623  		rec := httptest.NewRecorder()
   624  		am.DeleteUserConfig(rec, req)
   625  
   626  		require.Equal(t, http.StatusOK, rec.Code)
   627  		require.Equal(t, 0, len(storage.Objects()))
   628  	}
   629  }
   630  
   631  func TestAMConfigListUserConfig(t *testing.T) {
   632  	testCases := map[string]*UserConfig{
   633  		"user1": {
   634  			AlertmanagerConfig: `
   635  global:
   636    resolve_timeout: 5m
   637  route:
   638    receiver: route1
   639    group_by:
   640    - '...'
   641    continue: false
   642  receivers:
   643  - name: route1
   644    webhook_configs:
   645    - send_resolved: true
   646      http_config: {}
   647      url: http://alertmanager/api/notifications?orgId=1&rrid=7
   648      max_alerts: 0
   649  `,
   650  		},
   651  		"user2": {
   652  			AlertmanagerConfig: `
   653  global:
   654    resolve_timeout: 5m
   655  route:
   656    receiver: route1
   657    group_by:
   658    - '...'
   659    continue: false
   660  receivers:
   661  - name: route1
   662    webhook_configs:
   663    - send_resolved: true
   664      http_config: {}
   665      url: http://alertmanager/api/notifications?orgId=2&rrid=7
   666      max_alerts: 0
   667  `,
   668  		},
   669  	}
   670  
   671  	storage := objstore.NewInMemBucket()
   672  	alertStore := bucketclient.NewBucketAlertStore(storage, nil, log.NewNopLogger())
   673  
   674  	for u, cfg := range testCases {
   675  		err := alertStore.SetAlertConfig(context.Background(), alertspb.AlertConfigDesc{
   676  			User:      u,
   677  			RawConfig: cfg.AlertmanagerConfig,
   678  		})
   679  		require.NoError(t, err)
   680  	}
   681  
   682  	externalURL := flagext.URLValue{}
   683  	err := externalURL.Set("http://localhost:8080/alertmanager")
   684  	require.NoError(t, err)
   685  
   686  	// Create the Multitenant Alertmanager.
   687  	reg := prometheus.NewPedanticRegistry()
   688  	cfg := mockAlertmanagerConfig(t)
   689  	am, err := createMultitenantAlertmanager(cfg, nil, nil, alertStore, nil, nil, log.NewNopLogger(), reg)
   690  	require.NoError(t, err)
   691  	require.NoError(t, services.StartAndAwaitRunning(context.Background(), am))
   692  	defer services.StopAndAwaitTerminated(context.Background(), am) //nolint:errcheck
   693  
   694  	err = am.loadAndSyncConfigs(context.Background(), reasonPeriodic)
   695  	require.NoError(t, err)
   696  	require.Len(t, am.alertmanagers, 2)
   697  
   698  	router := mux.NewRouter()
   699  	router.Path("/multitenant_alertmanager/configs").Methods(http.MethodGet).HandlerFunc(am.ListAllConfigs)
   700  	req := httptest.NewRequest("GET", "https://localhost:8080/multitenant_alertmanager/configs", nil)
   701  	w := httptest.NewRecorder()
   702  	router.ServeHTTP(w, req)
   703  
   704  	resp := w.Result()
   705  	require.Equal(t, http.StatusOK, resp.StatusCode)
   706  	require.Equal(t, "application/yaml", resp.Header.Get("Content-Type"))
   707  	body, err := ioutil.ReadAll(resp.Body)
   708  	require.NoError(t, err)
   709  	old, err := yaml.Marshal(testCases)
   710  	require.NoError(t, err)
   711  	require.YAMLEq(t, string(old), string(body))
   712  }
   713  
   714  func TestValidateAlertmanagerConfig(t *testing.T) {
   715  	tests := map[string]struct {
   716  		input    interface{}
   717  		expected error
   718  	}{
   719  		"*HTTPClientConfig": {
   720  			input: &commoncfg.HTTPClientConfig{
   721  				BasicAuth: &commoncfg.BasicAuth{
   722  					PasswordFile: "/secrets",
   723  				},
   724  			},
   725  			expected: errPasswordFileNotAllowed,
   726  		},
   727  		"HTTPClientConfig": {
   728  			input: commoncfg.HTTPClientConfig{
   729  				BasicAuth: &commoncfg.BasicAuth{
   730  					PasswordFile: "/secrets",
   731  				},
   732  			},
   733  			expected: errPasswordFileNotAllowed,
   734  		},
   735  		"*TLSConfig": {
   736  			input: &commoncfg.TLSConfig{
   737  				CertFile: "/cert",
   738  			},
   739  			expected: errTLSFileNotAllowed,
   740  		},
   741  		"TLSConfig": {
   742  			input: commoncfg.TLSConfig{
   743  				CertFile: "/cert",
   744  			},
   745  			expected: errTLSFileNotAllowed,
   746  		},
   747  		"struct containing *HTTPClientConfig as direct child": {
   748  			input: config.GlobalConfig{
   749  				HTTPConfig: &commoncfg.HTTPClientConfig{
   750  					BasicAuth: &commoncfg.BasicAuth{
   751  						PasswordFile: "/secrets",
   752  					},
   753  				},
   754  			},
   755  			expected: errPasswordFileNotAllowed,
   756  		},
   757  		"struct containing *HTTPClientConfig as nested child": {
   758  			input: config.Config{
   759  				Global: &config.GlobalConfig{
   760  					HTTPConfig: &commoncfg.HTTPClientConfig{
   761  						BasicAuth: &commoncfg.BasicAuth{
   762  							PasswordFile: "/secrets",
   763  						},
   764  					},
   765  				},
   766  			},
   767  			expected: errPasswordFileNotAllowed,
   768  		},
   769  		"struct containing *HTTPClientConfig as nested child within a slice": {
   770  			input: config.Config{
   771  				Receivers: []*config.Receiver{{
   772  					Name: "test",
   773  					WebhookConfigs: []*config.WebhookConfig{{
   774  						HTTPConfig: &commoncfg.HTTPClientConfig{
   775  							BasicAuth: &commoncfg.BasicAuth{
   776  								PasswordFile: "/secrets",
   777  							},
   778  						},
   779  					}}},
   780  				},
   781  			},
   782  			expected: errPasswordFileNotAllowed,
   783  		},
   784  		"map containing *HTTPClientConfig": {
   785  			input: map[string]*commoncfg.HTTPClientConfig{
   786  				"test": {
   787  					BasicAuth: &commoncfg.BasicAuth{
   788  						PasswordFile: "/secrets",
   789  					},
   790  				},
   791  			},
   792  			expected: errPasswordFileNotAllowed,
   793  		},
   794  		"map containing TLSConfig as nested child": {
   795  			input: map[string][]config.EmailConfig{
   796  				"test": {{
   797  					TLSConfig: commoncfg.TLSConfig{
   798  						CAFile: "/file",
   799  					},
   800  				}},
   801  			},
   802  			expected: errTLSFileNotAllowed,
   803  		},
   804  	}
   805  
   806  	for testName, testData := range tests {
   807  		t.Run(testName, func(t *testing.T) {
   808  			err := validateAlertmanagerConfig(testData.input)
   809  			assert.ErrorIs(t, err, testData.expected)
   810  		})
   811  	}
   812  }