fleet/server/service/team_schedule_test.go
Victor Lyuboslavsky 913a5904c8
Move NewActivity to activity bounded context (#39521)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #38536 

This PR moves all logic to create new activities to activity bounded
context.
The old service and ActivityModule methods are not facades that route to
the new activity bounded context. The facades will be removed in a
subsequent PR.

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added webhook support for activity events with configurable endpoint
and enable/disable settings.
* Enhanced automation-initiated activity creation without requiring a
user context.
* Improved activity service architecture with centralized creation and
management.

* **Improvements**
* Refactored activity creation to use a dedicated service layer for
better separation of concerns.
* Added support for host-specific and automation-originated activities.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-25 14:11:03 -06:00

170 lines
4.5 KiB
Go

package service
import (
"context"
"testing"
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mock"
"github.com/fleetdm/fleet/v4/server/ptr"
)
func TestTeamScheduleAuth(t *testing.T) {
ds := new(mock.Store)
svc, ctx := newTestService(t, ds, nil, nil)
ds.ListQueriesFunc = func(ctx context.Context, opt fleet.ListQueryOptions) ([]*fleet.Query, int, int, *fleet.PaginationMetadata, error) {
return nil, 0, 0, nil, nil
}
ds.QueryFunc = func(ctx context.Context, id uint) (*fleet.Query, error) {
if id == 99 { // for testing modify and delete of a schedule
return &fleet.Query{
Name: "foobar",
Query: "SELECT 1;",
TeamID: ptr.Uint(1),
}, nil
}
return &fleet.Query{ // for testing creation of a schedule
Name: "foobar",
Query: "SELECT 1;",
// TeamID is set to nil because a query must be global to be able to be
// scheduled on a team by the deprecated APIs.
TeamID: nil,
}, nil
}
ds.SaveQueryFunc = func(ctx context.Context, query *fleet.Query, shouldDiscardResults bool, shouldDeleteStats bool) error {
return nil
}
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{}, nil
}
ds.NewQueryFunc = func(ctx context.Context, query *fleet.Query, opts ...fleet.OptionalArg) (*fleet.Query, error) {
return &fleet.Query{}, nil
}
ds.DeleteQueryFunc = func(ctx context.Context, teamID *uint, name string) error {
return nil
}
testCases := []struct {
name string
user *fleet.User
shouldFailWrite bool
shouldFailRead bool
}{
{
"global admin",
&fleet.User{
GlobalRole: ptr.String(fleet.RoleAdmin),
},
false,
false,
},
{
"global maintainer",
&fleet.User{GlobalRole: ptr.String(fleet.RoleMaintainer)},
false,
false,
},
{
"global observer",
&fleet.User{GlobalRole: ptr.String(fleet.RoleObserver)},
true,
false, // global observer can view all queries and scheduled queries.
},
{
"global observer+",
&fleet.User{GlobalRole: ptr.String(fleet.RoleObserverPlus)},
true,
false, // global observer+ can view all queries and scheduled queries.
},
{
"global gitops",
&fleet.User{GlobalRole: ptr.String(fleet.RoleGitOps)},
false,
false,
},
{
"team admin, belongs to team",
&fleet.User{
Teams: []fleet.UserTeam{{
Team: fleet.Team{ID: 1},
Role: fleet.RoleAdmin,
}},
},
false,
false,
},
{
"team maintainer, belongs to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleMaintainer}}},
false,
false,
},
{
"team observer, belongs to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserver}}},
true,
false,
},
{
"team observer+, belongs to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleObserverPlus}}},
true,
false,
},
{
"team gitops, belongs to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 1}, Role: fleet.RoleGitOps}}},
false,
false,
},
{
"team maintainer, DOES NOT belong to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 2}, Role: fleet.RoleMaintainer}}},
true,
true,
},
{
"team admin, DOES NOT belong to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 2}, Role: fleet.RoleAdmin}}},
true,
true,
},
{
"team observer, DOES NOT belong to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 2}, Role: fleet.RoleObserver}}},
true,
true,
},
{
"team observer+, DOES NOT belong to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 2}, Role: fleet.RoleObserverPlus}}},
true,
true,
},
{
"team gitops, DOES NOT belong to team",
&fleet.User{Teams: []fleet.UserTeam{{Team: fleet.Team{ID: 2}, Role: fleet.RoleGitOps}}},
true,
true,
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
ctx := viewer.NewContext(ctx, viewer.Viewer{User: tt.user})
_, err := svc.GetTeamScheduledQueries(ctx, 1, fleet.ListOptions{})
checkAuthErr(t, tt.shouldFailRead, err)
_, err = svc.TeamScheduleQuery(ctx, 1, &fleet.ScheduledQuery{Interval: 10})
checkAuthErr(t, tt.shouldFailWrite, err)
_, err = svc.ModifyTeamScheduledQueries(ctx, 1, 99, fleet.ScheduledQueryPayload{})
checkAuthErr(t, tt.shouldFailWrite, err)
err = svc.DeleteTeamScheduledQueries(ctx, 1, 99)
checkAuthErr(t, tt.shouldFailWrite, err)
})
}
}