Skip to content

Commit 3e706c4

Browse files
committed
Mark uninstall/lock/unlock/wipe script executions as internal, list as pending scripts when script execution is disabled globally
1 parent 907da7c commit 3e706c4

File tree

14 files changed

+113
-75
lines changed

14 files changed

+113
-75
lines changed

cmd/fleetctl/scripts_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ Fleet records the last 10,000 characters to prevent downtime.
338338
}
339339
return &h, nil
340340
}
341-
ds.ListPendingHostScriptExecutionsFunc = func(ctx context.Context, hid uint) ([]*fleet.HostScriptResult, error) {
341+
ds.ListPendingHostScriptExecutionsFunc = func(ctx context.Context, hid uint, onlyShowInternal bool) ([]*fleet.HostScriptResult, error) {
342342
require.Equal(t, uint(42), hid)
343343
if c.expectPending {
344344
return []*fleet.HostScriptResult{{HostID: uint(42)}}, nil

ee/server/service/software_installers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ func (svc *Service) UninstallSoftwareTitle(ctx context.Context, hostID uint, sof
936936
if host.TeamID != nil {
937937
teamID = *host.TeamID
938938
}
939-
// create the script execution request, the host will be notified of the
939+
// create the script execution request; the host will be notified of the
940940
// script execution request via the orbit config's Notifications mechanism.
941941
request := fleet.HostScriptRequestPayload{
942942
HostID: host.ID,
@@ -947,7 +947,7 @@ func (svc *Service) UninstallSoftwareTitle(ctx context.Context, hostID uint, sof
947947
if ctxUser := authz.UserFromContext(ctx); ctxUser != nil {
948948
request.UserID = &ctxUser.ID
949949
}
950-
scriptResult, err := svc.ds.NewHostScriptExecutionRequest(ctx, &request)
950+
scriptResult, err := svc.ds.NewInternalScriptExecutionRequest(ctx, &request)
951951
if err != nil {
952952
return ctxerr.Wrap(ctx, err, "create script execution request")
953953
}

ee/server/service/software_installers_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func TestInstallUninstallAuth(t *testing.T) {
112112
ds.GetAnyScriptContentsFunc = func(ctx context.Context, id uint) ([]byte, error) {
113113
return []byte("script"), nil
114114
}
115-
ds.NewHostScriptExecutionRequestFunc = func(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult,
115+
ds.NewInternalScriptExecutionRequestFunc = func(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult,
116116
error) {
117117
return &fleet.HostScriptResult{
118118
ExecutionID: "execution_id",

server/datastore/mysql/schema.sql

Lines changed: 3 additions & 2 deletions
Large diffs are not rendered by default.

server/datastore/mysql/scripts.go

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,26 @@ func (ds *Datastore) NewHostScriptExecutionRequest(ctx context.Context, request
4141
id, _ := scRes.LastInsertId()
4242
request.ScriptContentID = uint(id) //nolint:gosec // dismiss G115
4343
}
44-
res, err = newHostScriptExecutionRequest(ctx, tx, request)
44+
res, err = newHostScriptExecutionRequest(ctx, tx, request, false)
4545
return err
4646
})
4747
}
4848

49-
func newHostScriptExecutionRequest(ctx context.Context, tx sqlx.ExtContext, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult, error) {
49+
func (ds *Datastore) NewInternalScriptExecutionRequest(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult, error) {
50+
var res *fleet.HostScriptResult
51+
var err error
52+
return res, ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
53+
if request.ScriptContentID == 0 {
54+
return errors.New("script contents must be saved prior to execution")
55+
}
56+
res, err = newHostScriptExecutionRequest(ctx, tx, request, true)
57+
return err
58+
})
59+
}
60+
61+
func newHostScriptExecutionRequest(ctx context.Context, tx sqlx.ExtContext, request *fleet.HostScriptRequestPayload, isInternal bool) (*fleet.HostScriptResult, error) {
5062
const (
51-
insStmt = `INSERT INTO host_script_results (host_id, execution_id, script_content_id, output, script_id, policy_id, user_id, sync_request, setup_experience_script_id) VALUES (?, ?, ?, '', ?, ?, ?, ?, ?)`
63+
insStmt = `INSERT INTO host_script_results (host_id, execution_id, script_content_id, output, script_id, policy_id, user_id, sync_request, setup_experience_script_id, is_internal) VALUES (?, ?, ?, '', ?, ?, ?, ?, ?, ?)`
5264
getStmt = `SELECT hsr.id, hsr.host_id, hsr.execution_id, hsr.created_at, hsr.script_id, hsr.policy_id, hsr.user_id, hsr.sync_request, sc.contents as script_contents, hsr.setup_experience_script_id FROM host_script_results hsr JOIN script_contents sc WHERE sc.id = hsr.script_content_id AND hsr.id = ?`
5365
)
5466

@@ -62,6 +74,7 @@ func newHostScriptExecutionRequest(ctx context.Context, tx sqlx.ExtContext, requ
6274
request.UserID,
6375
request.SyncRequest,
6476
request.SetupExperienceScriptID,
77+
isInternal,
6578
)
6679
if err != nil {
6780
return nil, ctxerr.Wrap(ctx, err, "new host script execution request")
@@ -212,21 +225,26 @@ func (ds *Datastore) SetHostScriptExecutionResult(ctx context.Context, result *f
212225
return hsr, action, nil
213226
}
214227

215-
func (ds *Datastore) ListPendingHostScriptExecutions(ctx context.Context, hostID uint) ([]*fleet.HostScriptResult, error) {
228+
func (ds *Datastore) ListPendingHostScriptExecutions(ctx context.Context, hostID uint, onlyShowInternal bool) ([]*fleet.HostScriptResult, error) {
229+
internalWhere := ""
230+
if onlyShowInternal {
231+
internalWhere = " AND is_internal = TRUE"
232+
}
233+
216234
listStmt := fmt.Sprintf(`
217-
SELECT
218-
id,
219-
host_id,
220-
execution_id,
221-
script_id
222-
FROM
223-
host_script_results
224-
WHERE
225-
host_id = ? AND
226-
%s
227-
ORDER BY
228-
created_at ASC
229-
`, whereFilterPendingScript)
235+
SELECT
236+
id,
237+
host_id,
238+
execution_id,
239+
script_id
240+
FROM
241+
host_script_results
242+
WHERE
243+
host_id = ? AND
244+
%s
245+
%s
246+
ORDER BY
247+
created_at ASC`, whereFilterPendingScript, internalWhere)
230248

231249
var results []*fleet.HostScriptResult
232250
seconds := int(constants.MaxServerWaitTime.Seconds())
@@ -1029,7 +1047,7 @@ func (ds *Datastore) LockHostViaScript(ctx context.Context, request *fleet.HostS
10291047
id, _ := scRes.LastInsertId()
10301048
request.ScriptContentID = uint(id) //nolint:gosec // dismiss G115
10311049

1032-
res, err = newHostScriptExecutionRequest(ctx, tx, request)
1050+
res, err = newHostScriptExecutionRequest(ctx, tx, request, true)
10331051
if err != nil {
10341052
return ctxerr.Wrap(ctx, err, "lock host via script create execution")
10351053
}
@@ -1079,7 +1097,7 @@ func (ds *Datastore) UnlockHostViaScript(ctx context.Context, request *fleet.Hos
10791097
id, _ := scRes.LastInsertId()
10801098
request.ScriptContentID = uint(id) //nolint:gosec // dismiss G115
10811099

1082-
res, err = newHostScriptExecutionRequest(ctx, tx, request)
1100+
res, err = newHostScriptExecutionRequest(ctx, tx, request, true)
10831101
if err != nil {
10841102
return ctxerr.Wrap(ctx, err, "unlock host via script create execution")
10851103
}
@@ -1130,7 +1148,7 @@ func (ds *Datastore) WipeHostViaScript(ctx context.Context, request *fleet.HostS
11301148
id, _ := scRes.LastInsertId()
11311149
request.ScriptContentID = uint(id) //nolint:gosec // dismiss G115
11321150

1133-
res, err = newHostScriptExecutionRequest(ctx, tx, request)
1151+
res, err = newHostScriptExecutionRequest(ctx, tx, request, true)
11341152
if err != nil {
11351153
return ctxerr.Wrap(ctx, err, "wipe host via script create execution")
11361154
}

server/datastore/mysql/scripts_test.go

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) {
5353
ctx := context.Background()
5454

5555
// no script saved yet
56-
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1)
56+
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1, false)
5757
require.NoError(t, err)
5858
require.Empty(t, pending)
5959

@@ -83,11 +83,16 @@ func testHostScriptResult(t *testing.T, ds *Datastore) {
8383
require.True(t, createdScript.SyncRequest)
8484

8585
// the script execution is now listed as pending for this host
86-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
86+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
8787
require.NoError(t, err)
8888
require.Len(t, pending, 1)
8989
require.Equal(t, createdScript.ID, pending[0].ID)
9090

91+
// the script execution isn't visible when looking at internal-only scripts
92+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, true)
93+
require.NoError(t, err)
94+
require.Empty(t, pending)
95+
9196
// record a result for this execution
9297
hsr, action, err := ds.SetHostScriptExecutionResult(ctx, &fleet.HostScriptResultPayload{
9398
HostID: 1,
@@ -114,7 +119,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) {
114119
require.Nil(t, hsr)
115120

116121
// it is not pending anymore
117-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
122+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
118123
require.NoError(t, err)
119124
require.Empty(t, pending)
120125

@@ -202,7 +207,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) {
202207
require.False(t, createdScript.SyncRequest)
203208

204209
// the script execution is now listed as pending for this host
205-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
210+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
206211
require.NoError(t, err)
207212
require.Len(t, pending, 1)
208213
require.Equal(t, createdScript.ID, pending[0].ID)
@@ -215,7 +220,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) {
215220
})
216221

217222
// the script execution still shows as pending
218-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
223+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
219224
require.NoError(t, err)
220225
require.Len(t, pending, 1)
221226
require.Equal(t, createdScript.ID, pending[0].ID)
@@ -228,7 +233,7 @@ func testHostScriptResult(t *testing.T, ds *Datastore) {
228233
})
229234

230235
// the script is not pending anymore
231-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
236+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
232237
require.NoError(t, err)
233238
require.Empty(t, pending, 0)
234239

@@ -657,14 +662,14 @@ VALUES
657662

658663
t.Run("script deletion cancels pending script runs", func(t *testing.T) {
659664
insertResults(t, 43, scripts[3], now.Add(-2*time.Minute), "execution-4-4", nil)
660-
pending, err := ds.ListPendingHostScriptExecutions(ctx, 43)
665+
pending, err := ds.ListPendingHostScriptExecutions(ctx, 43, false)
661666
require.NoError(t, err)
662667
require.Len(t, pending, 1)
663668

664669
err = ds.DeleteScript(ctx, scripts[3].ID)
665670
require.NoError(t, err)
666671

667-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 43)
672+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 43, false)
668673
require.NoError(t, err)
669674
require.Len(t, pending, 0)
670675
})
@@ -821,10 +826,10 @@ VALUES
821826
// add pending scripts on team and no-team and confirm they're shown as pending
822827
insertResults(t, 44, n1WithTeamID, now.Add(-2*time.Minute), "execution-n1t1-1", nil)
823828
insertResults(t, 45, n1WithNoTeamId, now.Add(-2*time.Minute), "execution-n1nt1-1", nil)
824-
pending, err := ds.ListPendingHostScriptExecutions(ctx, 44)
829+
pending, err := ds.ListPendingHostScriptExecutions(ctx, 44, false)
825830
require.NoError(t, err)
826831
require.Len(t, pending, 1)
827-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 45)
832+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 45, false)
828833
require.NoError(t, err)
829834
require.Len(t, pending, 1)
830835

@@ -842,10 +847,10 @@ VALUES
842847
require.Equal(t, n1WithNoTeamId, *noTeamPolicy.ScriptID)
843848

844849
// team script should no longer be pending, no-team script should still be pending
845-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 44)
850+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 44, false)
846851
require.NoError(t, err)
847852
require.Len(t, pending, 0)
848-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 45)
853+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 45, false)
849854
require.NoError(t, err)
850855
require.Len(t, pending, 1)
851856

@@ -869,15 +874,15 @@ VALUES
869874
require.Nil(t, noTeamPolicy.ScriptID)
870875

871876
// no-team script should no longer be pending
872-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 45)
877+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 45, false)
873878
require.NoError(t, err)
874879
require.Len(t, pending, 0)
875880
}
876881

877882
func testLockHostViaScript(t *testing.T, ds *Datastore) {
878883
ctx := context.Background()
879884
// no script saved yet
880-
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1)
885+
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1, false)
881886
require.NoError(t, err)
882887
require.Empty(t, pending)
883888

@@ -930,7 +935,7 @@ func testLockHostViaScript(t *testing.T, ds *Datastore) {
930935
func testUnlockHostViaScript(t *testing.T, ds *Datastore) {
931936
ctx := context.Background()
932937
// no script saved yet
933-
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1)
938+
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1, false)
934939
require.NoError(t, err)
935940
require.Empty(t, pending)
936941

@@ -1468,14 +1473,14 @@ func testDeletePendingHostScriptExecutionsForPolicy(t *testing.T, ds *Datastore)
14681473
})
14691474
require.NoError(t, err)
14701475

1471-
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1)
1476+
pending, err := ds.ListPendingHostScriptExecutions(ctx, 1, false)
14721477
require.NoError(t, err)
14731478
require.Equal(t, 1, len(pending))
14741479

14751480
err = ds.deletePendingHostScriptExecutionsForPolicy(ctx, &team1.ID, p1.ID)
14761481
require.NoError(t, err)
14771482

1478-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
1483+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
14791484
require.NoError(t, err)
14801485
require.Equal(t, 0, len(pending))
14811486

@@ -1490,14 +1495,14 @@ func testDeletePendingHostScriptExecutionsForPolicy(t *testing.T, ds *Datastore)
14901495
})
14911496
require.NoError(t, err)
14921497

1493-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
1498+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
14941499
require.NoError(t, err)
14951500
require.Equal(t, 1, len(pending))
14961501

14971502
err = ds.deletePendingHostScriptExecutionsForPolicy(ctx, &team1.ID, p1.ID)
14981503
require.NoError(t, err)
14991504

1500-
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1)
1505+
pending, err = ds.ListPendingHostScriptExecutions(ctx, 1, false)
15011506
require.NoError(t, err)
15021507
require.Equal(t, 1, len(pending))
15031508

server/fleet/datastore.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,9 @@ type Datastore interface {
16071607
// NewHostScriptExecutionRequest creates a new host script result entry with
16081608
// just the script to run information (result is not yet available).
16091609
NewHostScriptExecutionRequest(ctx context.Context, request *HostScriptRequestPayload) (*HostScriptResult, error)
1610+
// NewInternalScriptExecutionRequest creates a new host script result entry with
1611+
// just the script to run information (result is not yet available), with the script marked as internal.
1612+
NewInternalScriptExecutionRequest(ctx context.Context, request *HostScriptRequestPayload) (*HostScriptResult, error)
16101613
// SetHostScriptExecutionResult stores the result of a host script execution
16111614
// and returns the updated host script result record. Note that it does not
16121615
// fail if the script execution request does not exist, in this case it will
@@ -1617,9 +1620,10 @@ type Datastore interface {
16171620
// received, it is the caller's responsibility to check if that was the case
16181621
// (with ExitCode being null).
16191622
GetHostScriptExecutionResult(ctx context.Context, execID string) (*HostScriptResult, error)
1620-
// ListPendingHostScriptExecutions returns all the pending host script
1621-
// executions, which are those that have yet to record a result.
1622-
ListPendingHostScriptExecutions(ctx context.Context, hostID uint) ([]*HostScriptResult, error)
1623+
// ListPendingHostScriptExecutions returns all the pending host script executions, which are those that have yet
1624+
// to record a result. Pass onlyShowInternal as true to return only scripts that execute when script execution is
1625+
// globally disabled (uninstall/lock/unlock/wipe).
1626+
ListPendingHostScriptExecutions(ctx context.Context, hostID uint, onlyShowInternal bool) ([]*HostScriptResult, error)
16231627

16241628
// NewScript creates a new saved script.
16251629
NewScript(ctx context.Context, script *Script) (*Script, error)

server/mock/datastore_mock.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,11 +1029,13 @@ type SetOrUpdateMDMAppleDeclarationFunc func(ctx context.Context, declaration *f
10291029

10301030
type NewHostScriptExecutionRequestFunc func(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult, error)
10311031

1032+
type NewInternalScriptExecutionRequestFunc func(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult, error)
1033+
10321034
type SetHostScriptExecutionResultFunc func(ctx context.Context, result *fleet.HostScriptResultPayload) (hsr *fleet.HostScriptResult, action string, err error)
10331035

10341036
type GetHostScriptExecutionResultFunc func(ctx context.Context, execID string) (*fleet.HostScriptResult, error)
10351037

1036-
type ListPendingHostScriptExecutionsFunc func(ctx context.Context, hostID uint) ([]*fleet.HostScriptResult, error)
1038+
type ListPendingHostScriptExecutionsFunc func(ctx context.Context, hostID uint, onlyShowInternal bool) ([]*fleet.HostScriptResult, error)
10371039

10381040
type NewScriptFunc func(ctx context.Context, script *fleet.Script) (*fleet.Script, error)
10391041

@@ -2690,6 +2692,9 @@ type DataStore struct {
26902692
NewHostScriptExecutionRequestFunc NewHostScriptExecutionRequestFunc
26912693
NewHostScriptExecutionRequestFuncInvoked bool
26922694

2695+
NewInternalScriptExecutionRequestFunc NewInternalScriptExecutionRequestFunc
2696+
NewInternalScriptExecutionRequestFuncInvoked bool
2697+
26932698
SetHostScriptExecutionResultFunc SetHostScriptExecutionResultFunc
26942699
SetHostScriptExecutionResultFuncInvoked bool
26952700

@@ -6443,6 +6448,13 @@ func (s *DataStore) NewHostScriptExecutionRequest(ctx context.Context, request *
64436448
return s.NewHostScriptExecutionRequestFunc(ctx, request)
64446449
}
64456450

6451+
func (s *DataStore) NewInternalScriptExecutionRequest(ctx context.Context, request *fleet.HostScriptRequestPayload) (*fleet.HostScriptResult, error) {
6452+
s.mu.Lock()
6453+
s.NewInternalScriptExecutionRequestFuncInvoked = true
6454+
s.mu.Unlock()
6455+
return s.NewInternalScriptExecutionRequestFunc(ctx, request)
6456+
}
6457+
64466458
func (s *DataStore) SetHostScriptExecutionResult(ctx context.Context, result *fleet.HostScriptResultPayload) (hsr *fleet.HostScriptResult, action string, err error) {
64476459
s.mu.Lock()
64486460
s.SetHostScriptExecutionResultFuncInvoked = true
@@ -6457,11 +6469,11 @@ func (s *DataStore) GetHostScriptExecutionResult(ctx context.Context, execID str
64576469
return s.GetHostScriptExecutionResultFunc(ctx, execID)
64586470
}
64596471

6460-
func (s *DataStore) ListPendingHostScriptExecutions(ctx context.Context, hostID uint) ([]*fleet.HostScriptResult, error) {
6472+
func (s *DataStore) ListPendingHostScriptExecutions(ctx context.Context, hostID uint, onlyShowInternal bool) ([]*fleet.HostScriptResult, error) {
64616473
s.mu.Lock()
64626474
s.ListPendingHostScriptExecutionsFuncInvoked = true
64636475
s.mu.Unlock()
6464-
return s.ListPendingHostScriptExecutionsFunc(ctx, hostID)
6476+
return s.ListPendingHostScriptExecutionsFunc(ctx, hostID, onlyShowInternal)
64656477
}
64666478

64676479
func (s *DataStore) NewScript(ctx context.Context, script *fleet.Script) (*fleet.Script, error) {

0 commit comments

Comments
 (0)