Skip to content
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
13 changes: 7 additions & 6 deletions cmd/fleet/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ import (
"github.com/fleetdm/fleet/v4/server/service/conditional_access_microsoft_proxy"
"github.com/fleetdm/fleet/v4/server/service/middleware/auth"
otelmw "github.com/fleetdm/fleet/v4/server/service/middleware/otel"
"github.com/fleetdm/fleet/v4/server/service/modules/activities"
"github.com/fleetdm/fleet/v4/server/service/redis_key_value"
"github.com/fleetdm/fleet/v4/server/service/redis_lock"
"github.com/fleetdm/fleet/v4/server/service/redis_policy_set"
Expand Down Expand Up @@ -874,7 +873,8 @@ the way that the Fleet server works.
digiCertService := digicert.NewService(digicert.WithLogger(logger))
ctx = ctxerr.NewContext(ctx, eh)

activitiesModule := activities.NewActivityModule()
// Declare svc early so the closure below can capture it.
var svc fleet.Service
config.MDM.AndroidAgent.Validate(initFatal)
androidSvc, err := android_service.NewService(
ctx,
Expand All @@ -883,14 +883,16 @@ the way that the Fleet server works.
config.License.Key,
config.Server.PrivateKey,
ds,
activitiesModule,
func(ctx context.Context, user *fleet.User, activity fleet.ActivityDetails) error {
return svc.NewActivity(ctx, user, activity)
},
config.MDM.AndroidAgent,
)
if err != nil {
initFatal(err, "initializing android service")
}

svc, err := service.NewService(
svc, err = service.NewService(
ctx,
ds,
task,
Expand Down Expand Up @@ -1039,9 +1041,8 @@ the way that the Fleet server works.

// Bootstrap activity bounded context (needed for cron schedules and HTTP routes)
activitySvc, activityRoutes := createActivityBoundedContext(svc, dbConns, logger)
// Inject the activity bounded context into the main service and activity module
// Inject the activity bounded context into the main service
svc.SetActivityService(activitySvc)
activitiesModule.SetService(activitySvc)

// Perform a cleanup of cron_stats outside of the cronSchedules because the
// schedule package uses cron_stats entries to decide whether a schedule will
Expand Down
2 changes: 1 addition & 1 deletion ee/server/scim/scim.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func RegisterSCIM(
Required: false,
},
},
Handler: NewUserHandler(ds, svc, scimLogger),
Handler: NewUserHandler(ds, svc.NewActivity, scimLogger),
},
{
ID: optional.NewString("Group"),
Expand Down
13 changes: 6 additions & 7 deletions ee/server/scim/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/ptr"
"github.com/fleetdm/fleet/v4/server/service/modules/activities"
"github.com/scim2/filter-parser/v2"
)

Expand All @@ -43,16 +42,16 @@ const (
)

type UserHandler struct {
ds fleet.Datastore
activityModule activities.ActivityModule
logger *slog.Logger
ds fleet.Datastore
newActivity fleet.NewActivityFunc
logger *slog.Logger
}

// Compile-time check
var _ scim.ResourceHandler = &UserHandler{}

func NewUserHandler(ds fleet.Datastore, activityModule activities.ActivityModule, logger *slog.Logger) scim.ResourceHandler {
return &UserHandler{ds: ds, activityModule: activityModule, logger: logger}
func NewUserHandler(ds fleet.Datastore, newActivity fleet.NewActivityFunc, logger *slog.Logger) scim.ResourceHandler {
return &UserHandler{ds: ds, newActivity: newActivity, logger: logger}
}

func (u *UserHandler) Create(r *http.Request, attributes scim.ResourceAttributes) (scim.Resource, error) {
Expand Down Expand Up @@ -620,7 +619,7 @@ func (u *UserHandler) deleteMatchingFleetUser(ctx context.Context, scimUser *fle
return ctxerr.Wrap(ctx, err, "delete fleet user")
}

if err := u.activityModule.NewActivity(
if err := u.newActivity(
ctx,
nil,
fleet.ActivityTypeDeletedUser{
Expand Down
6 changes: 3 additions & 3 deletions ee/server/scim/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ func newTestMocks() *testMocks {

func (m *testMocks) newTestHandler() *UserHandler {
return &UserHandler{
ds: m.ds,
activityModule: m.svc,
logger: slog.New(slog.DiscardHandler),
ds: m.ds,
newActivity: m.svc.NewActivity,
logger: slog.New(slog.DiscardHandler),
}
}

Expand Down
38 changes: 6 additions & 32 deletions server/fleet/activities.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,15 @@ import (
"context"
"encoding/json"
"time"

"github.com/fleetdm/fleet/v4/server/activity/api"
)

// NewActivityFunc is the function signature for creating a new activity.
type NewActivityFunc func(ctx context.Context, user *User, activity ActivityDetails) error

type Activity struct {
CreateTimestamp

// ID is the activity id in the activities table, it is omitted for upcoming
// activities as those are "virtual activities" generated from entries in
// queues (e.g. pending host_script_results).
ID uint `json:"id,omitempty" db:"id"`

// UUID is the activity UUID for the upcoming activities, as identified in
// the relevant queue (e.g. pending host_script_results). It is omitted for
// past activities as those are "real activities" with an activity id.
UUID string `json:"uuid,omitempty" db:"uuid"`

ActorFullName *string `json:"actor_full_name,omitempty" db:"name"`
ActorID *uint `json:"actor_id,omitempty" db:"user_id"`
ActorGravatar *string `json:"actor_gravatar,omitempty" db:"gravatar_url"`
ActorEmail *string `json:"actor_email,omitempty" db:"user_email"`
ActorAPIOnly *bool `json:"actor_api_only,omitempty" db:"api_only"`
Type string `json:"type" db:"activity_type"`
Details *json.RawMessage `json:"details" db:"details"`
Streamed *bool `json:"-" db:"streamed"`
FleetInitiated bool `json:"fleet_initiated" db:"fleet_initiated"`
}

// AuthzType implement AuthzTyper to be able to verify access to activities
func (*Activity) AuthzType() string {
return "activity"
}
// Activity is an alias for the canonical Activity type defined in server/activity/api.
type Activity = api.Activity

// UpcomingActivity is the augmented activity type used to return the list of
// upcoming (pending) activities for a host.
Expand Down Expand Up @@ -244,10 +220,8 @@ var ActivityDetailsList = []ActivityDetails{
ActivityTypeEditedEnrollSecrets{},
}

type ActivityDetails interface {
// ActivityName is the name/type of the activity.
ActivityName() string
}
// ActivityDetails is an alias for the canonical ActivityDetails interface defined in server/activity/api.
type ActivityDetails = api.ActivityDetails

type ActivityTypeEnabledActivityAutomations struct {
WebhookUrl string `json:"webhook_url"`
Expand Down
1 change: 0 additions & 1 deletion server/mdm/android/arch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func TestAllAndroidPackageDependencies(t *testing.T) {
m+"/server/service/externalsvc", // dependency on Jira and Zendesk
m+"/server/service/middleware/auth",
m+"/server/service/middleware/log",
m+"/server/service/modules/activities",
).
Check()
}
Expand Down
46 changes: 22 additions & 24 deletions server/mdm/android/service/enterprises_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func TestEnterprisesAuth(t *testing.T) {
androidAPIClient.InitCommonMocks()
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
fleetDS := InitCommonDSMocks()
activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

testCases := []struct {
Expand Down Expand Up @@ -126,9 +126,9 @@ func TestEnterpriseSignupMissingPrivateKey(t *testing.T) {
androidAPIClient.InitCommonMocks()
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
fleetDS := InitCommonDSMocks()
activityModule := &noopActivityModule{} // This test does not verify activity creation.
newActivity := noopNewActivity // This test does not verify activity creation.

svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

user := &fleet.User{ID: 1, GlobalRole: ptr.String(fleet.RoleAdmin)}
Expand Down Expand Up @@ -231,10 +231,8 @@ type notFoundError struct{}
func (e *notFoundError) Error() string { return "not found" }
func (e *notFoundError) IsNotFound() bool { return true }

// noopActivityModule is a no-op implementation of the ActivityModule interface.
type noopActivityModule struct{}

func (n *noopActivityModule) NewActivity(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error {
// noopNewActivity is a no-op activity creation function for tests that don't verify activity creation.
func noopNewActivity(_ context.Context, _ *fleet.User, _ fleet.ActivityDetails) error {
return nil
}

Expand All @@ -248,8 +246,8 @@ func TestGetEnterprise(t *testing.T) {
androidAPIClient.InitCommonMocks()

fleetDS := InitCommonDSMocks()
activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

enterprise, err := svc.GetEnterprise(ctx)
Expand All @@ -268,8 +266,8 @@ func TestGetEnterprise(t *testing.T) {
return nil, &notFoundError{}
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

enterprise, err := svc.GetEnterprise(ctx)
Expand Down Expand Up @@ -314,8 +312,8 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
}, nil
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

err = svc.VerifyExistingEnterpriseIfAny(ctx)
Expand Down Expand Up @@ -363,8 +361,8 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
}, nil
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

err = svc.VerifyExistingEnterpriseIfAny(ctx)
Expand Down Expand Up @@ -404,8 +402,8 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
}
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

err = svc.VerifyExistingEnterpriseIfAny(ctx)
Expand Down Expand Up @@ -445,8 +443,8 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
return []*androidmanagement.Enterprise{}, nil
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

err = svc.VerifyExistingEnterpriseIfAny(ctx)
Expand Down Expand Up @@ -512,8 +510,8 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
}, nil
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

err = svc.VerifyExistingEnterpriseIfAny(ctx)
Expand Down Expand Up @@ -542,8 +540,8 @@ func TestVerifyExistingEnterpriseIfAny(t *testing.T) {
return nil, &notFoundError{}
}

activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, activityModule, config.AndroidAgentConfig{})
newActivity := noopNewActivity // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, fleetDS, &androidAPIClient, "test-private-key", &fleetDS.DataStore, newActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

err = svc.VerifyExistingEnterpriseIfAny(ctx)
Expand Down
10 changes: 5 additions & 5 deletions server/mdm/android/service/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (svc *Service) handlePubSubStatusReport(ctx context.Context, token string,
}
for i, act := range acts {
user := users[i]
if err := svc.activityModule.NewActivity(ctx, user, act); err != nil {
if err := svc.newActivity(ctx, user, act); err != nil {
return ctxerr.Wrap(ctx, err, "create failed app install activity")
}
}
Expand All @@ -187,7 +187,7 @@ func (svc *Service) handlePubSubStatusReport(ctx context.Context, token string,
// Emit system activity: mdm_unenrolled. For Android BYOD, InstalledFromDEP is always false.
// Use the computed display name from the device payload as lite host may not include it.
displayName := svc.getComputerName(&device)
_ = svc.activityModule.NewActivity(ctx, nil, fleet.ActivityTypeMDMUnenrolled{
_ = svc.newActivity(ctx, nil, fleet.ActivityTypeMDMUnenrolled{
HostSerial: "",
HostDisplayName: displayName,
InstalledFromDEP: false,
Expand Down Expand Up @@ -308,13 +308,13 @@ func (svc *Service) handlePubSubEnrollment(ctx context.Context, token string, ra
}
for i, act := range acts {
user := users[i]
if err := svc.activityModule.NewActivity(ctx, user, act); err != nil {
if err := svc.newActivity(ctx, user, act); err != nil {
return ctxerr.Wrap(ctx, err, "create failed app install activity")
}
}

displayName := svc.getComputerName(&device)
_ = svc.activityModule.NewActivity(ctx, nil, fleet.ActivityTypeMDMUnenrolled{
_ = svc.newActivity(ctx, nil, fleet.ActivityTypeMDMUnenrolled{
HostSerial: "",
HostDisplayName: displayName,
InstalledFromDEP: false,
Expand Down Expand Up @@ -899,7 +899,7 @@ func (svc *Service) verifyDeviceSoftware(ctx context.Context, host *fleet.Host,
return false
}
act.FromSetupExperience = true // currently, all Android app installs are from setup experience
if err := svc.activityModule.NewActivity(ctx, user, act); err != nil {
if err := svc.newActivity(ctx, user, act); err != nil {
svc.logger.ErrorContext(ctx, "error creating past activity for installed software", "err", err, "host_uuid", hostUUID)
return true
}
Expand Down
3 changes: 1 addition & 2 deletions server/mdm/android/service/pubsub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ func createAndroidService(t *testing.T) (android.Service, *AndroidMockDS) {
androidAPIClient.InitCommonMocks()
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
mockDS := InitCommonDSMocks()
activityModule := &noopActivityModule{} // This test does not verify activity creation.
svc, err := NewServiceWithClient(logger, mockDS, &androidAPIClient, "test-private-key", &mockDS.DataStore, activityModule, config.AndroidAgentConfig{})
svc, err := NewServiceWithClient(logger, mockDS, &androidAPIClient, "test-private-key", &mockDS.DataStore, noopNewActivity, config.AndroidAgentConfig{})
require.NoError(t, err)

return svc, mockDS
Expand Down
Loading
Loading