chore: revert remove unmaintained secret stores#5857
Conversation
WalkthroughAdds three new external secret providers (Alibaba Cloud KMS, Device42, Passbolt) with complete API types, provider implementations, CRD schemas, unit tests, E2E tests, documentation, and build artifacts. Changes
Possibly related PRs
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This reverts commit aa51995. Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
7377042 to
633022a
Compare
|
There was a problem hiding this comment.
Actionable comments posted: 15
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
config/crds/bases/external-secrets.io_secretstores.yaml (1)
6540-6634: Keep v1beta1 frozen: remove new providers from the v1beta1 schema.
v1beta1 is deprecated/back-compat only, and these providers should live exclusively under v1. Please drop the alibaba/device42/passbolt blocks from v1beta1. Based on learnings, please keep new providers v1-only.Also applies to: 7813-7862, 9035-9109
🤖 Fix all issues with AI agents
In `@CODEOWNERS.md`:
- Line 24: Update the CODEOWNERS entries that reference non-existent directories
by replacing the old paths pkg/provider/alibaba/, pkg/provider/device42/, and
pkg/provider/passbolt/ with the correct provider directories
providers/v1/alibaba/, providers/v1/device42/, and providers/v1/passbolt/ and
keep the same owner `@external-secrets/provider-alibaba-reviewers` (and
corresponding owners) so ownership points to the actual implementations.
In `@config/crds/bases/external-secrets.io_clustersecretstores.yaml`:
- Around line 373-467: Remove the newly added provider blocks from the v1beta1
CRD schema: delete the "alibaba" provider definition (the alibaba.auth /
alibaba.regionID object) and any "device42" and "passbolt" provider entries that
were added to the v1beta1 CRD so that only GA v1 contains new providers; ensure
those providers remain only in the v1 CRD schema and update any references in
the v1beta1 file that list them as allowed providers (e.g., provider enum/lists)
so v1beta1 no longer includes "alibaba", "device42", or "passbolt".
In `@deploy/crds/bundle.yaml`:
- Around line 2452-2541: Summary: Remove new provider blocks from v1beta1 CRD
versions. Locate the provider blocks named "alibaba" (and similarly "device42"
and "passbolt") that were added under the v1beta1 schema versions for
ClusterSecretStore and SecretStore and delete those provider entries from the
v1beta1 sections only; leave the existing provider definitions in the v1 schema
untouched. Ensure you remove the entire provider object (its properties,
required, and type entries) from the v1beta1 ClusterSecretStore and SecretStore
definitions so v1beta1 remains frozen for backward compatibility.
In `@e2e/suites/provider/cases/alibaba/provider.go`:
- Around line 77-84: The DeleteSecret implementation ignores its key parameter
and uses the hardcoded secretName; update alibabaProvider.DeleteSecret to set
kmssecretrequest.SecretName = key (instead of secretName) so the passed-in key
is deleted, mirroring how CreateSecret should accept and use the key; keep the
existing client creation (kms.NewClientWithAccessKey) and error expectations
(Expect(...)) intact while replacing the hardcoded constant with the key
parameter.
- Around line 100-124: The SecretStore construction (secretStore,
AlibabaProvider) is missing the required RegionID and references the wrong
secret name; set AlibabaProvider.RegionID to the test region value and update
the SecretRef names in AccessKeyID and AccessKeySecret to use the same
Kubernetes secret variable used in BeforeEach (secretName) and ensure the
StringData keys in the created secret match "keyid" and "accesskey" so the
names/keys align with the AccessKeyID/AccessKeySecret selectors.
- Around line 66-75: In CreateSecret, replace the hardcoded secretName and
"value" with the function inputs so each call uses the provided key and val: set
kmssecretrequest.SecretName = key and kmssecretrequest.SecretData = the string
representation of val (e.g., val.Value or serialize framework.SecretEntry if it
contains multiple fields) before calling client.CreateSecret; keep the existing
client creation and Expect(err).ToNot(HaveOccurred()) checks but ensure you
properly convert/serialize framework.SecretEntry to a string for SecretData
instead of the fixed "value".
In `@providers/v1/alibaba/go.mod`:
- Line 95: Update the vulnerable module reference golang.org/x/crypto in
providers/v1/alibaba/go.mod from v0.43.0 to at least v0.45.0, then run
dependency housekeeping (e.g., go get golang.org/x/crypto@v0.45.0 and go mod
tidy) to refresh go.mod/go.sum and ensure the new secure version is resolved;
verify builds and tests pass after the upgrade.
In `@providers/v1/alibaba/kms.go`:
- Around line 243-249: The ConnectTimeout and Timeout values in credentialConfig
are using plain integers (30 and 60) while newRRSAAuth uses milliseconds
(30*1000, 60*1000), causing inconsistent units; update credentialConfig
(credential.Config) to set ConnectTimeout and Timeout in milliseconds to match
newRRSAAuth (e.g., multiply by 1000 or use the same expressions) so timeouts are
consistent across newRRSAAuth and the access-key auth path.
In `@providers/v1/alibaba/logger.go`:
- Around line 82-84: The Printf implementation of retryablehttp.Logger in
function logger.Printf is treating variadic format args as structured key/value
pairs by calling l.Logger.Info(msg, keysAndValues...), which is wrong; change it
to format the message first (e.g., formatted := fmt.Sprintf(msg,
keysAndValues...)) and then call l.Logger.Info(formatted) (or the logger's
single-argument Infof equivalent if available) and add "fmt" to imports so
format verbs are applied correctly and no odd key/value panics occur.
In `@providers/v1/alibaba/utils.go`:
- Around line 32-38: SanitizeErr currently panics on nil and only applies the
last regex because each loop reuses err.Error(); change it to return nil if err
== nil, initialize msg := err.Error(), then iterate over regexReqIDs applying
each regex to the evolving msg (e.g., regex.ReplaceAllString or ReplaceAll on
msg) so earlier sanitizations are preserved, and finally return errors.New(msg)
(or the original error if you prefer to preserve type) — update the function
SanitizeErr and reference regexReqIDs accordingly.
In `@providers/v1/device42/device42_api.go`:
- Around line 86-102: In ReadAndUnmarshal, the status-code error message uses
buf.String() before the body is read so it will always be empty; change the
logic to first read the response body into buf (and handle read errors), then
check resp.StatusCode and, if it's not 2xx, return an error that includes
buf.String() along with the status; keep the existing deferred resp.Body.Close()
and return json.Unmarshal(buf.Bytes(), target) only when status is OK.
- Around line 125-127: The code currently returns an empty D42Password with a
nil error when d42PasswordResponse.Passwords is empty; change this to return a
clear non-nil error instead: inside the function that processes
d42PasswordResponse (check d42PasswordResponse.Passwords), if len(...) == 0
return D42Password{} and an explicit error (e.g. fmt.Errorf or errors.New)
stating the Device42 secret/password was not found rather than returning the
existing err variable; update callers if needed to handle the new error.
In `@providers/v1/device42/device42.go`:
- Around line 143-151: Device42.Validate currently does a concrete type
assertion p.client.(*API) which will panic for mocks or nil; update the client
abstraction instead: add a method to the client interface (e.g., URL() string or
BaseURL() and HostPort()) and implement it on API and any mocks, then change
Device42.Validate to call p.client.URL() (or p.client.BaseURL()/HostPort()) to
build the url without asserting concrete types; if you cannot change the
interface immediately, replace the assertion with a safe type check (api, ok :=
p.client.(*API)) and return esv1.ValidationResultError with a clear error when
not ok or when p.client is nil.
In `@providers/v1/device42/go.mod`:
- Line 72: The go.mod in providers/v1/device42 pins golang.org/x/crypto at
v0.43.0 which is vulnerable; update the dependency declaration for
"golang.org/x/crypto v0.43.0" to at least v0.46.0 by running `go get
golang.org/x/crypto@v0.46.0` from the providers/v1/device42 directory and then
run `go mod tidy` to refresh go.sum and module lines so the go.mod entry for
golang.org/x/crypto is updated.
In `@providers/v1/passbolt/go.mod`:
- Line 79: Update the vulnerable dependency entry for golang.org/x/crypto in
go.mod to v0.45.0 (or later) by running the suggested command (go get -u
golang.org/x/crypto@v0.45.0), then run go mod tidy to update go.sum and ensure
module graph consistency; verify by running tests and any SSH-related
integration checks to confirm no regressions.
♻️ Duplicate comments (5)
deploy/crds/bundle.yaml (5)
3753-3798: Same v1-only schema verification applies to the Device42 block.
Please follow the earlier verification to ensure this block isn’t under v1beta1. Based on learnings, v1beta1 should not receive new providers.
5953-6027: Same v1-only schema verification applies to the Passbolt block.
Please follow the earlier verification to ensure this block isn’t under v1beta1. Based on learnings, v1beta1 should not receive new providers.
14229-14318: Same v1-only schema verification applies to this Alibaba block.
Please follow the earlier verification to ensure this block isn’t under v1beta1. Based on learnings, v1beta1 should not receive new providers.
15530-15575: Same v1-only schema verification applies to this Device42 block.
Please follow the earlier verification to ensure this block isn’t under v1beta1. Based on learnings, v1beta1 should not receive new providers.
17730-17804: Same v1-only schema verification applies to this Passbolt block.
Please follow the earlier verification to ensure this block isn’t under v1beta1. Based on learnings, v1beta1 should not receive new providers.
🟡 Minor comments (9)
docs/snippets/passbolt-secret-example.yaml-5-7 (1)
5-7: Secretdatafield values must be base64-encoded.Kubernetes Secret
datafields require base64-encoded values. The current plaintext values will cause errors when applied. Either:
- Use
stringDatainstead ofdatafor plaintext values, or- Base64-encode the values in
dataOption 1: Use stringData (recommended for docs)
apiVersion: v1 kind: Secret metadata: name: passbolt-example -data: +stringData: full_secret: '{"name":"passbolt-secret","username":"some-username","password":"supersecretpassword","uri":"passbolt.com","description":"some description"}' password_only: supersecretpassword type: Opaqueapis/externalsecrets/v1/secretstore_device42_types.go-37-42 (1)
37-42: Consider aligningSecretRefoptionality with other providers.
Device42Auth.SecretRefis a required field (non-pointer type), butDevice42SecretRef.Credentialsis optional. This deviates from the pattern used by other providers (AWS, GCPSM, Vault, Azure, etc.), which use pointers forSecretReffields to make them optional. Either makeSecretRefa pointer to align with other providers, or makeCredentialsrequired if authentication always needs credentials.providers/v1/device42/device42.go-181-189 (1)
181-189: Missing nil client check.
GetSecretMapdoes not check ifp.clientis nil before callingGetSecret, unlikeGetSecretwhich has this check on line 170. This inconsistency could lead to a nil pointer dereference.🐛 Proposed fix
func (p *Device42) GetSecretMap(_ context.Context, ref esv1.ExternalSecretDataRemoteRef) (map[string][]byte, error) { + if esutils.IsNil(p.client) { + return nil, errors.New(errUninitializedProvider) + } data, err := p.client.GetSecret(ref.Key) if err != nil { return nil, fmt.Errorf("error getting secret %s: %w", ref.Key, err) } return data.ToMap(), nil }pkg/register/device42.go-27-29 (1)
27-29: Incorrect comment: refers to "vault provider" instead of "device42 provider".The comment on line 28 appears to be a copy-paste error.
Suggested fix
func init() { - // Register vault provider + // Register device42 provider esv1.Register(device42.NewProvider(), device42.ProviderSpec(), device42.MaintenanceStatus()) }docs/provider/device42.md-6-6 (1)
6-6: Fix grammar in auth and secret reference descriptions.
Keeps docs professional and unambiguous.✏️ Suggested edits
-`username` and `password` is required to talk to the Device42 API. +`username` and `password` are required to talk to the Device42 API. ... -The `password` field is return from device42 +The `password` field is returned from Device42.Also applies to: 39-40
docs/snippets/passbolt-external-secret-example.yaml-15-18 (1)
15-18: Fix typo in comments (“exising” → “existing”).
Small but user-facing polish.🔧 Suggested edit
- key: e22487a8-feb8-4591-95aa-14b193930cb4 # Replace with ID of exising Passbolt secret + key: e22487a8-feb8-4591-95aa-14b193930cb4 # Replace with ID of existing Passbolt secret ... - key: e22487a8-feb8-4591-95aa-14b193930cb4 # Replace with ID of exising Passbolt secret + key: e22487a8-feb8-4591-95aa-14b193930cb4 # Replace with ID of existing Passbolt secretproviders/v1/alibaba/kms.go-310-312 (1)
310-312: Typo in error message: "proivder" should be "provider".✏️ Proposed fix
if alibabaSpec.Auth.RRSAAuth.OIDCProviderARN == "" { - return errors.New("missing alibaba OIDC proivder ARN") + return errors.New("missing alibaba OIDC provider ARN") }providers/v1/passbolt/passbolt.go-192-195 (1)
192-195: Potential nil pointer dereference ifCloseis called beforeNewClient.If
Closeis called whenprovider.clientis nil (e.g., ifNewClientwas never called or failed), this will cause a panic.🛡️ Proposed defensive fix
// Close implements cleanup operations for the Passbolt provider. func (provider *ProviderPassbolt) Close(ctx context.Context) error { + if provider.client == nil { + return nil + } return provider.client.Logout(ctx) }providers/v1/passbolt/passbolt.go-295-298 (1)
295-298: Emptytotpcase and incorrect error formatting.Two issues in this switch statement:
The
totpcase (line 295-296) is empty and doesn't populate any password-related fields. If this is intentional behavior for TOTP-only resources, consider adding a comment to clarify.Line 297 uses
resourceType(the struct) in the format string with%q, which will print the struct representation rather than the slug.🐛 Proposed fix for error formatting
case "totp": + // TOTP resources don't have a password field default: - return nil, fmt.Errorf("UnknownPassboltResourceType: %q", resourceType) + return nil, fmt.Errorf("UnknownPassboltResourceType: %q", resourceType.Slug) }
🧹 Nitpick comments (13)
providers/v1/passbolt/passbolt_test.go (1)
268-280: Minor: Subtest receives unused*testing.Tparameter.The subtest function signature discards
*testing.Twhile relying on the outertregistered with gomega. This works but is inconsistent with the pattern used inTestGetAllSecrets(lines 199-225) which properly uses the innert.♻️ Suggested fix
for _, row := range tbl { - t.Run(row.name, func(_ *testing.T) { + t.Run(row.name, func(t *testing.T) { + g.RegisterTestingT(t) p := &ProviderPassbolt{client: clientMock}apis/externalsecrets/v1/secretstore_device42_types.go (1)
24-30: Doc comment inconsistency: "URL" vs "Host".The comment on line 25 states "URL configures the Device42 instance URL" but the field is named
Host. Consider aligning the comment with the field name for clarity.📝 Suggested fix
// Device42Provider configures a store to sync secrets with a Device42 instance. type Device42Provider struct { - // URL configures the Device42 instance URL. + // Host configures the Device42 instance URL. Host string `json:"host"`providers/v1/alibaba/fake/fake.go (1)
31-34: Mock ignores the actual request parameter.
GetSecretValuecreates a new emptyGetSecretValueRequestinstead of forwarding the actual request to the mock function. This prevents tests from verifying that the correct request parameters are being passed.♻️ Suggested fix
// GetSecretValue retrieves a secret value from the mock Alibaba client. -func (mc *AlibabaMockClient) GetSecretValue(context.Context, *kmssdk.GetSecretValueRequest) (result *kmssdk.GetSecretValueResponseBody, err error) { - return mc.getSecretValue(&kmssdk.GetSecretValueRequest{}) +func (mc *AlibabaMockClient) GetSecretValue(_ context.Context, req *kmssdk.GetSecretValueRequest) (result *kmssdk.GetSecretValueResponseBody, err error) { + return mc.getSecretValue(req) }providers/v1/device42/device42_api.go (1)
64-78: Consider adding a default HTTP client timeout.The HTTP client is created without a timeout. While
GetSecretuses a context timeout, having a default client timeout provides defense-in-depth against hanging connections.♻️ Suggested improvement
func NewAPI(baseURL, username, password, hostPort string) *API { tr := &http.Transport{ TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS12}, } api := &API{ baseURL: baseURL, hostPort: hostPort, username: username, password: password, - client: &http.Client{Transport: tr}, + client: &http.Client{Transport: tr, Timeout: 30 * time.Second}, } return api }providers/v1/device42/device42_api_test.go (1)
41-103: Consider adding test cases for edge scenarios.The tests cover the happy path and bad JSON response, but don't cover:
- Empty passwords array (which currently has a bug returning nil error)
- Non-2xx HTTP status codes
- Network/request errors
These additional test cases would help catch the issues identified in the implementation.
♻️ Additional test cases to consider
{ name: "empty passwords array", fields: fields{ funcStack: []func(req *http.Request) (*http.Response, error){ createResponder(D42PasswordResponse{Passwords: []D42Password{}}, true), }, }, args: args{ secretID: device42PasswordID, }, want: D42Password{}, wantErr: true, // Should error when no password found }, { name: "non-2xx status code", fields: fields{ funcStack: []func(req *http.Request) (*http.Response, error){ func(req *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: http.StatusUnauthorized, Body: &closeableBuffer{bytes.NewReader([]byte("unauthorized"))}, }, nil }, }, }, args: args{ secretID: device42PasswordID, }, want: D42Password{}, wantErr: true, },providers/v1/device42/device42.go (2)
131-132: Port "443" is hardcoded.The port is hardcoded to "443" but the
Device42Providerstruct likely has a configurable host field. Consider making the port configurable or documenting that only HTTPS on port 443 is supported.
54-57: ValidateStore performs no validation.This method returns
nil, nilwithout validating the store configuration. Consider adding basic validation (e.g., required fields likeHost,Auth.SecretRef.Credentials.Name) to catch configuration errors early.providers/v1/alibaba/logger.go (1)
29-33: Redundant iota declarations.Each constant uses
iotaseparately, which works but is unconventional. A single iota sequence is cleaner.Suggested simplification
const ( - logLevelWarn logLevel = iota - logLevelInfo logLevel = iota - logLevelDebug logLevel = iota + logLevelWarn logLevel = iota + logLevelInfo + logLevelDebug )apis/externalsecrets/v1/secretstore_types.go (1)
196-197: Missing descriptive comment for Passbolt provider.Other provider fields include a comment describing the provider's purpose (e.g., "Alibaba configures this store to sync secrets using Alibaba Cloud provider"). The Passbolt field lacks this documentation.
Suggested fix
+ // Passbolt configures this store to sync secrets using the Passbolt provider // +optional Passbolt *PassboltProvider `json:"passbolt,omitempty"`providers/v1/alibaba/kms_test.go (2)
127-132: Misleading variable name:successCasesincludes error cases.The slice contains both success and error scenarios (e.g.,
setAPIErr,setNilMockClient), makingsuccessCasesa misnomer. Consider renaming totestCasesfor clarity.Suggested fix
- successCases := []*keyManagementServiceTestCase{ + testCases := []*keyManagementServiceTestCase{ makeValidKMSTestCaseCustom(setSecretString), makeValidKMSTestCaseCustom(setCustomKey), makeValidKMSTestCaseCustom(setAPIErr), makeValidKMSTestCaseCustom(setNilMockClient), }Apply the same change at line 161.
181-237: Consider adding negative validation test cases.The validation tests only cover valid configurations. Adding tests for invalid stores (e.g., missing
RegionID, missing both auth methods, or providing both auth methods) would improve coverage.apis/externalsecrets/v1/secretsstore_passbolt_types.go (1)
1-36: Filename inconsistency: extra 's' in filename.The filename is
secretsstore_passbolt_types.gobut other provider type files follow the patternsecretstore_*_types.go(e.g.,secretstore_alibaba_types.go,secretstore_device42_types.go). Consider renaming for consistency.Rename file to:
secretstore_passbolt_types.goproviders/v1/passbolt/passbolt.go (1)
141-144: Consider implementing actual validation for better UX.The
Validate()method always returnsValidationResultUnknown. While this is safe, it means users won't get feedback about whether their Passbolt configuration is correct until they try to fetch a secret. Consider validating by callingCheckSessionor performing a test login.
|
@coderabbitai just stop my man. It's a revert, this code was sadly already there. But will be deleted in a 1-2 weeks again anyways. |
|
Tip For best results, initiate chat on the files or code changes.
If you'd like, I can pause automatic reviews for this PR entirely - just let me know! |



Reverts #5854
Restore Support for Three Unmaintained Secret Stores
This PR reverts the removal of three external secret providers (Alibaba Cloud, Device42, and Passbolt) that were previously marked as unmaintained. The changes restore complete provider support including:
Core Implementation:
Alibaba Provider:
Device42 Provider:
Passbolt Provider:
Testing & Documentation:
CRD & Registration:
All three providers are marked with "not maintained" status in their maintenance metadata.