Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[main&2.10.3] Add schema links and resource methods for resource verb patch #450

Merged
merged 2 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 8 additions & 0 deletions pkg/resources/common/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func formatter(summarycache *summarycache.SummaryCache, asl accesscontrol.Access
}
hasUpdate := accessSet.Grants("update", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())
hasDelete := accessSet.Grants("delete", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())
hasPatch := accessSet.Grants("patch", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())

selfLink := selfLink(gvr, meta)

Expand All @@ -118,6 +119,13 @@ func formatter(summarycache *summarycache.SummaryCache, asl accesscontrol.Access
} else {
delete(resource.Links, "remove")
}
if hasPatch {
if attributes.DisallowMethods(resource.Schema)[http.MethodPatch] {
resource.Links["patch"] = "blocked"
}
} else {
delete(resource.Links, "patch")
}

if unstr, ok := resource.APIObject.Object.(*unstructured.Unstructured); ok {
// with the sql cache, these were already added by the indexer. However, the sql cache
Expand Down
82 changes: 82 additions & 0 deletions pkg/resources/common/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ func Test_formatterLinks(t *testing.T) {
hasGet bool
hasUpdate bool
hasRemove bool
hasPatch bool
}
tests := []struct {
name string
Expand Down Expand Up @@ -935,6 +936,81 @@ func Test_formatterLinks(t *testing.T) {
"view": "/api/v1/namespaces/example-ns/pods/example-pod",
},
},
{
name: "patch permissions",
hasUser: true,
permissions: &permissions{
hasPatch: true,
},
schema: &types.APISchema{
Schema: &schemas.Schema{
ID: "example",
Attributes: map[string]interface{}{
"group": "apps",
"version": "v1",
"resource": "deployments",
},
},
},
apiObject: types.APIObject{
ID: "example",
Object: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "example-deployment",
Namespace: "example-ns",
},
},
},
currentLinks: map[string]string{
"default": "defaultVal",
"patch": "/v1/apps.deployments/example-ns/example-deployment",
"view": "/apis/apps/v1/namespaces/example-ns/deployments/example-deployment",
},
wantLinks: map[string]string{
"default": "defaultVal",
"patch": "/v1/apps.deployments/example-ns/example-deployment",
"view": "/apis/apps/v1/namespaces/example-ns/deployments/example-deployment",
},
},
{
name: "patch permissions, but blocked",
hasUser: true,
permissions: &permissions{
hasPatch: true,
},
schema: &types.APISchema{
Schema: &schemas.Schema{
ID: "example",
Attributes: map[string]interface{}{
"group": "apps",
"version": "v1",
"resource": "deployments",
"disallowMethods": map[string]bool{
http.MethodPatch: true,
},
},
},
},
apiObject: types.APIObject{
ID: "example",
Object: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "example-deployment",
Namespace: "example-ns",
},
},
},
currentLinks: map[string]string{
"default": "defaultVal",
"patch": "/v1/apps.deployments/example-ns/example-deployment",
"view": "/apis/apps/v1/namespaces/example-ns/deployments/example-deployment",
},
wantLinks: map[string]string{
"default": "defaultVal",
"patch": "blocked",
"view": "/apis/apps/v1/namespaces/example-ns/deployments/example-deployment",
},
},
}

for _, test := range tests {
Expand Down Expand Up @@ -964,6 +1040,12 @@ func Test_formatterLinks(t *testing.T) {
ResourceName: meta.GetName(),
})
}
if test.permissions.hasPatch {
accessSet.Add("patch", gvr.GroupResource(), accesscontrol.Access{
Namespace: meta.GetNamespace(),
ResourceName: meta.GetName(),
})
}
asl.EXPECT().AccessFor(&defaultUserInfo).Return(&accessSet)
} else {
asl.EXPECT().AccessFor(&defaultUserInfo).Return(nil).AnyTimes()
Expand Down
3 changes: 3 additions & 0 deletions pkg/schema/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ func (c *Collection) schemasForSubject(access *accesscontrol.AccessSet) (*types.
if verbAccess.AnyVerb("create") {
s.CollectionMethods = append(s.CollectionMethods, allowed(http.MethodPost))
}
if verbAccess.AnyVerb("patch") {
s.ResourceMethods = append(s.ResourceMethods, allowed(http.MethodPatch))
}

if len(s.CollectionMethods) == 0 && len(s.ResourceMethods) == 0 {
continue
Expand Down
11 changes: 10 additions & 1 deletion pkg/schema/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ func TestSchemas(t *testing.T) {
errDesired: false,
},
},
{
name: "basic patch schema test",
config: schemaTestConfig{
permissionVerbs: []string{"patch"},
desiredResourceVerbs: []string{"PATCH"},
desiredCollectionVerbs: []string{},
errDesired: false,
},
},
}
for _, test := range tests {
test := test
Expand Down Expand Up @@ -162,7 +171,7 @@ func makeSchema(resourceType string) *types.APISchema {
"group": testGroup,
"version": testVersion,
"resource": resourceType,
"verbs": []string{"get", "list", "watch", "delete", "update", "create"},
"verbs": []string{"get", "list", "watch", "delete", "update", "create", "patch"},
},
},
}
Expand Down