Matt Keeler 59cb12c798
Migrate the Endpoints controller to use the controller cache (#20241)
* Add cache resource decoding helpers

* Implement a common package for workload selection facilities. This includes:

   * Controller cache Index
   * ACL hooks
   * Dependency Mapper to go from workload to list of resources which select it
   * Dependency Mapper to go from a resource which selects workloads to all the workloads it selects.

* Update the endpoints controller to use the cache instead of custom mappers.

Co-authored-by: R.B. Boyer <4903+rboyer@users.noreply.github.com>
2024-01-18 17:52:52 -05:00

124 lines
3.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package workloadselector
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/resourcetest"
pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1"
"github.com/hashicorp/consul/proto-public/pbresource"
)
func TestACLHooks(t *testing.T) {
suite.Run(t, new(aclHookSuite))
}
type aclHookSuite struct {
suite.Suite
hooks *resource.ACLHooks
authz *acl.MockAuthorizer
ctx *acl.AuthorizerContext
res *pbresource.Resource
}
func (suite *aclHookSuite) SetupTest() {
suite.authz = new(acl.MockAuthorizer)
suite.authz.On("ToAllowAuthorizer").Return(acl.AllowAuthorizer{Authorizer: suite.authz, AccessorID: "862270e5-7d7b-4583-98bc-4d14810cc158"})
suite.ctx = &acl.AuthorizerContext{}
acl.DefaultEnterpriseMeta().FillAuthzContext(suite.ctx)
suite.hooks = ACLHooks[*pbcatalog.Service]()
suite.res = resourcetest.Resource(pbcatalog.ServiceType, "foo").
WithData(suite.T(), &pbcatalog.Service{
Workloads: &pbcatalog.WorkloadSelector{
Prefixes: []string{"api-"},
Names: []string{"bar"},
},
}).
WithTenancy(resource.DefaultNamespacedTenancy()).
Build()
}
func (suite *aclHookSuite) TeardownTest() {
suite.authz.AssertExpectations(suite.T())
}
func (suite *aclHookSuite) TestReadHook_Allowed() {
suite.authz.On("ServiceRead", "foo", suite.ctx).
Return(acl.Allow).
Once()
require.NoError(suite.T(), suite.hooks.Read(suite.authz, suite.ctx, suite.res.Id, nil))
}
func (suite *aclHookSuite) TestReadHook_Denied() {
suite.authz.On("ServiceRead", "foo", suite.ctx).
Return(acl.Deny).
Once()
require.Error(suite.T(), suite.hooks.Read(suite.authz, suite.ctx, suite.res.Id, nil))
}
func (suite *aclHookSuite) TestWriteHook_ServiceWriteDenied() {
suite.authz.On("ServiceWrite", "foo", suite.ctx).
Return(acl.Deny).
Once()
require.Error(suite.T(), suite.hooks.Write(suite.authz, suite.ctx, suite.res))
}
func (suite *aclHookSuite) TestWriteHook_ServiceReadNameDenied() {
suite.authz.On("ServiceWrite", "foo", suite.ctx).
Return(acl.Allow).
Once()
suite.authz.On("ServiceRead", "bar", suite.ctx).
Return(acl.Deny).
Once()
require.Error(suite.T(), suite.hooks.Write(suite.authz, suite.ctx, suite.res))
}
func (suite *aclHookSuite) TestWriteHook_ServiceReadPrefixDenied() {
suite.authz.On("ServiceWrite", "foo", suite.ctx).
Return(acl.Allow).
Once()
suite.authz.On("ServiceRead", "bar", suite.ctx).
Return(acl.Allow).
Once()
suite.authz.On("ServiceReadPrefix", "api-", suite.ctx).
Return(acl.Deny).
Once()
require.Error(suite.T(), suite.hooks.Write(suite.authz, suite.ctx, suite.res))
}
func (suite *aclHookSuite) TestWriteHook_Allowed() {
suite.authz.On("ServiceWrite", "foo", suite.ctx).
Return(acl.Allow).
Once()
suite.authz.On("ServiceRead", "bar", suite.ctx).
Return(acl.Allow).
Once()
suite.authz.On("ServiceReadPrefix", "api-", suite.ctx).
Return(acl.Allow).
Once()
require.NoError(suite.T(), suite.hooks.Write(suite.authz, suite.ctx, suite.res))
}