mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
Team observers can browse global policies (#3737)
* Allow team observers to browse global policies * Add integration core test for team observer * Fix integration tests
This commit is contained in:
parent
ba64dc0003
commit
d4243d0a72
7 changed files with 80 additions and 11 deletions
|
|
@ -0,0 +1 @@
|
|||
* Team observers can read global policies (aka inherited policies).
|
||||
|
|
@ -73,6 +73,7 @@ The following table depicts various permissions levels in a team.
|
|||
| ------------------------------------------------------------ | -------- | ---------- | ------- |
|
||||
| Browse hosts assigned to team | ✅ | ✅ | ✅ |
|
||||
| Browse policies for hosts assigned to team | ✅ | ✅ | ✅ |
|
||||
| Browse global (inherited) policies | ✅ | ✅ | ✅ |
|
||||
| Filter hosts assigned to team using policies | ✅ | ✅ | ✅ |
|
||||
| Filter hosts assigned to team using labels | ✅ | ✅ | ✅ |
|
||||
| Target hosts assigned to team using labels | ✅ | ✅ | ✅ |
|
||||
|
|
|
|||
|
|
@ -429,11 +429,11 @@ allow {
|
|||
action == [read, write][_]
|
||||
}
|
||||
|
||||
# Team admin and maintainers can read global policies
|
||||
# Team admin, maintainers and observers can read global policies
|
||||
allow {
|
||||
is_null(object.team_id)
|
||||
object.type == "policy"
|
||||
team_role(subject, subject.teams[_].id) == [admin,maintainer][_]
|
||||
team_role(subject, subject.teams[_].id) == [admin,maintainer,observer][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -546,21 +546,21 @@ func TestAuthorizeCarves(t *testing.T) {
|
|||
func TestAuthorizePolicies(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
policy := &fleet.Policy{}
|
||||
globalPolicy := &fleet.Policy{}
|
||||
teamPolicy := &fleet.Policy{
|
||||
PolicyData: fleet.PolicyData{
|
||||
TeamID: ptr.Uint(1),
|
||||
},
|
||||
}
|
||||
runTestCases(t, []authTestCase{
|
||||
{user: test.UserNoRoles, object: policy, action: write, allow: false},
|
||||
{user: test.UserNoRoles, object: globalPolicy, action: write, allow: false},
|
||||
|
||||
{user: test.UserAdmin, object: policy, action: write, allow: true},
|
||||
{user: test.UserAdmin, object: policy, action: read, allow: true},
|
||||
{user: test.UserMaintainer, object: policy, action: write, allow: true},
|
||||
{user: test.UserMaintainer, object: policy, action: read, allow: true},
|
||||
{user: test.UserObserver, object: policy, action: write, allow: false},
|
||||
{user: test.UserObserver, object: policy, action: read, allow: true},
|
||||
{user: test.UserAdmin, object: globalPolicy, action: write, allow: true},
|
||||
{user: test.UserAdmin, object: globalPolicy, action: read, allow: true},
|
||||
{user: test.UserMaintainer, object: globalPolicy, action: write, allow: true},
|
||||
{user: test.UserMaintainer, object: globalPolicy, action: read, allow: true},
|
||||
{user: test.UserObserver, object: globalPolicy, action: write, allow: false},
|
||||
{user: test.UserObserver, object: globalPolicy, action: read, allow: true},
|
||||
|
||||
{user: test.UserAdmin, object: teamPolicy, action: write, allow: true},
|
||||
{user: test.UserAdmin, object: teamPolicy, action: read, allow: true},
|
||||
|
|
@ -583,6 +583,11 @@ func TestAuthorizePolicies(t *testing.T) {
|
|||
{user: test.UserTeamObserverTeam1, object: teamPolicy, action: read, allow: true},
|
||||
{user: test.UserTeamObserverTeam2, object: teamPolicy, action: write, allow: false},
|
||||
{user: test.UserTeamObserverTeam2, object: teamPolicy, action: read, allow: false},
|
||||
|
||||
// Team observers cannot write global policies.
|
||||
{user: test.UserTeamObserverTeam1, object: globalPolicy, action: write, allow: false},
|
||||
// Team observers can read global policies.
|
||||
{user: test.UserTeamObserverTeam1, object: globalPolicy, action: read, allow: true},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ func TestGlobalPoliciesAuth(t *testing.T) {
|
|||
"team observer",
|
||||
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserver}}},
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range testCases {
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ func TestAPIRoutesConflicts(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAPIRoutesMetrics(t *testing.T) {
|
||||
t.Skip()
|
||||
ds := new(mock.Store)
|
||||
|
||||
svc := newTestService(ds, nil, nil)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,17 @@ func (s *integrationTestSuite) TearDownTest() {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
globalPolicies, err := s.ds.ListGlobalPolicies(ctx)
|
||||
require.NoError(t, err)
|
||||
if len(globalPolicies) > 0 {
|
||||
var globalPolicyIDs []uint
|
||||
for _, gp := range globalPolicies {
|
||||
globalPolicyIDs = append(globalPolicyIDs, gp.ID)
|
||||
}
|
||||
_, err = s.ds.DeleteGlobalPolicies(ctx, globalPolicyIDs)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrations(t *testing.T) {
|
||||
|
|
@ -1997,6 +2008,7 @@ func (s *integrationTestSuite) TestGlobalPoliciesAutomationConfig() {
|
|||
}
|
||||
gpResp := globalPolicyResponse{}
|
||||
s.DoJSON("POST", "/api/v1/fleet/global/policies", gpParams, http.StatusOK, &gpResp)
|
||||
require.NotNil(t, gpResp.Policy)
|
||||
|
||||
s.DoRaw("PATCH", "/api/v1/fleet/config", []byte(fmt.Sprintf(`{
|
||||
"webhook_settings": {
|
||||
|
|
@ -2024,3 +2036,52 @@ func (s *integrationTestSuite) TestGlobalPoliciesAutomationConfig() {
|
|||
config = s.getConfig()
|
||||
require.Empty(t, config.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
}
|
||||
|
||||
// TestGlobalPoliciesBrowsing tests that team users can browse (read) global policies (see #3722).
|
||||
func (s *integrationTestSuite) TestGlobalPoliciesBrowsing() {
|
||||
t := s.T()
|
||||
|
||||
team, err := s.ds.NewTeam(context.Background(), &fleet.Team{
|
||||
ID: 42,
|
||||
Name: "team_for_global_policies_browsing",
|
||||
Description: "desc team1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
gpParams0 := globalPolicyRequest{
|
||||
Name: "global policy",
|
||||
Query: "select * from osquery;",
|
||||
}
|
||||
gpResp0 := globalPolicyResponse{}
|
||||
s.DoJSON("POST", "/api/v1/fleet/global/policies", gpParams0, http.StatusOK, &gpResp0)
|
||||
require.NotNil(t, gpResp0.Policy)
|
||||
|
||||
email := "team.observer@example.com"
|
||||
teamObserver := &fleet.User{
|
||||
Name: "team observer user",
|
||||
Email: email,
|
||||
GlobalRole: nil,
|
||||
Teams: []fleet.UserTeam{
|
||||
{
|
||||
Team: *team,
|
||||
Role: fleet.RoleObserver,
|
||||
},
|
||||
},
|
||||
}
|
||||
password := "p4ssw0rd."
|
||||
require.NoError(t, teamObserver.SetPassword(password, 10, 10))
|
||||
_, err = s.ds.NewUser(context.Background(), teamObserver)
|
||||
require.NoError(t, err)
|
||||
|
||||
oldToken := s.token
|
||||
s.token = s.getTestToken(email, password)
|
||||
t.Cleanup(func() {
|
||||
s.token = oldToken
|
||||
})
|
||||
|
||||
policiesResponse := listGlobalPoliciesResponse{}
|
||||
s.DoJSON("GET", "/api/v1/fleet/global/policies", nil, http.StatusOK, &policiesResponse)
|
||||
require.Len(t, policiesResponse.Policies, 1)
|
||||
assert.Equal(t, "global policy", policiesResponse.Policies[0].Name)
|
||||
assert.Equal(t, "select * from osquery;", policiesResponse.Policies[0].Query)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue