Skip to content

Commit

Permalink
feat: add JoinURL field to Team Spec (#636)
Browse files Browse the repository at this point in the history
* feat: add JoinURL field to Team Spec

* Automatic generation of CRD API Docs

* fix lint suggestions

* Automatic generation of CRD API Docs

* Automatic generation of CRD API Docs

* Automatic generation of CRD API Docs

* feat: enforce http and https urls for JoinURL in Team, describe valid URL in error message

* Automatic generation of CRD API Docs

---------

Co-authored-by: k.zagorski <k.zagorski@accenture.com>
Co-authored-by: CRD API Docs Bot <crd_api_docs_bot@github.com>
  • Loading branch information
3 people authored Oct 25, 2024
1 parent 3a4ac0b commit 1ba5c64
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 8 deletions.
3 changes: 3 additions & 0 deletions charts/manager/crds/greenhouse.sap_teams.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ spec:
description:
description: Description provides additional details of the team.
type: string
joinUrl:
description: URL to join the IdP group.
type: string
mappedIdPGroup:
description: IdP group id matching team.
type: string
Expand Down
22 changes: 22 additions & 0 deletions docs/reference/api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,17 @@ <h3 id="greenhouse.sap/v1alpha1.Team">Team
<p>IdP group id matching team.</p>
</td>
</tr>
<tr>
<td>
<code>joinUrl</code><br>
<em>
string
</em>
</td>
<td>
<p>URL to join the IdP group.</p>
</td>
</tr>
</table>
</td>
</tr>
Expand Down Expand Up @@ -3262,6 +3273,17 @@ <h3 id="greenhouse.sap/v1alpha1.TeamSpec">TeamSpec
<p>IdP group id matching team.</p>
</td>
</tr>
<tr>
<td>
<code>joinUrl</code><br>
<em>
string
</em>
</td>
<td>
<p>URL to join the IdP group.</p>
</td>
</tr>
</tbody>
</table>
</div>
Expand Down
5 changes: 4 additions & 1 deletion docs/reference/api/openapi.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
openapi: 3.0.0
info:
title: Greenhouse
version: bfd6d09
version: a72ea02
description: PlusOne operations platform
paths:
/TeamMembership:
Expand Down Expand Up @@ -1063,6 +1063,9 @@ components:
description:
description: Description provides additional details of the team.
type: string
joinUrl:
description: URL to join the IdP group.
type: string
mappedIdPGroup:
description: IdP group id matching team.
type: string
Expand Down
23 changes: 21 additions & 2 deletions pkg/admission/team_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,21 @@ func ValidateCreateTeam(ctx context.Context, c client.Client, o runtime.Object)
if !ok {
return nil, nil
}
return nil, validateGreenhouseLabels(team, ctx, c)
if err := validateGreenhouseLabels(team, ctx, c); err != nil {
return nil, err
}
return nil, validateJoinURL(team)
}

func ValidateUpdateTeam(ctx context.Context, c client.Client, _, o runtime.Object) (admission.Warnings, error) {
team, ok := o.(*greenhousev1alpha1.Team)
if !ok {
return nil, nil
}
return nil, validateGreenhouseLabels(team, ctx, c)
if err := validateGreenhouseLabels(team, ctx, c); err != nil {
return nil, err
}
return nil, validateJoinURL(team)
}

func ValidateDeleteTeam(_ context.Context, _ client.Client, _ runtime.Object) (admission.Warnings, error) {
Expand Down Expand Up @@ -89,3 +95,16 @@ func validateGreenhouseLabels(team *greenhousev1alpha1.Team, ctx context.Context
}
return nil
}

func validateJoinURL(team *greenhousev1alpha1.Team) error {
if team.Spec.JoinURL == "" {
return nil
}
if !validateURL(team.Spec.JoinURL) {
return apierrors.NewInvalid(team.GroupVersionKind().GroupKind(), team.GetName(), field.ErrorList{
field.Invalid(field.NewPath("spec").Child("joinUrl"), team.Spec.JoinURL,
"JoinURL must be a valid 'http:' or 'https:' URL, like 'https://example.com'."),
})
}
return nil
}
34 changes: 29 additions & 5 deletions pkg/admission/team_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,21 @@ var _ = Describe("Validate Team Creation", func() {
teamFaultyGreenhouseLabels := teamStub
teamFaultyGreenhouseLabels.SetName("faulty-greenhouse-labels")

By("correctly allowing creation of a team with non-greenhouse labels", func() {
teamValidJoinURL := teamStub
teamValidJoinURL.SetName("valid-joinurl")

teamInvalidJoinURL := teamStub
teamInvalidJoinURL.SetName("invalid-joinurl")

By("correctly allowing creation of a team with non-greenhouse labels", func() {
teamNoGreenhouseLabels.SetLabels(map[string]string{
"some-key": "some-value",
})
err := test.K8sClient.Create(test.Ctx, &teamNoGreenhouseLabels)
Expect(err).ToNot(HaveOccurred(), "There should be no error when creating a team with non-greenhouse labels")
})

By("correctly allowing creation of a tema with greenhouse labels that use whitelabeled labels and/or existing pluginDefinition names", func() {

By("correctly allowing creation of a team with greenhouse labels that use whitelabeled labels and/or existing pluginDefinition names", func() {
teamGreenhouseLabels.SetLabels(map[string]string{
"greenhouse.sap/test-plugindefinition-1": "true",
"greenhouse.sap/support-group": "true",
Expand All @@ -92,7 +96,6 @@ var _ = Describe("Validate Team Creation", func() {
})

By("correctly denying creation of a team with greenhouse labels that use non-existing pluginDefinition names", func() {

teamFaultyGreenhouseLabels.SetLabels(map[string]string{
"greenhouse.sap/test-plugindefinition-3": "true",
})
Expand Down Expand Up @@ -129,6 +132,27 @@ var _ = Describe("Validate Team Creation", func() {
Expect(err.Error()).To(ContainSubstring("Only pluginDefinition names as greenhouse labels allowed."))
})

By("correctly allowing create of a team with valid JoinURL", func() {
teamValidJoinURL.Spec.JoinURL = "https://example.com/resource"
err := test.K8sClient.Create(test.Ctx, &teamValidJoinURL)
Expect(err).ToNot(HaveOccurred(), "There should be no error when creating a team with valid JoinURL")
})
By("correctly denying create of a team with invalid JoinURL", func() {
teamInvalidJoinURL.Spec.JoinURL = "testvalue"
err := test.K8sClient.Create(test.Ctx, &teamInvalidJoinURL)
Expect(err).To(HaveOccurred(), "There should be an error when creating a team with invalid JoinURL")
Expect(err.Error()).To(ContainSubstring("JoinURL must be a valid 'http:' or 'https:' URL, like 'https://example.com'."))
})
By("correctly allowing update of a team with valid JoinURL", func() {
teamValidJoinURL.Spec.JoinURL = "http://1.1.1.1:80"
err := test.K8sClient.Update(test.Ctx, &teamValidJoinURL)
Expect(err).ToNot(HaveOccurred(), "There should be no error when updating a team with valid JoinURL")
})
By("correctly denying update of a team with invalid JoinURL", func() {
teamValidJoinURL.Spec.JoinURL = "/example/1"
err := test.K8sClient.Update(test.Ctx, &teamValidJoinURL)
Expect(err).To(HaveOccurred(), "There should be an error when updating a team with invalid JoinURL")
Expect(err.Error()).To(ContainSubstring("JoinURL must be a valid 'http:' or 'https:' URL, like 'https://example.com'."))
})
})

})
9 changes: 9 additions & 0 deletions pkg/admission/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package admission

import (
"context"
"net/url"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
Expand Down Expand Up @@ -103,6 +104,14 @@ func validateImmutableField(oldValue, newValue string, path *field.Path) *field.
return nil
}

func validateURL(str string) bool {
parsedURL, err := url.Parse(str)
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
return false
}
return parsedURL.Scheme == "http" || parsedURL.Scheme == "https"
}

// logAdmissionRequest logs the AdmissionRequest.
// This is necessary to audit log the AdmissionRequest independently of the api server audit logs.
func logAdmissionRequest(ctx context.Context) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/greenhouse/v1alpha1/team_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type TeamSpec struct {
Description string `json:"description,omitempty"`
// IdP group id matching team.
MappedIDPGroup string `json:"mappedIdPGroup,omitempty"`
// URL to join the IdP group.
JoinURL string `json:"joinUrl,omitempty"`
}

// TeamStatus defines the observed state of Team
Expand Down

0 comments on commit 1ba5c64

Please sign in to comment.