Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f269f75
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 4, 2026
5eee547
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 5, 2026
e9f8935
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 5, 2026
25cebe9
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 5, 2026
46e54de
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 5, 2026
0da577b
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 5, 2026
f393f42
fix(test): fix unit tests for identity provider validating webhook se…
akafazov Feb 6, 2026
bec2524
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 6, 2026
1e8cbcd
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 6, 2026
a16b829
Merge remote-tracking branch 'origin/feat/prevent-creation-idp' into …
makdeniss Feb 6, 2026
8b1264e
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 6, 2026
46c468a
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 6, 2026
c080a71
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 6, 2026
46d2cd5
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 6, 2026
0f5e684
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 6, 2026
6635504
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 6, 2026
2212f06
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 6, 2026
fdf3fb3
feat: prevent creation of an IDP resource (#286)
makdeniss Feb 6, 2026
c4d9f30
feat: centralize secrets for tests (#286)
makdeniss Feb 9, 2026
d9c446f
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 9, 2026
6dde27e
feat: centralize secrets for tests (#286)
makdeniss Feb 9, 2026
0cb5331
feat: add more logging (#286)
makdeniss Feb 9, 2026
195dd64
fix typo in dir name
akafazov Feb 10, 2026
1d5aa23
fix path in subroutines tests
akafazov Feb 10, 2026
a188270
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 10, 2026
fdd973a
feat: revert certificate related changes (#286)
makdeniss Feb 10, 2026
ff1dc73
feat: revert certificate related changes (#286)
makdeniss Feb 10, 2026
ceaff63
feat: revert certificate related changes (#286)
makdeniss Feb 10, 2026
92d386e
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 13, 2026
1170b37
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 13, 2026
ff6e9b1
Merge branch 'main' into feat/prevent-creation-idp
makdeniss Feb 20, 2026
ac06969
feat: update OCM component version (#286)
makdeniss Feb 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ tasks:
cmds:
- test -s {{.LOCAL_BIN}}/kind || GOBIN=$(pwd)/{{.LOCAL_BIN}} go install sigs.k8s.io/kind@{{ .KIND_VERSION }}
- export PATH=$(pwd)/{{.LOCAL_BIN}}:$PATH

## Development
mockery:
deps: [setup:mockery]
cmds:
- "{{.LOCAL_BIN}}/mockery"

kindtest:
deps: [setup:mkcert, setup:kind]
env:
Expand Down Expand Up @@ -93,7 +93,7 @@ tasks:
go test -timeout 10m -coverprofile=cover.out ./... {{.ADDITIONAL_COMMAND_ARGS}}
fi
ignore_error: false

manifests:
deps: [setup:controller-gen]
cmds:
Expand Down Expand Up @@ -148,7 +148,7 @@ tasks:
bump-versions-internal:
internal: true
vars:
SERVICES:
SERVICES:
- account-operator
- account-ui
- apeiro-example-content
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: identityproviderconfiguration-validator.webhooks.core.platform-mesh.io
webhooks:
- admissionReviewVersions:
- v1
clientConfig:
caBundle: {{ index . "identityproviderconfiguration-validator.webhooks.core.platform-mesh.io.ca-bundle" }}
url: https://security-operator-webhook.platform-mesh-system.svc.cluster.local:9443/validate-core-platform-mesh-io-v1alpha1-identityproviderconfiguration
failurePolicy: Fail
name: identityproviderconfiguration.validation.platform-mesh.io
rules:
- apiGroups:
- core.platform-mesh.io
apiVersions:
- v1alpha1
operations:
- CREATE
- UPDATE
resources:
- identityproviderconfigurations
sideEffects: None
timeoutSeconds: 30
17 changes: 17 additions & 0 deletions pkg/subroutines/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ var AccountOperatorWebhookSecretNamespace = "platform-mesh-system"
var DefaultCASecretKey = "ca.crt"
var AccountOperatorMutatingWebhookName = "account-operator.webhooks.core.platform-mesh.io"
var AccountOperatorValidatingWebhookName = "organization-validator.webhooks.core.platform-mesh.io"

var SecurityOperatorWebhookCASecretName = "security-operator-ca-secret"
var IdentityProviderValidatingWebhookName = "identityproviderconfiguration-validator.webhooks.core.platform-mesh.io"
var AccountOperatorWorkspace = "root:platform-mesh-system"
var DefaultProviderConnections = []corev1alpha1.ProviderConnection{
{
Expand Down Expand Up @@ -77,6 +80,20 @@ var DEFAULT_VALIDATING_WEBHOOK_CONFIGURATION = corev1alpha1.WebhookConfiguration
},
}

var DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION = corev1alpha1.WebhookConfiguration{
SecretRef: corev1alpha1.SecretReference{
Name: SecurityOperatorWebhookCASecretName,
Namespace: AccountOperatorWebhookSecretNamespace,
},
SecretData: DefaultCASecretKey,
WebhookRef: corev1alpha1.KCPAPIVersionKindRef{
ApiVersion: "admissionregistration.k8s.io/v1",
Kind: "ValidatingWebhookConfiguration",
Name: IdentityProviderValidatingWebhookName,
Path: AccountOperatorWorkspace,
},
}

var DEFAULT_WAIT_CONFIG = corev1alpha1.WaitConfig{
ResourceTypes: []corev1alpha1.ResourceType{
{
Expand Down
12 changes: 11 additions & 1 deletion pkg/subroutines/kcpsetup.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (r *KcpsetupSubroutine) Process(ctx context.Context, runtimeObj runtimeobje
return ctrl.Result{}, errors.NewOperatorError(errors.New("FrontProxy is not ready"), true, true)
}

// Build kcp kubeonfig
// Build kcp kubeconfig
cfg, err := buildKubeconfig(ctx, r.client, r.kcpUrl)
if err != nil {
log.Error().Err(err).Msg("Failed to build kubeconfig")
Expand Down Expand Up @@ -240,6 +240,16 @@ func (r *KcpsetupSubroutine) getCABundleInventory(
b64Data := base64.StdEncoding.EncodeToString(caData)
caBundles[key] = b64Data

// Get Identity Provider validating webhook CA bundle (security-operator webhook)
ipdValidatingWebhookConfig := DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION
ipdCaData, err := r.getCaBundle(ctx, &ipdValidatingWebhookConfig)
if err != nil {
log.Error().Err(err).Msg("Failed to get Identity Provider ValidatingWebhook CA bundle")
return nil, errors.Wrap(err, "Failed to get Identity Provider ValidatingWebhook CA bundle")
}
ipdKey := fmt.Sprintf("%s.ca-bundle", ipdValidatingWebhookConfig.WebhookRef.Name)
caBundles[ipdKey] = base64.StdEncoding.EncodeToString(ipdCaData)

// Get validating webhook CA bundle
validatingWebhookConfig := DEFAULT_VALIDATING_WEBHOOK_CONFIGURATION
validatingCaData, err := r.getCaBundle(ctx, &validatingWebhookConfig)
Expand Down
86 changes: 85 additions & 1 deletion pkg/subroutines/kcpsetup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,21 @@ func (s *KcpsetupTestSuite) Test_getCABundleInventory() {
}).
Once() // Only called once due to caching

// Mock the identity provider validating webhook secret lookup (called once due to caching)
s.clientMock.EXPECT().
Get(mock.Anything, types.NamespacedName{
Name: subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.SecretRef.Name,
Namespace: subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.SecretRef.Namespace,
}, mock.AnythingOfType("*v1.Secret")).
RunAndReturn(func(ctx context.Context, nn types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
secret := obj.(*corev1.Secret)
secret.Data = map[string][]byte{
subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.SecretData: expectedCaData,
}
return nil
}).
Once() // Only called once due to caching

s.clientMock.EXPECT().
Get(mock.Anything, types.NamespacedName{
Name: "domain-certificate-ca",
Expand Down Expand Up @@ -181,14 +196,21 @@ func (s *KcpsetupTestSuite) Test_getCABundleInventory() {
s.Assert().Contains(inventory, validatingKey)
s.Assert().Equal(expectedB64, inventory[validatingKey])

// Check identity provider validating webhook CA bundle
ipdValidatingKey := subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.WebhookRef.Name + ".ca-bundle"
s.Assert().Contains(inventory, ipdValidatingKey)
s.Assert().Equal(expectedB64, inventory[ipdValidatingKey])

// Second call should use cache (no additional mock calls expected)
inventory2, err2 := s.testObj.GetCABundleInventory(ctx)
s.Assert().NoError(err2)
s.Assert().NotNil(inventory2)
s.Assert().Contains(inventory2, mutatingKey)
s.Assert().Contains(inventory2, validatingKey)
s.Assert().Contains(inventory2, ipdValidatingKey)
s.Assert().Equal(expectedB64, inventory2[mutatingKey])
s.Assert().Equal(expectedB64, inventory2[validatingKey])
s.Assert().Equal(expectedB64, inventory2[ipdValidatingKey])

s.clientMock.AssertExpectations(s.T())

Expand Down Expand Up @@ -369,6 +391,20 @@ func (s *KcpsetupTestSuite) TestProcess() {
return nil
}).Once() // Only called once due to caching

// Mock the identity provider validating webhook CA secret lookup
s.clientMock.EXPECT().
Get(mock.Anything, types.NamespacedName{
Name: subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.SecretRef.Name,
Namespace: subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.SecretRef.Namespace,
}, mock.AnythingOfType("*v1.Secret")).
RunAndReturn(func(ctx context.Context, nn types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
secret := obj.(*corev1.Secret)
secret.Data = map[string][]byte{
subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION.SecretData: []byte("test-ca-data"),
}
return nil
}).Once()

// Mock the secondary webhook server cert lookup (called once since we cache results)
s.clientMock.EXPECT().
Get(mock.Anything, types.NamespacedName{
Expand All @@ -389,6 +425,10 @@ func (s *KcpsetupTestSuite) TestProcess() {
NewKcpClient(mock.Anything, "root").
Return(mockKcpClient, nil)

s.helperMock.EXPECT().
NewKcpClient(mock.Anything, "root:platform-mesh").
Return(mockKcpClient, nil)

s.helperMock.EXPECT().
NewKcpClient(mock.Anything, "root:platform-mesh-system").
Return(mockKcpClient, nil)
Expand Down Expand Up @@ -588,6 +628,7 @@ func (s *KcpsetupTestSuite) TestCreateWorkspaces() {
// Mock both webhook secret lookups for CA bundle inventory
webhookConfig := subroutines.DEFAULT_WEBHOOK_CONFIGURATION
validatingWebhookConfig := subroutines.DEFAULT_VALIDATING_WEBHOOK_CONFIGURATION
ipdValidatingWebhookConfig := subroutines.DEFAULT_IDENTITY_PROVIDER_VALIDATING_WEBHOOK_CONFIGURATION

// Mock the mutating webhook secret lookup (called once due to caching)
mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Expand All @@ -603,7 +644,7 @@ func (s *KcpsetupTestSuite) TestCreateWorkspaces() {
Return(nil).
Once()

// Mock the mutating webhook secret lookup (called once due to caching)
// Mock the domain certificate CA lookup
mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Name: "domain-certificate-ca",
Namespace: webhookConfig.SecretRef.Namespace,
Expand All @@ -618,6 +659,20 @@ func (s *KcpsetupTestSuite) TestCreateWorkspaces() {
}).
Return(nil)

// Mock the identity provider validating webhook secret lookup (called once due to caching)
mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Name: ipdValidatingWebhookConfig.SecretRef.Name,
Namespace: ipdValidatingWebhookConfig.SecretRef.Namespace,
}, mock.AnythingOfType("*v1.Secret")).
Run(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) {
sec := obj.(*corev1.Secret)
sec.Data = map[string][]byte{
ipdValidatingWebhookConfig.SecretData: []byte("dummy-ca-data"),
}
}).
Return(nil).
Once()

// Mock the validating webhook secret lookup (called once due to caching)
mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Name: validatingWebhookConfig.SecretRef.Name,
Expand Down Expand Up @@ -694,6 +749,35 @@ func (s *KcpsetupTestSuite) TestCreateWorkspaces() {
Return(nil).
Once()

// Mock the domain certificate CA lookup
mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Name: "domain-certificate-ca",
Namespace: webhookConfig.SecretRef.Namespace,
}, mock.AnythingOfType("*v1.Secret")).
Run(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) {
sec := obj.(*corev1.Secret)
sec.Data = map[string][]byte{
"ca.crt": []byte("test-ca-data"),
"tls.crt": []byte("test-tls-crt"),
"tls.key": []byte("test-tls-key"),
}
}).
Return(nil)

// Mock the identity provider validating webhook secret lookup (called once due to caching)
mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Name: ipdValidatingWebhookConfig.SecretRef.Name,
Namespace: ipdValidatingWebhookConfig.SecretRef.Namespace,
}, mock.AnythingOfType("*v1.Secret")).
Run(func(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) {
sec := obj.(*corev1.Secret)
sec.Data = map[string][]byte{
ipdValidatingWebhookConfig.SecretData: []byte("dummy-ca-data"),
}
}).
Return(nil).
Once()

mockedK8sClient.EXPECT().Get(mock.Anything, types.NamespacedName{
Name: validatingWebhookConfig.SecretRef.Name,
Namespace: validatingWebhookConfig.SecretRef.Namespace,
Expand Down
2 changes: 1 addition & 1 deletion pkg/subroutines/subroutine_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,6 @@ func (s *HelperTestSuite) TestApplyManifestFromFile() {
KCP: config.OperatorConfig{}.KCP,
}
ctx := context.WithValue(context.TODO(), keys.ConfigCtxKey, operatorCfg)
err = subroutines.ApplyManifestFromFile(ctx, "../../manifests/kcp/03-platform-mesh-system/mutatingwebhookconfiguration-admissionregistration.k8s.io.yaml", cl, templateData, "root:platform-mesh-system", &corev1alpha1.PlatformMesh{})
err = subroutines.ApplyManifestFromFile(ctx, "../../manifests/kcp/04-platform-mesh-system/mutatingwebhookconfiguration-admissionregistration.k8s.io.yaml", cl, templateData, "root:platform-mesh-system", &corev1alpha1.PlatformMesh{})
s.Assert().Nil(err)
}
2 changes: 1 addition & 1 deletion test/e2e/kind/kustomize/components/ocm/component.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ spec:
namespace: default
repositoryRef:
name: platform-mesh
semver: 0.2.0
semver: 0.3.0-build.268
11 changes: 11 additions & 0 deletions test/e2e/kind/suite_kind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,16 @@ func (s *KindTestSuite) createSecrets(ctx context.Context, dirRootPath []byte) e
},
Type: corev1.SecretTypeTLS,
}
security_operator_ca := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "security-operator-ca-secret",
Namespace: "platform-mesh-system",
},
Data: map[string][]byte{
"ca.crt": caRootBytes,
},
Type: corev1.SecretTypeOpaque,
}
domain_certificate_ca := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "domain-certificate-ca",
Expand All @@ -315,6 +325,7 @@ func (s *KindTestSuite) createSecrets(ctx context.Context, dirRootPath []byte) e
keycloak_admin,
domain_certificate,
rbac_webhook_ca,
security_operator_ca,
domain_certificate_ca,
pms_domain_certificate,
}
Expand Down
Loading