Allow GitOps user to list software (#44721)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #44696 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests - [X] QA'd all new/changed functionality manually - [X] reproduced issue on main branch (with software exceptions on and policies with software automation, `fleetctl gitops` failed for a gitops user with a 403) - [X] verified issue fixed on this branch -- `fleetctl gitops` synced successfully For unreleased bug fixes in a release candidate, one of: - [X] Confirmed that the fix is not expected to adversely impact load test results <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Expanded GitOps permissions to read and list software inventory, software titles, installable software, and maintained apps at both global and team scopes; adjusted related read behaviors and capitalization in messaging. * **Tests** * Updated and added authorization and integration tests to reflect the new GitOps read/list behavior across software-related and maintained-app endpoints, including team-scoped scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Added permissions for GitOps user to list software titles
|
||||
@@ -86,6 +86,20 @@ func TestListMaintainedAppsAuth(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"global gitops",
|
||||
&fleet.User{GlobalRole: ptr.String(fleet.RoleGitOps)},
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"team gitops",
|
||||
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleGitOps}}},
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
var forbiddenError *authz.Forbidden
|
||||
@@ -224,6 +238,20 @@ func TestGetMaintainedAppAuth(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"global gitops",
|
||||
&fleet.User{GlobalRole: ptr.String(fleet.RoleGitOps)},
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"team gitops",
|
||||
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleGitOps}}},
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
var forbiddenError *authz.Forbidden
|
||||
|
||||
+17
-17
@@ -740,10 +740,10 @@ allow {
|
||||
# Software
|
||||
##
|
||||
|
||||
# Global admins, maintainers, technician, observers, and observer_plus can read all software.
|
||||
# Global admins, maintainers, technician, observers, observer_plus and gitops can read all software.
|
||||
allow {
|
||||
object.type == "software_inventory"
|
||||
subject.global_role == [admin, maintainer, technician, observer, observer_plus][_]
|
||||
subject.global_role == [admin, maintainer, technician, observer, observer_plus, gitops][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
@@ -754,32 +754,32 @@ allow {
|
||||
action == write
|
||||
}
|
||||
|
||||
# Team admins, maintainers, technician, observers and observer_plus can read all software in their teams.
|
||||
# Team admins, maintainers, technician, observers, observer_plus and gitops can read all software in their teams.
|
||||
allow {
|
||||
not is_null(object.team_id)
|
||||
object.type == "software_inventory"
|
||||
team_role(subject, object.team_id) == [admin, maintainer, technician, observer, observer_plus][_]
|
||||
team_role(subject, object.team_id) == [admin, maintainer, technician, observer, observer_plus, gitops][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
# Global admins and maintainers can read all maintained apps.
|
||||
# Global admins and maintainers and gitops can read all maintained apps.
|
||||
allow {
|
||||
object.type == "maintained_app"
|
||||
subject.global_role == [admin, maintainer][_]
|
||||
subject.global_role == [admin, maintainer, gitops][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
# Team admins and maintainers can read all maintained apps (no team constraint, unlike installers)
|
||||
# Team admins and maintainers and gitops can read all maintained apps (no team constraint, unlike installers)
|
||||
allow {
|
||||
object.type == "maintained_app"
|
||||
team_role(subject, subject.teams[_].id) == [admin, maintainer][_]
|
||||
team_role(subject, subject.teams[_].id) == [admin, maintainer, gitops][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
# Global admins, maintainers, and technicians can read any installable entity (software installer or VPP app)
|
||||
# Global admins, maintainers, technicians and gitops can read any installable entity (software installer or VPP app)
|
||||
allow {
|
||||
object.type == "installable_entity"
|
||||
subject.global_role == [admin, maintainer, technician][_]
|
||||
subject.global_role == [admin, maintainer, technician, gitops][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
@@ -790,11 +790,11 @@ allow {
|
||||
action == write
|
||||
}
|
||||
|
||||
# Team admins, maintainers, and technicians can read any installable entity (software installer or VPP app) in their teams.
|
||||
# Team admins, maintainers, technicians and gitops can read any installable entity (software installer or VPP app) in their teams.
|
||||
allow {
|
||||
not is_null(object.team_id)
|
||||
object.type == "installable_entity"
|
||||
team_role(subject, object.team_id) == [admin, maintainer, technician][_]
|
||||
team_role(subject, object.team_id) == [admin, maintainer, technician, gitops][_]
|
||||
action == read
|
||||
}
|
||||
|
||||
@@ -865,9 +865,9 @@ allow {
|
||||
|
||||
# Global admins, maintainers, technicians, and gitops can resend MDM config profiles.
|
||||
#
|
||||
# GitOps doesn't really need permissions to resend to specific hosts,
|
||||
# gitops doesn't really need permissions to resend to specific hosts,
|
||||
# but we will keep this as-is to not break any workflows that might be using a
|
||||
# GitOps token to do a resend.
|
||||
# gitops token to do a resend.
|
||||
allow {
|
||||
object.type == "mdm_config_profile"
|
||||
subject.global_role == [admin, maintainer, technician, gitops][_]
|
||||
@@ -894,9 +894,9 @@ allow {
|
||||
|
||||
# Team admins, maintainers, technicians, and gitops can resend MDM config profiles on their teams.
|
||||
#
|
||||
# GitOps doesn't really need permissions to resend to specific hosts,
|
||||
# gitops doesn't really need permissions to resend to specific hosts,
|
||||
# but we will keep this as-is to not break any workflows that might be using a
|
||||
# GitOps token to do a resend.
|
||||
# gitops token to do a resend.
|
||||
allow {
|
||||
not is_null(object.team_id)
|
||||
object.team_id != 0
|
||||
@@ -1250,7 +1250,7 @@ allow {
|
||||
##
|
||||
# Certificate Authorities
|
||||
##
|
||||
# Global admins and GitOps can configure, read, list, and read secrets of certificate authorities.
|
||||
# Global admins and gitops can configure, read, list, and read secrets of certificate authorities.
|
||||
allow {
|
||||
object.type == "certificate_authority"
|
||||
subject.global_role == [admin, gitops][_]
|
||||
|
||||
@@ -643,6 +643,8 @@ func TestAuthorizeSoftwareInventory(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
softwareInventory := &fleet.AuthzSoftwareInventory{}
|
||||
team1SoftwareInventory := &fleet.AuthzSoftwareInventory{TeamID: ptr.Uint(1)}
|
||||
team2SoftwareInventory := &fleet.AuthzSoftwareInventory{TeamID: ptr.Uint(2)}
|
||||
runTestCases(t, []authTestCase{
|
||||
{user: nil, object: softwareInventory, action: read, allow: false},
|
||||
{user: test.UserNoRoles, object: softwareInventory, action: read, allow: false},
|
||||
@@ -651,8 +653,11 @@ func TestAuthorizeSoftwareInventory(t *testing.T) {
|
||||
{user: test.UserObserver, object: softwareInventory, action: read, allow: true},
|
||||
{user: test.UserObserverPlus, object: softwareInventory, action: read, allow: true},
|
||||
{user: test.UserTechnician, object: softwareInventory, action: read, allow: true},
|
||||
{user: test.UserGitOps, object: softwareInventory, action: read, allow: false},
|
||||
{user: test.UserGitOps, object: softwareInventory, action: read, allow: true},
|
||||
{user: test.UserGitOps, object: team1SoftwareInventory, action: read, allow: true},
|
||||
{user: test.UserTeamGitOpsTeam1, object: softwareInventory, action: read, allow: false},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team1SoftwareInventory, action: read, allow: true},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team2SoftwareInventory, action: read, allow: false},
|
||||
{user: test.UserTeamTechnicianTeam1, object: softwareInventory, action: read, allow: false},
|
||||
})
|
||||
}
|
||||
@@ -713,18 +718,16 @@ func TestAuthorizeSoftwareInstaller(t *testing.T) {
|
||||
{user: test.UserTechnician, object: team2Installer, action: read, allow: true},
|
||||
{user: test.UserTechnician, object: team2Installer, action: write, allow: false},
|
||||
|
||||
// TODO: confirm gitops permissions
|
||||
{user: test.UserGitOps, object: noTeamInstaller, action: read, allow: false},
|
||||
{user: test.UserGitOps, object: noTeamInstaller, action: read, allow: true},
|
||||
{user: test.UserGitOps, object: noTeamInstaller, action: write, allow: true},
|
||||
{user: test.UserGitOps, object: team1Installer, action: read, allow: false},
|
||||
{user: test.UserGitOps, object: team1Installer, action: read, allow: true},
|
||||
{user: test.UserGitOps, object: team1Installer, action: write, allow: true},
|
||||
{user: test.UserGitOps, object: team2Installer, action: read, allow: false},
|
||||
{user: test.UserGitOps, object: team2Installer, action: read, allow: true},
|
||||
{user: test.UserGitOps, object: team2Installer, action: write, allow: true},
|
||||
|
||||
// TODO: confirm gitops permissions
|
||||
{user: test.UserTeamGitOpsTeam1, object: noTeamInstaller, action: read, allow: false},
|
||||
{user: test.UserTeamGitOpsTeam1, object: noTeamInstaller, action: write, allow: false},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team1Installer, action: read, allow: false},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team1Installer, action: read, allow: true},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team1Installer, action: write, allow: true},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team2Installer, action: read, allow: false},
|
||||
{user: test.UserTeamGitOpsTeam1, object: team2Installer, action: write, allow: false},
|
||||
@@ -766,6 +769,30 @@ func TestAuthorizeSoftwareInstaller(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizeMaintainedApp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
maintainedApp := &fleet.MaintainedApp{}
|
||||
runTestCases(t, []authTestCase{
|
||||
{user: nil, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserNoRoles, object: maintainedApp, action: read, allow: false},
|
||||
|
||||
{user: test.UserAdmin, object: maintainedApp, action: read, allow: true},
|
||||
{user: test.UserMaintainer, object: maintainedApp, action: read, allow: true},
|
||||
{user: test.UserObserver, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserObserverPlus, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserTechnician, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserGitOps, object: maintainedApp, action: read, allow: true},
|
||||
|
||||
{user: test.UserTeamAdminTeam1, object: maintainedApp, action: read, allow: true},
|
||||
{user: test.UserTeamMaintainerTeam1, object: maintainedApp, action: read, allow: true},
|
||||
{user: test.UserTeamObserverTeam1, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserTeamObserverPlusTeam1, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserTeamTechnicianTeam1, object: maintainedApp, action: read, allow: false},
|
||||
{user: test.UserTeamGitOpsTeam1, object: maintainedApp, action: read, allow: true},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizeHostSoftwareInstallerResult(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -7019,14 +7019,13 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
// Attempt to delete a label, should allow.
|
||||
s.DoJSON("DELETE", "/api/latest/fleet/labels/foo2", fleet.DeleteLabelRequest{}, http.StatusOK, &fleet.DeleteLabelResponse{})
|
||||
|
||||
// Attempt to list all software, should fail.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/versions", listSoftwareRequest{}, http.StatusForbidden, &listSoftwareVersionsResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software", listSoftwareRequest{}, http.StatusForbidden, &listSoftwareResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/count", countSoftwareRequest{}, http.StatusForbidden, &countSoftwareResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusForbidden, &listSoftwareTitlesResponse{})
|
||||
// Listing software is allowed for gitops so they can reconcile software state.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/versions", listSoftwareRequest{}, http.StatusOK, &listSoftwareVersionsResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software", listSoftwareRequest{}, http.StatusOK, &listSoftwareResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/count", countSoftwareRequest{}, http.StatusOK, &countSoftwareResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &listSoftwareTitlesResponse{})
|
||||
// Getting a single software title or version still requires Host:list, which gitops doesn't have.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles/1", getSoftwareTitleRequest{}, http.StatusForbidden, &getSoftwareTitleResponse{})
|
||||
|
||||
// Attempt to list a software, should fail.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/1", getSoftwareRequest{}, http.StatusForbidden, &getSoftwareResponse{})
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/versions/1", getSoftwareRequest{}, http.StatusForbidden, &getSoftwareResponse{})
|
||||
|
||||
@@ -7575,6 +7574,13 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
},
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusForbidden, &countTargetsResponse{})
|
||||
|
||||
// Listing software titles for the team it owns is allowed.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &listSoftwareTitlesResponse{}, "team_id", fmt.Sprint(t1.ID))
|
||||
// Listing software titles globally (no team) is forbidden for team gitops.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusForbidden, &listSoftwareTitlesResponse{})
|
||||
// Listing software titles for a team it does not own is forbidden.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusForbidden, &listSoftwareTitlesResponse{}, "team_id", fmt.Sprint(t2.ID))
|
||||
}
|
||||
|
||||
func (s *integrationEnterpriseTestSuite) TestDesktopEndpointWithInvalidPolicy() {
|
||||
|
||||
@@ -57,8 +57,8 @@ func TestSoftwareInstallersAuth(t *testing.T) {
|
||||
{"global observer+ team 0", test.UserObserverPlus, ptr.Uint(0), true, true},
|
||||
{"global observer+ team", test.UserObserverPlus, ptr.Uint(1), true, true},
|
||||
{"global gitops no team", test.UserGitOps, nil, true, false},
|
||||
{"global gitops team 0", test.UserGitOps, ptr.Uint(0), true, false},
|
||||
{"global gitops team", test.UserGitOps, ptr.Uint(1), true, false},
|
||||
{"global gitops team 0", test.UserGitOps, ptr.Uint(0), false, false},
|
||||
{"global gitops team", test.UserGitOps, ptr.Uint(1), false, false},
|
||||
{"team admin no team", test.UserTeamAdminTeam1, nil, true, true},
|
||||
{"team admin team 0", test.UserTeamAdminTeam1, ptr.Uint(0), true, true},
|
||||
{"team admin team", test.UserTeamAdminTeam1, ptr.Uint(1), false, false},
|
||||
@@ -77,7 +77,7 @@ func TestSoftwareInstallersAuth(t *testing.T) {
|
||||
{"team observer+ other team", test.UserTeamObserverPlusTeam2, ptr.Uint(1), true, true},
|
||||
{"team gitops no team", test.UserTeamGitOpsTeam1, nil, true, true},
|
||||
{"team gitops team 0", test.UserTeamGitOpsTeam1, ptr.Uint(0), true, true},
|
||||
{"team gitops team", test.UserTeamGitOpsTeam1, ptr.Uint(1), true, false},
|
||||
{"team gitops team", test.UserTeamGitOpsTeam1, ptr.Uint(1), false, false},
|
||||
{"team gitops other team", test.UserTeamGitOpsTeam2, ptr.Uint(1), true, true},
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
user *fleet.User
|
||||
shouldFailGlobalRead bool
|
||||
shouldFailTeamRead bool
|
||||
shouldFailGetByID bool
|
||||
}{
|
||||
{
|
||||
name: "global-admin",
|
||||
@@ -81,6 +82,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
},
|
||||
{
|
||||
name: "global-maintainer",
|
||||
@@ -90,6 +92,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
},
|
||||
{
|
||||
name: "global-observer",
|
||||
@@ -99,6 +102,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
},
|
||||
{
|
||||
name: "team-admin-belongs-to-team",
|
||||
@@ -111,6 +115,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
},
|
||||
{
|
||||
name: "team-maintainer-belongs-to-team",
|
||||
@@ -123,6 +128,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
},
|
||||
{
|
||||
name: "team-observer-belongs-to-team",
|
||||
@@ -135,6 +141,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
},
|
||||
{
|
||||
name: "team-admin-does-not-belong-to-team",
|
||||
@@ -147,6 +154,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
},
|
||||
{
|
||||
name: "team-maintainer-does-not-belong-to-team",
|
||||
@@ -159,6 +167,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
},
|
||||
{
|
||||
name: "team-observer-does-not-belong-to-team",
|
||||
@@ -171,6 +180,45 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
},
|
||||
{
|
||||
// GitOps can list/count software but cannot fetch a single version
|
||||
// because SoftwareByID also requires Host:list permission.
|
||||
name: "global-gitops",
|
||||
user: &fleet.User{
|
||||
ID: 1,
|
||||
GlobalRole: ptr.String(fleet.RoleGitOps),
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: true,
|
||||
},
|
||||
{
|
||||
name: "team-gitops-belongs-to-team",
|
||||
user: &fleet.User{
|
||||
ID: 1,
|
||||
Teams: []fleet.UserTeam{{
|
||||
Team: fleet.Team{ID: 1},
|
||||
Role: fleet.RoleGitOps,
|
||||
}},
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: true,
|
||||
},
|
||||
{
|
||||
name: "team-gitops-does-not-belong-to-team",
|
||||
user: &fleet.User{
|
||||
ID: 1,
|
||||
Teams: []fleet.UserTeam{{
|
||||
Team: fleet.Team{ID: 2},
|
||||
Role: fleet.RoleGitOps,
|
||||
}},
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -197,7 +245,7 @@ func TestServiceSoftwareInventoryAuth(t *testing.T) {
|
||||
checkAuthErr(t, tc.shouldFailTeamRead, err)
|
||||
|
||||
_, err = svc.SoftwareByID(ctx, 1, ptr.Uint(1), false)
|
||||
checkAuthErr(t, tc.shouldFailTeamRead, err)
|
||||
checkAuthErr(t, tc.shouldFailGetByID, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
user *fleet.User
|
||||
shouldFailGlobalRead bool
|
||||
shouldFailTeamRead bool
|
||||
shouldFailGetByID bool
|
||||
shouldFailWrite bool
|
||||
}{
|
||||
{
|
||||
@@ -46,6 +47,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
shouldFailWrite: false,
|
||||
},
|
||||
{
|
||||
@@ -56,6 +58,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -66,6 +69,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -79,6 +83,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -92,6 +97,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -105,6 +111,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: false,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -118,6 +125,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -131,6 +139,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
@@ -144,6 +153,48 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
// GitOps can list software titles but cannot fetch a single title
|
||||
// because SoftwareTitleByID also requires Host:list permission.
|
||||
name: "global-gitops",
|
||||
user: &fleet.User{
|
||||
ID: 1,
|
||||
GlobalRole: ptr.String(fleet.RoleGitOps),
|
||||
},
|
||||
shouldFailGlobalRead: false,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: true,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
name: "team-gitops-belongs-to-team",
|
||||
user: &fleet.User{
|
||||
ID: 1,
|
||||
Teams: []fleet.UserTeam{{
|
||||
Team: fleet.Team{ID: 1},
|
||||
Role: fleet.RoleGitOps,
|
||||
}},
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: false,
|
||||
shouldFailGetByID: true,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
{
|
||||
name: "team-gitops-does-not-belong-to-team",
|
||||
user: &fleet.User{
|
||||
ID: 1,
|
||||
Teams: []fleet.UserTeam{{
|
||||
Team: fleet.Team{ID: 2},
|
||||
Role: fleet.RoleGitOps,
|
||||
}},
|
||||
},
|
||||
shouldFailGlobalRead: true,
|
||||
shouldFailTeamRead: true,
|
||||
shouldFailGetByID: true,
|
||||
shouldFailWrite: true,
|
||||
},
|
||||
} {
|
||||
@@ -172,7 +223,7 @@ func TestServiceSoftwareTitlesAuth(t *testing.T) {
|
||||
|
||||
// Get a software title for a team
|
||||
_, err = svc.SoftwareTitleByID(ctx, 1, ptr.Uint(1))
|
||||
checkAuthErr(t, tc.shouldFailTeamRead, err)
|
||||
checkAuthErr(t, tc.shouldFailGetByID, err)
|
||||
|
||||
// Update a software title's name
|
||||
err = svc.UpdateSoftwareName(ctx, 1, "2 Chrome 2 Furious")
|
||||
|
||||
@@ -77,8 +77,8 @@ func TestVPPAuth(t *testing.T) {
|
||||
{"global observer team", test.UserObserver, ptr.Uint(1), true, true, true},
|
||||
{"global observer+ no team", test.UserObserverPlus, nil, true, true, true},
|
||||
{"global observer+ team", test.UserObserverPlus, ptr.Uint(1), true, true, true},
|
||||
{"global gitops no team", test.UserGitOps, nil, true, false, false},
|
||||
{"global gitops team", test.UserGitOps, ptr.Uint(1), true, false, false},
|
||||
{"global gitops no team", test.UserGitOps, nil, false, false, false},
|
||||
{"global gitops team", test.UserGitOps, ptr.Uint(1), false, false, false},
|
||||
{"team admin no team", test.UserTeamAdminTeam1, nil, true, true, false},
|
||||
{"team admin team", test.UserTeamAdminTeam1, ptr.Uint(1), false, false, false},
|
||||
{"team admin other team", test.UserTeamAdminTeam2, ptr.Uint(1), true, true, false},
|
||||
@@ -92,7 +92,7 @@ func TestVPPAuth(t *testing.T) {
|
||||
{"team observer+ team", test.UserTeamObserverPlusTeam1, ptr.Uint(1), true, true, true},
|
||||
{"team observer+ other team", test.UserTeamObserverPlusTeam2, ptr.Uint(1), true, true, true},
|
||||
{"team gitops no team", test.UserTeamGitOpsTeam1, nil, true, true, false},
|
||||
{"team gitops team", test.UserTeamGitOpsTeam1, ptr.Uint(1), true, false, false},
|
||||
{"team gitops team", test.UserTeamGitOpsTeam1, ptr.Uint(1), false, false, false},
|
||||
{"team gitops other team", test.UserTeamGitOpsTeam2, ptr.Uint(1), true, true, false},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user