Skip to content
This repository was archived by the owner on Nov 27, 2024. It is now read-only.

Commit 8788cb4

Browse files
authored
impl has-direct-access label (#293)
Signed-off-by: Andy Sadler <ansadler@redhat.com>
1 parent 09d6681 commit 8788cb4

18 files changed

Lines changed: 329 additions & 73 deletions

server/api/v1alpha1/workspace_types.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ const (
2929
// WorkspaceVisibilityPrivate Private value for Workspaces visibility
3030
WorkspaceVisibilityPrivate WorkspaceVisibility = "private"
3131

32-
// LabelInternalDomain if the requesting user is the owner of the workspace
32+
// LabelIsOwner if the requesting user is the owner of the workspace
3333
LabelIsOwner string = workspacesv1alpha1.LabelInternalDomain + "is-owner"
34+
// LabelHasDirectAccess if the requesting user has access to the workspace
35+
// via a direct grant or via public-viewer
36+
LabelHasDirectAccess string = workspacesv1alpha1.LabelInternalDomain + "has-direct-access"
3437
)
3538

3639
// WorkspaceSpec defines the desired state of Workspace
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright 2024 The Workspaces Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package clientinterface
18+
19+
import (
20+
"context"
21+
22+
workspacesv1alpha1 "github.com/konflux-workspaces/workspaces/operator/api/v1alpha1"
23+
restworkspacesv1alpha1 "github.com/konflux-workspaces/workspaces/server/api/v1alpha1"
24+
"sigs.k8s.io/controller-runtime/pkg/client"
25+
)
26+
27+
// SpaceKey comprises a Space name, with a mandatory owner.
28+
type SpaceKey struct {
29+
Owner string
30+
Name string
31+
}
32+
33+
// InternalWorkspacesReader is the definition for a InternalWorkspaces Read Client
34+
type InternalWorkspacesReader interface {
35+
GetAsUser(context.Context, string, SpaceKey, *workspacesv1alpha1.InternalWorkspace, ...client.GetOption) error
36+
ListAsUser(context.Context, string, *workspacesv1alpha1.InternalWorkspaceList) error
37+
}
38+
39+
// InternalWorkspacesMapper is the definition for a InternalWorkspaces/Workspaces Mapper
40+
type InternalWorkspacesMapper interface {
41+
InternalWorkspaceListToWorkspaceList(*workspacesv1alpha1.InternalWorkspaceList) (*restworkspacesv1alpha1.WorkspaceList, error)
42+
InternalWorkspaceToWorkspace(*workspacesv1alpha1.InternalWorkspace) (*restworkspacesv1alpha1.Workspace, error)
43+
WorkspaceToInternalWorkspace(*restworkspacesv1alpha1.Workspace) (*workspacesv1alpha1.InternalWorkspace, error)
44+
}
45+
46+
type DirectAccessChecker interface {
47+
UserHasDirectAccess(context.Context, string, string) (bool, error)
48+
}
49+
50+
type InternalWorkspacesReadClient interface {
51+
InternalWorkspacesReader
52+
DirectAccessChecker
53+
}

server/persistence/iwclient/iwclient.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import (
66
"sigs.k8s.io/controller-runtime/pkg/client"
77

88
toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
9+
"github.com/konflux-workspaces/workspaces/server/persistence/clientinterface"
10+
"github.com/konflux-workspaces/workspaces/server/persistence/mapper"
911
)
1012

11-
// SpaceKey comprises a Space name, with a mandatory owner.
12-
type SpaceKey struct {
13-
Owner string
14-
Name string
15-
}
13+
var (
14+
_ clientinterface.InternalWorkspacesReadClient = &Client{}
15+
_ clientinterface.InternalWorkspacesMapper = mapper.Default
16+
)
1617

1718
type Client struct {
1819
backend client.Reader
@@ -30,7 +31,7 @@ func New(backend client.Reader, workspacesNamespace, kubesawNamespace string) *C
3031
}
3132
}
3233

