master
go 156 lines 4.83 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package secretstore_test
4
5 import (
6 "context"
7 "testing"
8
9 "github.com/netdata/netdata/go/plugins/plugin/agent/secrets/secretstore"
10 "github.com/netdata/netdata/go/plugins/plugin/agent/secrets/secretstore/backends"
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
13 )
14
15 func TestProviderSchemaAndValidationParity(t *testing.T) {
16 svc := secretstore.NewService(backends.Creators()...)
17
18 tests := map[string]struct {
19 kind secretstore.StoreKind
20 valid map[string]any
21 invalid map[string]any
22 wantErrContains string
23 assertSchemaShape func(t *testing.T, schema map[string]any)
24 }{
25 "aws": {
26 kind: secretstore.KindAWSSM,
27 valid: map[string]any{
28 "name": "aws_prod",
29 "auth_mode": "env",
30 "region": "us-east-1",
31 },
32 invalid: map[string]any{
33 "name": "aws_prod",
34 "auth_mode": "env",
35 },
36 wantErrContains: "region is required",
37 assertSchemaShape: func(t *testing.T, schema map[string]any) {
38 jsonSchema := schema["jsonSchema"].(map[string]any)
39 assert.Contains(t, jsonSchema["required"], "auth_mode")
40 assert.Contains(t, jsonSchema["required"], "region")
41 _, ok := jsonSchema["allOf"]
42 assert.False(t, ok)
43 },
44 },
45 "azure": {
46 kind: secretstore.KindAzureKV,
47 valid: map[string]any{
48 "name": "azure_prod",
49 "mode": "managed_identity",
50 },
51 invalid: map[string]any{
52 "name": "azure_prod",
53 "mode": "service_principal",
54 "mode_service_principal": map[string]any{
55 "client_id": "client-id",
56 },
57 },
58 wantErrContains: "mode_service_principal.tenant_id is required",
59 assertSchemaShape: func(t *testing.T, schema map[string]any) {
60 jsonSchema := schema["jsonSchema"].(map[string]any)
61 uiSchema := schema["uiSchema"].(map[string]any)
62 assert.Contains(t, jsonSchema["required"], "mode")
63 deps := jsonSchema["dependencies"].(map[string]any)
64 assert.Contains(t, deps, "mode")
65 modeServicePrincipal := uiSchema["mode_service_principal"].(map[string]any)
66 clientSecret := modeServicePrincipal["client_secret"].(map[string]any)
67 assert.Equal(t, "password", clientSecret["ui:widget"])
68 },
69 },
70 "azure default requires mode": {
71 kind: secretstore.KindAzureKV,
72 valid: map[string]any{
73 "name": "azure_default",
74 "mode": "default",
75 },
76 invalid: map[string]any{
77 "name": "azure_default",
78 },
79 wantErrContains: "mode is required",
80 },
81 "gcp": {
82 kind: secretstore.KindGCPSM,
83 valid: map[string]any{
84 "name": "gcp_prod",
85 "mode": "metadata",
86 },
87 invalid: map[string]any{
88 "name": "gcp_prod",
89 "mode": "service_account_file",
90 "mode_service_account_file": map[string]any{},
91 },
92 wantErrContains: "mode_service_account_file.path is required",
93 assertSchemaShape: func(t *testing.T, schema map[string]any) {
94 jsonSchema := schema["jsonSchema"].(map[string]any)
95 assert.Contains(t, jsonSchema["required"], "mode")
96 deps := jsonSchema["dependencies"].(map[string]any)
97 assert.Contains(t, deps, "mode")
98 },
99 },
100 "vault": {
101 kind: secretstore.KindVault,
102 valid: map[string]any{
103 "name": "vault_prod",
104 "mode": "token",
105 "mode_token": map[string]any{
106 "token": "vault-token",
107 },
108 "addr": "https://vault.example",
109 },
110 invalid: map[string]any{
111 "name": "vault_prod",
112 "mode": "token_file",
113 "addr": "https://vault.example",
114 },
115 wantErrContains: "mode_token_file is required",
116 assertSchemaShape: func(t *testing.T, schema map[string]any) {
117 jsonSchema := schema["jsonSchema"].(map[string]any)
118 uiSchema := schema["uiSchema"].(map[string]any)
119 assert.Contains(t, jsonSchema["required"], "addr")
120 assert.Contains(t, jsonSchema["required"], "mode")
121 assert.NotContains(t, jsonSchema["required"], "kind")
122 deps := jsonSchema["dependencies"].(map[string]any)
123 assert.Contains(t, deps, "mode")
124 modeToken := uiSchema["mode_token"].(map[string]any)
125 token := modeToken["token"].(map[string]any)
126 assert.Equal(t, "password", token["ui:widget"])
127 },
128 },
129 }
130
131 for name, tc := range tests {
132 t.Run(name, func(t *testing.T) {
133 displayName, ok := svc.DisplayName(tc.kind)
134 require.True(t, ok)
135 assert.NotEmpty(t, displayName)
136
137 schema, ok := svc.Schema(tc.kind)
138 require.True(t, ok)
139 schemaObj := decodeSchema(t, schema)
140 _, ok = schemaObj["jsonSchema"].(map[string]any)
141 require.True(t, ok)
142 _, ok = schemaObj["uiSchema"].(map[string]any)
143 require.True(t, ok)
144 if tc.assertSchemaShape != nil {
145 tc.assertSchemaShape(t, schemaObj)
146 }
147
148 err := svc.Validate(context.Background(), newStoreFromConfig(t, svc, tc.kind, tc.valid))
149 require.NoError(t, err)
150
151 err = svc.Validate(context.Background(), newStoreFromConfig(t, svc, tc.kind, tc.invalid))
152 require.Error(t, err)
153 assert.ErrorContains(t, err, tc.wantErrContains)
154 })
155 }
156 }