33-
func (c *Client) existsSpaceBindingForUserAndSpace(ctx context.Context, user, space string) (bool, error) {
34+
func (c *Client) UserHasDirectAccess(ctx context.Context, user, space string) (bool, error) {
3435
ml := client.MatchingLabels{
3536
toolchainv1alpha1.SpaceBindingMasterUserRecordLabelKey: user,
3637
toolchainv1alpha1.SpaceBindingSpaceLabelKey: space,

server/persistence/iwclient/iwclient_read.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sigs.k8s.io/controller-runtime/pkg/client"
88

99
"github.com/konflux-workspaces/workspaces/server/log"
10+
"github.com/konflux-workspaces/workspaces/server/persistence/clientinterface"
1011
"github.com/konflux-workspaces/workspaces/server/persistence/internal/cache"
1112

1213
toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
@@ -23,7 +24,7 @@ var (
2324
func (c *Client) GetAsUser(
2425
ctx context.Context,
2526
user string,
26-
key SpaceKey,
27+
key clientinterface.SpaceKey,
2728
workspace *workspacesv1alpha1.InternalWorkspace,
2829
opts ...client.GetOption,
2930
) error {
@@ -44,7 +45,7 @@ func (c *Client) GetAsUser(
4445

4546
// check if user has direct visibility on the space
4647
l.Debug("InternalWorkspace is private, checking for a SpaceBinding for the user")
47-
ok, err := c.existsSpaceBindingForUserAndSpace(ctx, user, w.GetName())
48+
ok, err := c.UserHasDirectAccess(ctx, user, w.GetName())
4849
if err != nil {
4950
l.Error("error retrieving SpaceBindings for InternalWorkspace", "error", err)
5051
return err

server/persistence/iwclient/iwclient_read_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
1313
workspacesv1alpha1 "github.com/konflux-workspaces/workspaces/operator/api/v1alpha1"
1414

15+
"github.com/konflux-workspaces/workspaces/server/persistence/clientinterface"
1516
"github.com/konflux-workspaces/workspaces/server/persistence/iwclient"
1617
)
1718

@@ -47,7 +48,7 @@ var _ = Describe("Read", func() {
4748
It("should not return the workspace in read", func() {
4849
// when
4950
var w workspacesv1alpha1.InternalWorkspace
50-
key := iwclient.SpaceKey{Owner: "owner", Name: "no-space-binding"}
51+
key := clientinterface.SpaceKey{Owner: "owner", Name: "no-space-binding"}
5152
err := c.GetAsUser(ctx, "owner", key, &w)
5253

5354
// then
@@ -85,7 +86,7 @@ var _ = Describe("Read", func() {
8586
It("should not return the workspace in read", func() {
8687
// when
8788
var w workspacesv1alpha1.InternalWorkspace
88-
key := iwclient.SpaceKey{Owner: "owner", Name: "no-label"}
89+
key := clientinterface.SpaceKey{Owner: "owner", Name: "no-label"}
8990
err := c.GetAsUser(ctx, "owner", key, &w)
9091

9192
// then
@@ -150,7 +151,7 @@ var _ = Describe("Read", func() {
150151
It("should be returned in read", func() {
151152
// when
152153
var rw workspacesv1alpha1.InternalWorkspace
153-
key := iwclient.SpaceKey{Owner: "owner-user", Name: "owner-ws"}
154+
key := clientinterface.SpaceKey{Owner: "owner-user", Name: "owner-ws"}
154155
err := c.GetAsUser(ctx, "owner-user", key, &rw)
155156

156157
// then
@@ -161,7 +162,7 @@ var _ = Describe("Read", func() {
161162
It("should NOT be returned in read of not-owner-user workspace", func() {
162163
// when
163164
rw := workspacesv1alpha1.InternalWorkspace{}
164-
key := iwclient.SpaceKey{Owner: "owner-user", Name: "owner-ws"}
165+
key := clientinterface.SpaceKey{Owner: "owner-user", Name: "owner-ws"}
165166
err := c.GetAsUser(ctx, "not-owner-user", key, &rw)
166167

167168
// then
@@ -242,7 +243,7 @@ var _ = Describe("Read", func() {
242243
for _, w := range ww {
243244
// when
244245
var rw workspacesv1alpha1.InternalWorkspace
245-
key := iwclient.SpaceKey{Owner: w.Status.Owner.Username, Name: w.Spec.DisplayName}
246+
key := clientinterface.SpaceKey{Owner: w.Status.Owner.Username, Name: w.Spec.DisplayName}
246247
err := c.GetAsUser(ctx, w.Status.Owner.Username, key, &rw)
247248
Expect(err).NotTo(HaveOccurred())
248249

@@ -255,7 +256,7 @@ var _ = Describe("Read", func() {
255256
for _, w := range ww {
256257
// when
257258
rw := workspacesv1alpha1.InternalWorkspace{}
258-
key := iwclient.SpaceKey{Owner: w.Status.Owner.Username, Name: w.Spec.DisplayName}
259+
key := clientinterface.SpaceKey{Owner: w.Status.Owner.Username, Name: w.Spec.DisplayName}
259260
err := c.GetAsUser(ctx, "not-owner-user", key, &rw)
260261

261262
// then
@@ -340,7 +341,7 @@ var _ = Describe("Read", func() {
340341
It("is returned in read", func() {
341342
// when
342343
var w workspacesv1alpha1.InternalWorkspace
343-
key := iwclient.SpaceKey{Owner: "owner-user", Name: wName}
344+
key := clientinterface.SpaceKey{Owner: "owner-user", Name: wName}
344345
err := c.GetAsUser(ctx, "owner-user", key, &w)
345346

346347
// then
@@ -408,7 +409,7 @@ var _ = Describe("Read", func() {
408409
It("is returned in other-user's read", func() {
409410
// when
410411
var w workspacesv1alpha1.InternalWorkspace
411-
key := iwclient.SpaceKey{Owner: "owner-user", Name: wName}
412+
key := clientinterface.SpaceKey{Owner: "owner-user", Name: wName}
412413
err := c.GetAsUser(ctx, "other-user", key, &w)
413414
Expect(err).NotTo(HaveOccurred())
414415

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright 2024 The Workspaces Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package mutate
18+
19+
import (
20+
"context"
21+
"strconv"
22+
23+
restworkspacesv1alpha1 "github.com/konflux-workspaces/workspaces/server/api/v1alpha1"
24+
"github.com/konflux-workspaces/workspaces/server/persistence/clientinterface"
25+
)
26+
27+
// Applies the has-direct-access label if the user "accessor" has access via
28+
// public viewer or via a direct binding to the workspace
29+
func ApplyHasDirectAccessLabel(
30+
ctx context.Context,
31+
client clientinterface.DirectAccessChecker,
32+
workspace *restworkspacesv1alpha1.Workspace,
33+
accessor string,
34+
) error {
35+
if workspace == nil {
36+
return nil
37+
}
38+
if workspace.Labels == nil {
39+
workspace.Labels = map[string]string{}
40+
}
41+
42+
ok, err := client.UserHasDirectAccess(ctx, accessor, workspace.Namespace)
43+
if err != nil {
44+
return err
45+
}
46+
47+
workspace.Labels[restworkspacesv1alpha1.LabelHasDirectAccess] = strconv.FormatBool(ok)
48+
49+
return nil
50+
}

server/persistence/mutate/owner.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ limitations under the License.
1616

1717
package mutate
1818

19-
import restworkspacesv1alpha1 "github.com/konflux-workspaces/workspaces/server/api/v1alpha1"
19+
import (
20+
"strconv"
21+
22+
restworkspacesv1alpha1 "github.com/konflux-workspaces/workspaces/server/api/v1alpha1"
23+
)
2024

2125
// Applies the is-owner internal label to a workspace
2226
func ApplyIsOwnerLabel(workspace *restworkspacesv1alpha1.Workspace, owner string) {
@@ -29,10 +33,6 @@ func ApplyIsOwnerLabel(workspace *restworkspacesv1alpha1.Workspace, owner string
2933
workspace.Labels = map[string]string{}
3034
}
3135

32-
switch workspace.Namespace {
33-
case owner:
34-
workspace.Labels[restworkspacesv1alpha1.LabelIsOwner] = "true"
35-
default:
36-
workspace.Labels[restworkspacesv1alpha1.LabelIsOwner] = "false"
37-
}
36+
isOwner := workspace.Namespace == owner
37+
workspace.Labels[restworkspacesv1alpha1.LabelIsOwner] = strconv.FormatBool(isOwner)
3838
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package readclient_test
22

3-
import "github.com/konflux-workspaces/workspaces/server/persistence/readclient"
3+
import (
4+
"github.com/konflux-workspaces/workspaces/server/persistence/clientinterface"
5+
)
46

57
//go:generate mockgen -source=interface_test.go -destination=mocks/readclient.go -package=mocks -exclude_interfaces=FakeIWMapper
68
type FakeIWReadClient interface {
7-
readclient.InternalWorkspacesReadClient
9+
clientinterface.InternalWorkspacesReadClient
810
}
911

1012
//go:generate mockgen -source=interface_test.go -destination=mocks/mapper.go -package=mocks -exclude_interfaces=FakeIWReadClient
1113
type FakeIWMapper interface {
12-
readclient.InternalWorkspacesMapper
14+
clientinterface.InternalWorkspacesMapper
1315
}

server/persistence/readclient/mocks/readclient.go

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/persistence/readclient/readclient.go

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,18 @@ import (
55

66
"k8s.io/client-go/rest"
77
"sigs.k8s.io/controller-runtime/pkg/cache"
8-
"sigs.k8s.io/controller-runtime/pkg/client"
98

9+
"github.com/konflux-workspaces/workspaces/server/persistence/clientinterface"
1010
icache "github.com/konflux-workspaces/workspaces/server/persistence/internal/cache"
1111
"github.com/konflux-workspaces/workspaces/server/persistence/iwclient"
1212
"github.com/konflux-workspaces/workspaces/server/persistence/mapper"
13-
14-
workspacesv1alpha1 "github.com/konflux-workspaces/workspaces/operator/api/v1alpha1"
15-
restworkspacesv1alpha1 "github.com/konflux-workspaces/workspaces/server/api/v1alpha1"
16-
)
17-
18-
var (
19-
_ InternalWorkspacesReadClient = &iwclient.Client{}
20-
_ InternalWorkspacesMapper = mapper.Default
2113
)
2214

23-
// InternalWorkspacesReadClient is the definition for a InternalWorkspaces Read Client
24-
type InternalWorkspacesReadClient interface {
25-
GetAsUser(context.Context, string, iwclient.SpaceKey, *workspacesv1alpha1.InternalWorkspace, ...client.GetOption) error
26-
ListAsUser(context.Context, string, *workspacesv1alpha1.InternalWorkspaceList) error
27-
}
28-
29-
// InternalWorkspacesMapper is the definition for a InternalWorkspaces/Workspaces Mapper
30-
type InternalWorkspacesMapper interface {
31-
InternalWorkspaceListToWorkspaceList(*workspacesv1alpha1.InternalWorkspaceList) (*restworkspacesv1alpha1.WorkspaceList, error)
32-
InternalWorkspaceToWorkspace(*workspacesv1alpha1.InternalWorkspace) (*restworkspacesv1alpha1.Workspace, error)
33-
WorkspaceToInternalWorkspace(*restworkspacesv1alpha1.Workspace) (*workspacesv1alpha1.InternalWorkspace, error)
34-
}
35-
3615
// ReadClient implements the WorkspaceLister and WorkspaceReader interfaces
3716
// using a client.Reader as backend
3817
type ReadClient struct {
39-
internalClient InternalWorkspacesReadClient
40-
mapper InternalWorkspacesMapper
18+
internalClient clientinterface.InternalWorkspacesReadClient
19+
mapper clientinterface.InternalWorkspacesMapper
4120
}
4221

4322
// NewDefaultWithCache creates a controller-runtime cache and use it as KubeReadClient's backend.
@@ -53,12 +32,12 @@ func NewDefaultWithCache(ctx context.Context, cfg *rest.Config, workspacesNamesp
5332
}
5433

5534
// NewDefaultWithInternalClient creates a new KubeReadClient with the provided backend and default InternalWorkspaces/Workspaces mapper
56-
func NewDefaultWithInternalClient(internalClient InternalWorkspacesReadClient) *ReadClient {
35+
func NewDefaultWithInternalClient(internalClient clientinterface.InternalWorkspacesReadClient) *ReadClient {
5736
return New(internalClient, mapper.Default)
5837
}
5938

6039
// New creates a new KubeReadClient with the provided backend and a custom InternalWorkspaces/Workspaces mapper
61-
func New(internalClient InternalWorkspacesReadClient, mapper InternalWorkspacesMapper) *ReadClient {
40+
func New(internalClient clientinterface.InternalWorkspacesReadClient, mapper clientinterface.InternalWorkspacesMapper) *ReadClient {
6241
return &ReadClient{
6342
internalClient: internalClient,
6443
mapper: mapper,

0 commit comments

Comments
 (0)