From d5e82fda30d7d0b05acccae7c187ce2ddb44b331 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:49 +0000
Subject: [PATCH 01/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
...20240222073518_AddCertInfoToNanoCertAssociations.go | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/server/datastore/mysql/migrations/tables/20240222073518_AddCertInfoToNanoCertAssociations.go b/server/datastore/mysql/migrations/tables/20240222073518_AddCertInfoToNanoCertAssociations.go
index 12ae487694f..873cc0b063f 100644
--- a/server/datastore/mysql/migrations/tables/20240222073518_AddCertInfoToNanoCertAssociations.go
+++ b/server/datastore/mysql/migrations/tables/20240222073518_AddCertInfoToNanoCertAssociations.go
@@ -94,9 +94,13 @@ func updateCertAssociationTimestamps(txx *sqlx.Tx, limit, offset int) error {
expiries := make(map[string]time.Time, len(scepCerts))
for i, rawCert := range scepCerts {
block, _ := pem.Decode(rawCert.CertificatePEM)
+ if block == nil {
+ log.Printf("failed to decode PEM for certificate with serial %s", rawCert.Serial)
+ continue
+ }
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
- log.Printf("failed to parse certificate with serial %s", rawCert.Serial)
+ log.Printf("failed to parse certificate with serial %s: %v", rawCert.Serial, err)
continue
}
@@ -123,6 +127,10 @@ func updateCertAssociationTimestamps(txx *sqlx.Tx, limit, offset int) error {
return fmt.Errorf("failed to retrieve cert associations: %w", err)
}
+ if len(assocs) == 0 {
+ return nil
+ }
+
var sb strings.Builder
updateAssocArgs := make([]any, len(assocs)*3)
for i, assoc := range assocs {
From 414a3a115d5b4e84adb2b28520ec3f18cddcc08a Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:50 +0000
Subject: [PATCH 02/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
tools/mdm/assets/main.go | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/tools/mdm/assets/main.go b/tools/mdm/assets/main.go
index 2fd34c2870a..b4c53e5623f 100644
--- a/tools/mdm/assets/main.go
+++ b/tools/mdm/assets/main.go
@@ -74,7 +74,7 @@ func setupSharedFlags() {
func setupDS(privateKey, userName, password, address, name string) *mysql.Datastore {
db, err := sql.Open(
"mysql",
- fmt.Sprintf("%s:%s@tcp(%s)/?multiStatements=true&tls=skip-verify", testUsername, testPassword, testAddress),
+ fmt.Sprintf("%s:%s@tcp(%s)/?multiStatements=true&tls=skip-verify", userName, password, address),
)
if err != nil {
log.Fatal("opening MySQL connection:", err)
@@ -324,9 +324,20 @@ export FLEET_MDM_APPLE_BM_KEY=%[1]s/abm_key.key
// SCEPDepot.Serial() from ever handing it out to a future client cert.
// We deliberately do not insert into identity_certificates — the CA
// cert itself lives in mdm_config_assets, not the depot's cert table.
+ //
+ // NOTE: this uses a separate raw *sql.DB connection (rather than the
+ // `ds` datastore) because reserving the serial and writing the
+ // rolled-over CA cert via ReplaceMDMConfigAssets are not wrapped in a
+ // single cross-datastore transaction. If ReplaceMDMConfigAssets fails
+ // after the serial below has been allocated, this tool exits via
+ // log.Fatal without releasing/rolling back the reserved serial. This
+ // is an accepted trade-off: the only consequence is a permanent gap
+ // in the identity_serials auto-increment sequence (no cert is ever
+ // issued using the leaked serial, so there is no risk of collision
+ // or of a dangling/invalid certificate).
rawDB, err := sql.Open(
"mysql",
- fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=skip-verify", flagDBUser, flagDBPass, flagDBAddress, flagDBName),
+ fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=%s", flagDBUser, flagDBPass, flagDBAddress, flagDBName, "skip-verify"),
)
if err != nil {
log.Fatal("opening MySQL connection to reserve CA serial: ", err)
From aa408be0b88b6a71314555c8545199a805c93f18 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:51 +0000
Subject: [PATCH 03/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/reconcile/reconcile_test.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/server/mdm/reconcile/reconcile_test.go b/server/mdm/reconcile/reconcile_test.go
index 2bf2366a1f5..a4673c695c2 100644
--- a/server/mdm/reconcile/reconcile_test.go
+++ b/server/mdm/reconcile/reconcile_test.go
@@ -101,7 +101,7 @@ func TestHandlerExcludeAny(t *testing.T) {
t.Run("dynamic label created after host's last scan -> true (exclude)", func(t *testing.T) {
labels := []fleet.MDMProfileLabelRef{
{
- LabelID: new(uint(1)),
+ LabelID: func() *uint { v := uint(1); return &v }(),
CreatedAt: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
LabelMembershipType: int(fleet.LabelMembershipTypeDynamic),
},
@@ -111,7 +111,7 @@ func TestHandlerExcludeAny(t *testing.T) {
t.Run("host vital label created after host's last scan -> false (include)", func(t *testing.T) {
labels := []fleet.MDMProfileLabelRef{
{
- LabelID: new(uint(1)),
+ LabelID: func() *uint { v := uint(1); return &v }(),
CreatedAt: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
LabelMembershipType: int(fleet.LabelMembershipTypeHostVitals),
},
@@ -121,7 +121,7 @@ func TestHandlerExcludeAny(t *testing.T) {
t.Run("manual label created after host's last scan -> still false (include)", func(t *testing.T) {
labels := []fleet.MDMProfileLabelRef{
{
- LabelID: new(uint(1)),
+ LabelID: func() *uint { v := uint(1); return &v }(),
CreatedAt: time.Date(2026, 2, 1, 0, 0, 0, 0, time.UTC),
LabelMembershipType: int(fleet.LabelMembershipTypeManual),
},
From bacf53af162d9277d3e11ed2183789112f04c65a Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:52 +0000
Subject: [PATCH 04/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/datastore/redis/keyprefix.go | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/server/datastore/redis/keyprefix.go b/server/datastore/redis/keyprefix.go
index c606506d150..5002e7124ad 100644
--- a/server/datastore/redis/keyprefix.go
+++ b/server/datastore/redis/keyprefix.go
@@ -137,7 +137,11 @@ func twoKeys(args []interface{}, prefix string) {
prefixOne(args, 1, prefix)
}
-// evalArgs: args = [script, numKeys, k1, ..., kN, arg1, ...].
+// evalArgs: args = [script, numKeys, k1, ..., kN, arg1, ...]. If numKeys is
+// malformed (larger than the number of args actually supplied), that's a
+// caller bug: fail closed and skip prefixing entirely rather than silently
+// prefixing only some of the intended keys, which could leave later key args
+// operating on another tenant's keyspace.
func evalArgs(args []interface{}, prefix string) {
if len(args) < 2 {
return
@@ -146,6 +150,9 @@ func evalArgs(args []interface{}, prefix string) {
if n <= 0 {
return
}
+ if 2+n > len(args) {
+ return
+ }
for i := 0; i < n; i++ {
prefixOne(args, 2+i, prefix)
}
@@ -220,6 +227,21 @@ func sortArgs(args []interface{}, prefix string) {
}
}
+// geoRadiusArgs: GEORADIUS/GEORADIUSBYMEMBER key ... [STORE dst] [STOREDIST dst].
+// Prefix the source key and any STORE/STOREDIST destination key(s) so results
+// aren't written into another tenant's keyspace.
+func geoRadiusArgs(args []interface{}, prefix string) {
+ if len(args) == 0 {
+ return
+ }
+ prefixOne(args, 0, prefix)
+ for i := 1; i < len(args)-1; i++ {
+ if strings.EqualFold(toString(args[i]), "STORE") || strings.EqualFold(toString(args[i]), "STOREDIST") {
+ prefixOne(args, i+1, prefix)
+ }
+ }
+}
+
func toInt(v interface{}) int {
switch x := v.(type) {
case int:
@@ -343,6 +365,10 @@ var specialCmds = map[string]prefixRule{
// SORT key ... [STORE dst]
"SORT": sortArgs,
+ // GEORADIUS/GEORADIUSBYMEMBER key ... [STORE dst] [STOREDIST dst]
+ "GEORADIUS": geoRadiusArgs,
+ "GEORADIUSBYMEMBER": geoRadiusArgs,
+
// pub/sub channel commands — every arg is a channel
"SUBSCRIBE": allArgs,
"UNSUBSCRIBE": allArgs,
From 286bde029a3db4774eec368dca9f558920e3c4f0 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:53 +0000
Subject: [PATCH 05/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/datastore/mysqlredis/host_cache_writes_test.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/datastore/mysqlredis/host_cache_writes_test.go b/server/datastore/mysqlredis/host_cache_writes_test.go
index cc0046f0b7f..4e92502b6e3 100644
--- a/server/datastore/mysqlredis/host_cache_writes_test.go
+++ b/server/datastore/mysqlredis/host_cache_writes_test.go
@@ -95,7 +95,8 @@ func TestWritePathInvalidation(t *testing.T) {
ds.UpdateHostRefetchCriticalQueriesUntilFunc = func(_ context.Context, _ uint, _ *time.Time) error { return nil }
},
invoke: func(ctx context.Context, d *Datastore, id uint, _ string) error {
- return d.UpdateHostRefetchCriticalQueriesUntil(ctx, id, new(time.Unix(1, 0)))
+ until := time.Unix(1, 0)
+ return d.UpdateHostRefetchCriticalQueriesUntil(ctx, id, &until)
},
invoked: func(ds *mock.Store) bool { return ds.UpdateHostRefetchCriticalQueriesUntilFuncInvoked },
},
From 94a2212d549cf63b53469c4507ad13fb536d30ac Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:54 +0000
Subject: [PATCH 06/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/nanomdm/storage/mysql/pushcert.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/mdm/nanomdm/storage/mysql/pushcert.go b/server/mdm/nanomdm/storage/mysql/pushcert.go
index 1a7bd63b58d..b154e8d6a20 100644
--- a/server/mdm/nanomdm/storage/mysql/pushcert.go
+++ b/server/mdm/nanomdm/storage/mysql/pushcert.go
@@ -55,8 +55,9 @@ ON DUPLICATE KEY
UPDATE
cert_pem = VALUES(cert_pem),
key_pem = VALUES(key_pem),
- push_certs.stale_token = push_certs.stale_token + 1;`,
+ stale_token = stale_token + 1;`,
topic, pemCert, pemKey,
)
return err
}
+
From 31faecd164311bbfcd32412920d34040045abf2d Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:55 +0000
Subject: [PATCH 07/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/profiles/android_appconfig_test.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/server/mdm/profiles/android_appconfig_test.go b/server/mdm/profiles/android_appconfig_test.go
index d10ea4a739a..da1514fab34 100644
--- a/server/mdm/profiles/android_appconfig_test.go
+++ b/server/mdm/profiles/android_appconfig_test.go
@@ -7,6 +7,7 @@ import (
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mock"
+ "github.com/fleetdm/fleet/v4/server/ptr"
"github.com/stretchr/testify/require"
)
@@ -139,7 +140,7 @@ func TestSubstituteFleetVarsInAndroidAppConfig(t *testing.T) {
return []uint{42}, nil
}
ds.ScimUserByHostIDFunc = func(ctx context.Context, hostID uint) (*fleet.ScimUser, error) {
- return &fleet.ScimUser{UserName: "jdoe@example.com", GivenName: new("John"), FamilyName: new("Doe")}, nil
+ return &fleet.ScimUser{UserName: "jdoe@example.com", GivenName: ptr.String("John"), FamilyName: ptr.String("Doe")}, nil
}
ds.ListHostDeviceMappingFunc = func(ctx context.Context, hostID uint) ([]*fleet.HostDeviceMapping, error) {
return nil, nil
@@ -157,7 +158,7 @@ func TestSubstituteFleetVarsInAndroidAppConfig(t *testing.T) {
return []uint{42}, nil
}
ds.ScimUserByHostIDFunc = func(ctx context.Context, hostID uint) (*fleet.ScimUser, error) {
- return &fleet.ScimUser{UserName: "jdoe@example.com", GivenName: new("John"), FamilyName: new("Doe")}, nil
+ return &fleet.ScimUser{UserName: "jdoe@example.com", GivenName: ptr.String("John"), FamilyName: ptr.String("Doe")}, nil
}
ds.ListHostDeviceMappingFunc = func(ctx context.Context, hostID uint) ([]*fleet.HostDeviceMapping, error) {
return nil, nil
From 8d9d98178d59ef0724b4be3f8eb98258eed4ac23 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:56 +0000
Subject: [PATCH 08/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/nanomdm/storage/mysql/certauth.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/mdm/nanomdm/storage/mysql/certauth.go b/server/mdm/nanomdm/storage/mysql/certauth.go
index c64cb1bb696..8bb904f5e30 100644
--- a/server/mdm/nanomdm/storage/mysql/certauth.go
+++ b/server/mdm/nanomdm/storage/mysql/certauth.go
@@ -60,7 +60,7 @@ func (s *MySQLStorage) EnrollmentFromHash(ctx context.Context, hash string) (str
var id string
err := s.db.QueryRowContext(
ctx,
- `SELECT id FROM cert_auth_associations WHERE sha256 = ? LIMIT 1;`,
+ `SELECT id FROM nano_cert_auth_associations WHERE sha256 = ? LIMIT 1;`,
hash,
).Scan(&id)
if errors.Is(err, sql.ErrNoRows) {
@@ -68,3 +68,4 @@ func (s *MySQLStorage) EnrollmentFromHash(ctx context.Context, hash string) (str
}
return id, err
}
+
From 4495899db448bf9774afdee4532d173e88fd929d Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:57 +0000
Subject: [PATCH 09/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/datastore/filesystem/software_installer.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/datastore/filesystem/software_installer.go b/server/datastore/filesystem/software_installer.go
index 26c7a6fc514..7e22584a3c4 100644
--- a/server/datastore/filesystem/software_installer.go
+++ b/server/datastore/filesystem/software_installer.go
@@ -119,7 +119,8 @@ func (i *SoftwareInstallerStore) Cleanup(ctx context.Context, usedInstallerIDs [
info, err := de.Info()
if err != nil {
- return 0, ctxerr.Wrap(ctx, err, "get software installer modtime in filesystem store")
+ errs = append(errs, err)
+ continue
}
if info.ModTime().After(removeCreatedBefore) {
continue
From 31d568f7323f86fd41711cee3099742d69ec52ef Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:58 +0000
Subject: [PATCH 10/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../20241125150614_AddAppConfigWindowsMigrationEnabledField.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/datastore/mysql/migrations/tables/20241125150614_AddAppConfigWindowsMigrationEnabledField.go b/server/datastore/mysql/migrations/tables/20241125150614_AddAppConfigWindowsMigrationEnabledField.go
index f069d072aae..204b42468e2 100644
--- a/server/datastore/mysql/migrations/tables/20241125150614_AddAppConfigWindowsMigrationEnabledField.go
+++ b/server/datastore/mysql/migrations/tables/20241125150614_AddAppConfigWindowsMigrationEnabledField.go
@@ -31,7 +31,8 @@ func Up_20241125150614(tx *sql.Tx) error {
mdm, ok := config["mdm"]
if !ok {
- return errors.New("missing mdm section")
+ mdm = map[string]interface{}{}
+ config["mdm"] = mdm
}
mdmMap, ok := mdm.(map[string]interface{})
if !ok {
From 60a18e52d74db78bfc3c03a89d73a1feddcb6cc1 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:44:59 +0000
Subject: [PATCH 11/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
infrastructure/loadtesting/terraform/infra/secrets.tf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/infrastructure/loadtesting/terraform/infra/secrets.tf b/infrastructure/loadtesting/terraform/infra/secrets.tf
index 1171ff0156f..71ebe496e44 100644
--- a/infrastructure/loadtesting/terraform/infra/secrets.tf
+++ b/infrastructure/loadtesting/terraform/infra/secrets.tf
@@ -4,4 +4,4 @@ data "aws_secretsmanager_secret" "license" {
data "aws_secretsmanager_secret_version" "enroll_secret" {
secret_id = data.terraform_remote_state.shared.outputs.enroll_secret.id
-}
\ No newline at end of file
+}
From 6a9255ee7258c541d840f86829c591fb36524545 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:00 +0000
Subject: [PATCH 12/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../conditional_access_microsoft_proxy.go | 38 +++++++++++++------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go b/server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go
index 0a64c90349c..53136e3a258 100644
--- a/server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go
+++ b/server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go
@@ -53,6 +53,7 @@ type CreateResponse struct {
func (p *Proxy) Create(ctx context.Context, tenantID string) (*CreateResponse, error) {
var createResponse CreateResponse
if err := p.post(
+ ctx,
"/api/v1/microsoft-compliance-partner",
createRequest{TenantID: tenantID},
&createResponse,
@@ -73,9 +74,13 @@ type GetResponse struct {
// Get returns the integration settings.
func (p *Proxy) Get(ctx context.Context, tenantID string, secret string) (*GetResponse, error) {
var getResponse GetResponse
+ query := url.Values{}
+ query.Set("entraTenantId", tenantID)
+ query.Set("fleetServerSecret", secret)
if err := p.get(
+ ctx,
"/api/v1/microsoft-compliance-partner/settings",
- fmt.Sprintf("entraTenantId=%s&fleetServerSecret=%s", tenantID, secret),
+ query.Encode(),
&getResponse,
); err != nil {
return nil, fmt.Errorf("get integration settings failed: %w", err)
@@ -92,9 +97,13 @@ type DeleteResponse struct {
// Returns a fleet.IsNotFound error if the integration doesn't exist.
func (p *Proxy) Delete(ctx context.Context, tenantID string, secret string) (*DeleteResponse, error) {
var deleteResponse DeleteResponse
+ query := url.Values{}
+ query.Set("entraTenantId", tenantID)
+ query.Set("fleetServerSecret", secret)
if err := p.delete(
+ ctx,
"/api/v1/microsoft-compliance-partner",
- fmt.Sprintf("entraTenantId=%s&fleetServerSecret=%s", tenantID, secret),
+ query.Encode(),
&deleteResponse,
); err != nil {
return nil, fmt.Errorf("delete integration failed: %w", err)
@@ -137,6 +146,7 @@ func (p *Proxy) SetComplianceStatus(
) (*SetComplianceStatusResponse, error) {
var setComplianceStatusResponse SetComplianceStatusResponse
if err := p.post(
+ ctx,
"/api/v1/microsoft-compliance-partner/device",
setComplianceStatusRequest{
TenantID: tenantID,
@@ -179,9 +189,14 @@ func (p *Proxy) GetMessageStatus(
messageID string,
) (*GetMessageStatusResponse, error) {
var getMessageStatusResponse GetMessageStatusResponse
+ query := url.Values{}
+ query.Set("entraTenantId", tenantID)
+ query.Set("fleetServerSecret", secret)
+ query.Set("messageId", messageID)
if err := p.get(
+ ctx,
"/api/v1/microsoft-compliance-partner/device/message",
- fmt.Sprintf("entraTenantId=%s&fleetServerSecret=%s&messageId=%s", tenantID, secret, messageID),
+ query.Encode(),
&getMessageStatusResponse,
); err != nil {
return nil, fmt.Errorf("get message status response failed: %w", err)
@@ -189,12 +204,12 @@ func (p *Proxy) GetMessageStatus(
return &getMessageStatusResponse, nil
}
-func (p *Proxy) post(path string, request interface{}, response interface{}) error {
+func (p *Proxy) post(ctx context.Context, path string, request interface{}, response interface{}) error {
b, err := json.Marshal(request)
if err != nil {
return fmt.Errorf("marshal request: %w", err)
}
- postRequest, err := http.NewRequest("POST", p.uri+path, nil)
+ postRequest, err := http.NewRequestWithContext(ctx, "POST", p.uri+path, bytes.NewBuffer(b))
if err != nil {
return fmt.Errorf("post create request: %w", err)
}
@@ -202,7 +217,6 @@ func (p *Proxy) post(path string, request interface{}, response interface{}) err
return fmt.Errorf("post set headers: %w", err)
}
postRequest.Header.Add("Content-Type", "application/json")
- postRequest.Body = io.NopCloser(bytes.NewBuffer(b))
resp, err := p.c.Do(postRequest)
if err != nil {
return fmt.Errorf("post request: %w", err)
@@ -221,12 +235,12 @@ func (p *Proxy) post(path string, request interface{}, response interface{}) err
return nil
}
-func (p *Proxy) get(path string, query string, response interface{}) error {
+func (p *Proxy) get(ctx context.Context, path string, query string, response interface{}) error {
getURL := p.uri + path
if query != "" {
- getURL += "?" + url.PathEscape(query)
+ getURL += "?" + query
}
- getRequest, err := http.NewRequest("GET", getURL, nil)
+ getRequest, err := http.NewRequestWithContext(ctx, "GET", getURL, nil)
if err != nil {
return fmt.Errorf("get create request: %w", err)
}
@@ -251,12 +265,12 @@ func (p *Proxy) get(path string, query string, response interface{}) error {
return nil
}
-func (p *Proxy) delete(path string, query string, response interface{}) error {
+func (p *Proxy) delete(ctx context.Context, path string, query string, response interface{}) error {
deleteURL := p.uri + path
if query != "" {
- deleteURL += "?" + url.PathEscape(query)
+ deleteURL += "?" + query
}
- deleteRequest, err := http.NewRequest("DELETE", deleteURL, nil)
+ deleteRequest, err := http.NewRequestWithContext(ctx, "DELETE", deleteURL, nil)
if err != nil {
return fmt.Errorf("delete create request: %w", err)
}
From eb9e71542cf08c79b659aaeeb141466233fa24c5 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:02 +0000
Subject: [PATCH 13/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../tables/20240314085226_AddCalendarEventTables.go | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/server/datastore/mysql/migrations/tables/20240314085226_AddCalendarEventTables.go b/server/datastore/mysql/migrations/tables/20240314085226_AddCalendarEventTables.go
index 8f8871d1054..ac0a136562b 100644
--- a/server/datastore/mysql/migrations/tables/20240314085226_AddCalendarEventTables.go
+++ b/server/datastore/mysql/migrations/tables/20240314085226_AddCalendarEventTables.go
@@ -22,7 +22,7 @@ func Up_20240314085226(tx *sql.Tx) error {
event JSON NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY idx_one_calendar_event_per_email (email)
) DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
@@ -30,6 +30,11 @@ func Up_20240314085226(tx *sql.Tx) error {
return fmt.Errorf("create calendar_events table: %w", err)
}
+ // Note: host_id intentionally does not have a foreign key constraint to the
+ // hosts table. Hosts can be deleted and re-enrolled (churn/replacement), and
+ // host_calendar_events rows referencing a deleted host_id are cleaned up by
+ // application logic rather than a DB-level cascade, to avoid tying calendar
+ // event bookkeeping lifecycle directly to host deletion.
if _, err := tx.Exec(`
CREATE TABLE IF NOT EXISTS host_calendar_events (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
@@ -38,7 +43,7 @@ func Up_20240314085226(tx *sql.Tx) error {
webhook_status TINYINT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP NOT NULL NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY idx_one_calendar_event_per_host (host_id),
FOREIGN KEY (calendar_event_id) REFERENCES calendar_events(id) ON DELETE CASCADE
From c35d992ea244b1a2e7fa452ddac0b56415128dee Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:03 +0000
Subject: [PATCH 14/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb b/ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb
index 1eb10295433..542cb80003c 100644
--- a/ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb
+++ b/ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb
@@ -175,7 +175,7 @@ def req(method: :get, path: '', body: nil, headers: {}, cached: false, environme
end
end
rescue => e
- out['error'] = e
+ out['error'] = e.message
end
out
@@ -196,7 +196,7 @@ def parse_response(response)
message = 'server returned a non-ok status code without an error'
if response.body
- body = JSON.parse(response.body)
+ body = out['body']
message = body['message']
unless body['errors'].nil?
From cec4ffc6c597ff21e90726d3872ccf03e9c21c00 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:04 +0000
Subject: [PATCH 15/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
tools/tuf/test/create_repository.sh | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tools/tuf/test/create_repository.sh b/tools/tuf/test/create_repository.sh
index 8aa777eb6f2..e07aae58f60 100755
--- a/tools/tuf/test/create_repository.sh
+++ b/tools/tuf/test/create_repository.sh
@@ -317,7 +317,6 @@ for system in $SYSTEMS; do
do
extensionName=$(basename $extension)
extensionName=$(echo "$extensionName" | cut -d'.' -f1)
- echo "$FILE" | cut -d'.' -f2
./build/fleetctl updates add \
--path $TUF_PATH \
--target $extension \
@@ -333,7 +332,6 @@ for system in $SYSTEMS; do
do
extensionName=$(basename $extension)
extensionName=$(echo "$extensionName" | cut -d'.' -f1)
- echo "$FILE" | cut -d'.' -f2
./build/fleetctl updates add \
--path $TUF_PATH \
--target $extension \
@@ -343,3 +341,4 @@ for system in $SYSTEMS; do
done
fi
done
+
From dba4e2441c22e64f22f31d02b9cdfd671842c704 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:05 +0000
Subject: [PATCH 16/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../SoftwareVulnerabilities/SoftwareVulnerabilities.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx
index b4974e3672e..e7fbf21d20e 100644
--- a/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx
+++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx
@@ -178,7 +178,7 @@ const SoftwareVulnerabilities = ({
};
// Handle 400 response which is an invalid CVE format
- if (error.status === 400) {
+ if (error.response?.status === 400) {
if (
error?.data?.errors &&
error.data.errors[0].reason.includes(
@@ -198,7 +198,7 @@ const SoftwareVulnerabilities = ({
}
// Handle 404 response which is BE validated CVE string but not a known CVE
- } else if (error.status === 404) {
+ } else if (error.response?.status === 404) {
if (
error?.data?.errors &&
(error.data.errors[0].reason.includes("This is not a known CVE.") ||
@@ -234,7 +234,7 @@ const SoftwareVulnerabilities = ({
if (isExactMatchQuery) {
refetchExactMatch();
}
- }, [queryParams.exploit, isExactMatchQuery]);
+ }, [queryParams.exploit, isExactMatchQuery, refetchExactMatch]);
// !tableData is used to show the Spinner only on the first render.
// This prevents the Spinner from flashing on every data refresh, noticable
From 421b682d74c24be09d582d909018cb4d6fdfe8ac Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:06 +0000
Subject: [PATCH 17/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../migrations/tables/20240826160025_AddRemovedToInstalls.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/datastore/mysql/migrations/tables/20240826160025_AddRemovedToInstalls.go b/server/datastore/mysql/migrations/tables/20240826160025_AddRemovedToInstalls.go
index 6314d654854..37e8d27c511 100644
--- a/server/datastore/mysql/migrations/tables/20240826160025_AddRemovedToInstalls.go
+++ b/server/datastore/mysql/migrations/tables/20240826160025_AddRemovedToInstalls.go
@@ -56,7 +56,7 @@ func Up_20240826160025(tx *sql.Tx) error {
return fmt.Errorf("failed to find host_software_installs to remove: %w", err)
}
if len(ids) > 0 {
- stmt, args, err := sqlx.In("UPDATE host_software_installs SET removed = 1 WHERE id IN (?)", ids)
+ stmt, args, err := sqlx.In("UPDATE host_software_installs SET removed = 1 WHERE id IN (?)", ids)
if err != nil {
return fmt.Errorf("failed to expand slice value for host_software_installs: %w", err)
}
@@ -87,7 +87,7 @@ func Up_20240826160025(tx *sql.Tx) error {
return fmt.Errorf("failed to find host_vpp_software_installs to remove: %w", err)
}
if len(vppIDs) > 0 {
- stmt, args, err := sqlx.In("UPDATE host_vpp_software_installs SET removed = 1 WHERE id IN (?)", vppIDs)
+ stmt, args, err := sqlx.In("UPDATE host_vpp_software_installs SET removed = 1 WHERE id IN (?)", vppIDs)
if err != nil {
return fmt.Errorf("failed to expand slice value for host_vpp_software_installs: %w", err)
}
From 5f02562cf1d1316ad721d3ee2e4f53706a48288a Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:07 +0000
Subject: [PATCH 18/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/errorstore/errors.go | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/server/errorstore/errors.go b/server/errorstore/errors.go
index a730de6583f..1d617775636 100644
--- a/server/errorstore/errors.go
+++ b/server/errorstore/errors.go
@@ -317,19 +317,22 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
flush, err = strconv.ParseBool(opts.Get("flush"))
if err != nil {
+ h.logger.ErrorContext(r.Context(), "failed to parse flush query param", "err", err)
w.WriteHeader(http.StatusBadRequest)
return
}
}
- errors, err := h.Retrieve(flush)
+ storedErrors, err := h.Retrieve(flush)
if err != nil {
+ h.logger.ErrorContext(r.Context(), "failed to retrieve stored errors", "err", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
- bytes, err := json.Marshal(errors)
+ bytes, err := json.Marshal(storedErrors)
if err != nil {
+ h.logger.ErrorContext(r.Context(), "failed to marshal stored errors", "err", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
From 8da2947a05a59bdcb927cc7f68c943478eb363ec Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:08 +0000
Subject: [PATCH 19/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/scep/depot/file/depot.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/server/mdm/scep/depot/file/depot.go b/server/mdm/scep/depot/file/depot.go
index a4a9874f18f..55b980956bc 100644
--- a/server/mdm/scep/depot/file/depot.go
+++ b/server/mdm/scep/depot/file/depot.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "log"
"math/big"
"os"
"path/filepath"
@@ -230,13 +231,12 @@ func (d *fileDepot) HasCN(_ string, allowTime int, cert *x509.Certificate, revok
addDB.WriteString(line + "\n")
}
}
- file.Close()
for key, value := range candidates {
if value == "no" {
return false, errors.New("DN " + dn + " already exists")
}
if revokeOldCertificate {
- fmt.Println("Revoking certificate with serial " + key + " from DB. Recreation of CRL needed.")
+ log.Printf("Revoking certificate with serial %s from DB. Recreation of CRL needed.", key)
entries := strings.Split(value, "\t")
addDB.WriteString("R\t" + entries[1] + "\t" + makeOpenSSLTime(time.Now()) + "\t" + strings.ToUpper(entries[3]) + "\t" + entries[4] + "\t" + entries[5] + "\n")
}
@@ -249,6 +249,7 @@ func (d *fileDepot) HasCN(_ string, allowTime int, cert *x509.Certificate, revok
if err != nil {
return false, err
}
+ defer file.Close()
if _, err := file.Write(addDB.Bytes()); err != nil {
return false, err
}
From f56465ff29de48b130d75b661d7cc5097e414c73 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:09 +0000
Subject: [PATCH 20/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../datastore/mysql/migrations/tables/migration.go | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/server/datastore/mysql/migrations/tables/migration.go b/server/datastore/mysql/migrations/tables/migration.go
index b8724086bdf..2b96a366720 100644
--- a/server/datastore/mysql/migrations/tables/migration.go
+++ b/server/datastore/mysql/migrations/tables/migration.go
@@ -60,7 +60,7 @@ func incrementalMigrationStep(count getTotalCountFn, execute executeWithProgress
// Every five seconds, echo the % progress of the executor
// Since we output once the migration step is complete, we need an extra channel to indicate when both the step
- // and the "step complete" output are com0plete
+ // and the "step complete" output are complete
stepComplete := make(chan struct{})
outputComplete := make(chan struct{})
go func() {
@@ -83,10 +83,12 @@ func incrementalMigrationStep(count getTotalCountFn, execute executeWithProgress
}
}()
- err = execute(tx, func() {
- atomicCurrent.Add(1)
- })
- close(stepComplete)
+ func() {
+ defer close(stepComplete)
+ err = execute(tx, func() {
+ atomicCurrent.Add(1)
+ })
+ }()
<-outputComplete // Wait for the goroutine to complete
return err
}
@@ -258,3 +260,4 @@ func updateAppConfigJSON(tx *sql.Tx, fn func(config *fleet.AppConfig) error) err
return nil
}
+
From b75a9b8c9b0743a7c1983b2f5a761cdefc9e40b6 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:10 +0000
Subject: [PATCH 21/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/service/endpoint_setup.go | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/server/service/endpoint_setup.go b/server/service/endpoint_setup.go
index 75927928f20..95d722521a6 100644
--- a/server/service/endpoint_setup.go
+++ b/server/service/endpoint_setup.go
@@ -157,9 +157,15 @@ func ApplyStarterLibrary(
if err != nil {
return fmt.Errorf("failed to create fleetctl config: %w", err)
}
+ if err := os.Chmod(configFile.Name(), 0o600); err != nil {
+ configFile.Close()
+ return fmt.Errorf("failed to set permissions on fleetctl config: %w", err)
+ }
fmt.Fprintf(configFile, "contexts:\n default:\n address: %s\n tls-skip-verify: true\n token: %s\n",
serverURL, token)
- configFile.Close()
+ if err := configFile.Close(); err != nil {
+ return fmt.Errorf("failed to close fleetctl config: %w", err)
+ }
// Build the gitops args: global config first, then team configs (premium only).
args := []string{"gitops", "--config", configFile.Name(), "-f", filepath.Join(outDir, "default.yml")}
From fe88ceb135fd53e63afbe52d44046cc9fd6de2e6 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:11 +0000
Subject: [PATCH 22/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
frontend/components/LiveQuery/SelectTargets.tsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/frontend/components/LiveQuery/SelectTargets.tsx b/frontend/components/LiveQuery/SelectTargets.tsx
index c6e547b936c..1ee075f0692 100644
--- a/frontend/components/LiveQuery/SelectTargets.tsx
+++ b/frontend/components/LiveQuery/SelectTargets.tsx
@@ -290,6 +290,8 @@ const SelectTargets = ({
// this effect every render, which dispatches a context update and causes an
// infinite render loop ("Maximum update depth exceeded"), freezing the
// Select targets UI (e.g. the X to remove a host stops responding).
+ // TODO: memoize `setSelectedTargets` at its source in QueryContext so this
+ // effect can safely include it in its dependency array.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [targetedHosts, targetedLabels, targetedTeams]);
@@ -318,7 +320,9 @@ const SelectTargets = ({
// if the target was previously selected, we want to remove it now
let newTargets = prevTargets.filter((t) => t.id !== selectedEntity.id);
// if the length remains the same, the target was not previously selected so we want to add it now
- prevTargets.length === newTargets.length && newTargets.push(selectedEntity);
+ if (prevTargets.length === newTargets.length) {
+ newTargets.push(selectedEntity);
+ }
// Logic when to deselect/select "all hosts" when using more granulated filters
// If "all hosts" is selected
From 41ba39680888e19ec85ad717d7dc630619b42f0c Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:12 +0000
Subject: [PATCH 23/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/datastore/mysql/software_title_icons.go | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/server/datastore/mysql/software_title_icons.go b/server/datastore/mysql/software_title_icons.go
index 2f96e7086c7..aa53dbf2888 100644
--- a/server/datastore/mysql/software_title_icons.go
+++ b/server/datastore/mysql/software_title_icons.go
@@ -183,8 +183,9 @@ func (ds *Datastore) ActivityDetailsForSoftwareTitleIcon(ctx context.Context, te
Exclude bool `db:"exclude"`
RequireAll bool `db:"require_all"`
}
- var labels []ActivitySoftwareLabel
+ var allLabels []ActivitySoftwareLabel
if details.SoftwareInstallerID != nil {
+ var labels []ActivitySoftwareLabel
labelQuery := `
SELECT
labels.id AS id,
@@ -198,8 +199,10 @@ func (ds *Datastore) ActivityDetailsForSoftwareTitleIcon(ctx context.Context, te
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &labels, labelQuery, details.SoftwareInstallerID); err != nil {
return fleet.DetailsForSoftwareIconActivity{}, ctxerr.Wrap(ctx, err, "getting labels for software title icon")
}
+ allLabels = append(allLabels, labels...)
}
- if details.AdamID != nil {
+ if details.AdamID != nil && details.VPPAppTeamID != nil {
+ var labels []ActivitySoftwareLabel
labelQuery := `
SELECT
labels.id AS id,
@@ -213,8 +216,10 @@ func (ds *Datastore) ActivityDetailsForSoftwareTitleIcon(ctx context.Context, te
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &labels, labelQuery, details.VPPAppTeamID); err != nil {
return fleet.DetailsForSoftwareIconActivity{}, ctxerr.Wrap(ctx, err, "getting labels for software title icon")
}
+ allLabels = append(allLabels, labels...)
}
if details.InHouseAppID != nil {
+ var labels []ActivitySoftwareLabel
labelQuery := `
SELECT
labels.id AS id,
@@ -228,9 +233,10 @@ func (ds *Datastore) ActivityDetailsForSoftwareTitleIcon(ctx context.Context, te
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &labels, labelQuery, details.InHouseAppID); err != nil {
return fleet.DetailsForSoftwareIconActivity{}, ctxerr.Wrap(ctx, err, "getting labels for software title icon")
}
+ allLabels = append(allLabels, labels...)
}
- for _, l := range labels {
+ for _, l := range allLabels {
switch {
case l.Exclude && !l.RequireAll:
details.LabelsExcludeAny = append(details.LabelsExcludeAny, fleet.ActivitySoftwareLabel{
From f22fa048098604ff4ded3bf2d26c5a90271e8ea8 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:13 +0000
Subject: [PATCH 24/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../tables/20260518194422_AddEncodingTypeToHostSCDData.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/datastore/mysql/migrations/tables/20260518194422_AddEncodingTypeToHostSCDData.go b/server/datastore/mysql/migrations/tables/20260518194422_AddEncodingTypeToHostSCDData.go
index 12f6df131ae..dded977df57 100644
--- a/server/datastore/mysql/migrations/tables/20260518194422_AddEncodingTypeToHostSCDData.go
+++ b/server/datastore/mysql/migrations/tables/20260518194422_AddEncodingTypeToHostSCDData.go
@@ -9,7 +9,7 @@ func init() {
MigrationClient.AddMigration(Up_20260518194422, Down_20260518194422)
}
-// Up_20260514220719 adds the encoding_type column that discriminates between
+// Up_20260518194422 adds the encoding_type column that discriminates between
// the legacy dense bitmap format (encoding_type = 0) and the new roaring
// bitmap format (encoding_type = 1). ALGORITHM=INSTANT is a metadata-only
// change on MySQL 8.0+; existing rows are not rewritten and read back with
From 11a4a23e9fa6c03f6d18efc1827a034f67608f3d Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:14 +0000
Subject: [PATCH 25/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
website/api/helpers/strings/to-html-email.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/website/api/helpers/strings/to-html-email.js b/website/api/helpers/strings/to-html-email.js
index 59aa7e999fb..dc5e4f514b6 100644
--- a/website/api/helpers/strings/to-html-email.js
+++ b/website/api/helpers/strings/to-html-email.js
@@ -112,7 +112,7 @@ module.exports = {
// For emphasized text
customRenderer.em = function(textHTML) {
- return `${textHTML}`;
};
// For inline codespans
@@ -162,3 +162,4 @@ module.exports = {
};
+
From 270eb8a0ba8122b911dd7941990807ea9bb73c82 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:15 +0000
Subject: [PATCH 26/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
frontend/pages/DashboardPage/cards/Software/Software.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/pages/DashboardPage/cards/Software/Software.tsx b/frontend/pages/DashboardPage/cards/Software/Software.tsx
index 82660ca26c8..bf238b59c27 100644
--- a/frontend/pages/DashboardPage/cards/Software/Software.tsx
+++ b/frontend/pages/DashboardPage/cards/Software/Software.tsx
@@ -97,7 +97,7 @@ const Software = ({
data={(isSoftwareEnabled && software?.software) || []}
isLoading={isSoftwareFetching}
pageIndex={softwarePageIndex}
- defaultSortHeader={SOFTWARE_DEFAULT_SORT_DIRECTION}
+ defaultSortHeader={SOFTWARE_DEFAULT_SORT_HEADER}
defaultSortDirection={SOFTWARE_DEFAULT_SORT_DIRECTION}
resultsTitle="software"
emptyComponent={() => }
From 3375f7761ef13a9e24bbfbfdc5841600fa2392af Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:16 +0000
Subject: [PATCH 27/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
orbit/pkg/table/app_sso_platform/app_sso_platform_darwin.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/orbit/pkg/table/app_sso_platform/app_sso_platform_darwin.go b/orbit/pkg/table/app_sso_platform/app_sso_platform_darwin.go
index ad079368287..d6d97c6bc82 100644
--- a/orbit/pkg/table/app_sso_platform/app_sso_platform_darwin.go
+++ b/orbit/pkg/table/app_sso_platform/app_sso_platform_darwin.go
@@ -232,7 +232,7 @@ func parseAppSSOPlatformCommandOutput(output []byte, expectedExtensionIdentifier
}
realm, ok := realm_.(string)
if !ok {
- return nil, fmt.Errorf("unexpected type for \"realm\" key in \"kerberosStatus\": %T", err)
+ return nil, fmt.Errorf("unexpected type for \"realm\" key in \"kerberosStatus\": %T", realm_)
}
upn_, ok := userConfig.KerberosStatus[0]["upn"]
if !ok {
From c3fcb765c0865be7d2bae0cb019fefad105acd99 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:18 +0000
Subject: [PATCH 28/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/datastore/mysql/conditional_access_microsoft.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/server/datastore/mysql/conditional_access_microsoft.go b/server/datastore/mysql/conditional_access_microsoft.go
index a4367f62d95..ee3d5dff743 100644
--- a/server/datastore/mysql/conditional_access_microsoft.go
+++ b/server/datastore/mysql/conditional_access_microsoft.go
@@ -93,6 +93,7 @@ func (ds *Datastore) LoadHostConditionalAccessStatus(ctx context.Context, hostID
if errors.Is(err, sql.ErrNoRows) {
return nil, ctxerr.Wrap(ctx, notFound("HostConditionalAccessStatus").WithID(hostID))
}
+ return nil, ctxerr.Wrap(ctx, err, "getting host conditional access status")
}
hostConditionalAccessStatus.OSVersion = strings.TrimPrefix(hostConditionalAccessStatus.OSVersion, "macOS ")
if strings.HasPrefix(hostConditionalAccessStatus.OSVersion, "Windows") {
From 1f79c0ff4265e037c9b83b3b1437c5de395c7872 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:19 +0000
Subject: [PATCH 29/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/nanodep/cmd/deptokens/main.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/server/mdm/nanodep/cmd/deptokens/main.go b/server/mdm/nanodep/cmd/deptokens/main.go
index a7775f2ecd5..ef4a8c91668 100644
--- a/server/mdm/nanodep/cmd/deptokens/main.go
+++ b/server/mdm/nanodep/cmd/deptokens/main.go
@@ -83,6 +83,9 @@ func encodeEncryptedKeyPEM(key *rsa.PrivateKey, password string) ([]byte, error)
// decrypting it with password.
func decodeEncryptedKeyPEM(pemBytes []byte, password string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(pemBytes)
+ if block == nil {
+ return nil, errors.New("failed to decode PEM block")
+ }
if block.Type != "RSA PRIVATE KEY" {
return nil, errors.New("PEM type is not RSA PRIVATE KEY")
}
From 0541ce407b2c496d0485b0ab5ddbe9a744d648ea Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:20 +0000
Subject: [PATCH 30/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../external_refs/cisco_jabber_version_transformer.go | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go b/ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go
index be81febcc2b..355600d065c 100644
--- a/ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go
+++ b/ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go
@@ -4,9 +4,10 @@ import (
maintained_apps "github.com/fleetdm/fleet/v4/ee/maintained-apps"
)
-// CiscoJabberVersionTransformer sets the version to "15.2.0" which matches what osquery reports.
-// Homebrew reports a build number (e.g., "20251027035315") instead of the app version (e.g., "15.2.0").
+// CiscoJabberVersionTransformer sets the version to "15.2.1" which matches what osquery reports.
+// Homebrew reports a build number (e.g., "20251027035315") instead of the app version (e.g., "15.2.1").
func CiscoJabberVersionTransformer(app *maintained_apps.FMAManifestApp) (*maintained_apps.FMAManifestApp, error) {
app.Version = "15.2.1"
return app, nil
}
+
From dfeff80be8f9d65139b94723674ffcb2e083f761 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:21 +0000
Subject: [PATCH 31/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/datastore/mysql/host_identity_scep.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/server/datastore/mysql/host_identity_scep.go b/server/datastore/mysql/host_identity_scep.go
index b261a8581cd..813376d70f2 100644
--- a/server/datastore/mysql/host_identity_scep.go
+++ b/server/datastore/mysql/host_identity_scep.go
@@ -19,12 +19,12 @@ import (
func (ds *Datastore) GetHostIdentityCertBySerialNumber(ctx context.Context, serialNumber uint64) (*types.HostIdentityCertificate, error) {
var hostIdentityCert types.HostIdentityCertificate
- err := sqlx.GetContext(ctx, ds.reader(ctx), &hostIdentityCert, fmt.Sprintf(`
+ err := sqlx.GetContext(ctx, ds.reader(ctx), &hostIdentityCert, `
SELECT serial, host_id, name, not_valid_after, public_key_raw
FROM host_identity_scep_certificates
- WHERE serial = %d
+ WHERE serial = ?
AND not_valid_after > NOW()
- AND revoked = 0`, serialNumber))
+ AND revoked = 0`, serialNumber)
switch {
case errors.Is(err, sql.ErrNoRows):
return nil, notFound("host identity certificate")
From 8222f0a5ff108e8c798590ef2bfb4f423385b040 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:22 +0000
Subject: [PATCH 32/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
frontend/pages/hosts/details/cards/User/helpers.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/frontend/pages/hosts/details/cards/User/helpers.tsx b/frontend/pages/hosts/details/cards/User/helpers.tsx
index 9f5a6c6c7c8..3a073dc359a 100644
--- a/frontend/pages/hosts/details/cards/User/helpers.tsx
+++ b/frontend/pages/hosts/details/cards/User/helpers.tsx
@@ -38,7 +38,7 @@ export const generateGroupsValues = (endUsers: IHostEndUser[]) => {
return [];
}
- return endUser.idp_groups.sort((a, b) => {
+ return [...endUser.idp_groups].sort((a, b) => {
return a.localeCompare(b);
});
};
@@ -106,3 +106,4 @@ export const generateGroupsTipContent = (endUsers: IHostEndUser[]) => {
return null;
};
+
From e82bd17e65e2feb14010c690e262897aa59aba4d Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:23 +0000
Subject: [PATCH 33/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../components/ProfileUploader/helpers.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/ConfigurationProfiles/components/ProfileUploader/helpers.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/ConfigurationProfiles/components/ProfileUploader/helpers.tsx
index 6a28479cf4c..6ddd7150346 100644
--- a/frontend/pages/ManageControlsPage/OSSettings/cards/ConfigurationProfiles/components/ProfileUploader/helpers.tsx
+++ b/frontend/pages/ManageControlsPage/OSSettings/cards/ConfigurationProfiles/components/ProfileUploader/helpers.tsx
@@ -94,7 +94,7 @@ const generateGenericLearnMoreErrMsg = (errMsg: string) => {
*/
// eslint-disable-next-line import/prefer-default-export
export const getErrorMessage = (err: AxiosResponse) => {
- const apiReason = err?.data?.errors?.[0]?.reason;
+ const apiReason = err?.data?.errors?.[0]?.reason ?? "";
if (apiReason.includes("should include valid JSON")) {
return "Couldn't add. The profile should include valid JSON.";
From 70fce183d0f8cd8179a1e87fe9dec418bf271ed3 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:24 +0000
Subject: [PATCH 34/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
...103700_AddAndroidApplicationIDToSoftware_test.go | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/server/datastore/mysql/migrations/tables/20251015103700_AddAndroidApplicationIDToSoftware_test.go b/server/datastore/mysql/migrations/tables/20251015103700_AddAndroidApplicationIDToSoftware_test.go
index 27f15dc01da..0f300d5261c 100644
--- a/server/datastore/mysql/migrations/tables/20251015103700_AddAndroidApplicationIDToSoftware_test.go
+++ b/server/datastore/mysql/migrations/tables/20251015103700_AddAndroidApplicationIDToSoftware_test.go
@@ -54,21 +54,18 @@ func TestUp_20251015103700(t *testing.T) {
var title fleet.SoftwareTitle
err := db.Get(&title, "SELECT id, name, source, extension_for, application_id, bundle_identifier FROM software_titles WHERE id = ?", tt.titleID)
require.NoError(t, err)
- switch {
- case tt.expectedBundleID == nil:
+ if tt.expectedBundleID == nil {
require.Nil(t, title.BundleIdentifier)
-
- case tt.expectedBundleID != nil:
+ } else {
require.NotNil(t, tt.expectedBundleID)
assert.Equal(t, *tt.expectedBundleID, *title.BundleIdentifier)
+ }
- case tt.expectedApplicationID == nil:
+ if tt.expectedApplicationID == nil {
require.Nil(t, title.ApplicationID)
-
- case tt.expectedApplicationID != nil:
+ } else {
require.NotNil(t, title.ApplicationID)
assert.Equal(t, tt.expectedApplicationID, title.ApplicationID)
-
}
var gotUniqueID string
From 688ac1fb993e09b29768b9a4fc18ce16ff5d14a1 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:25 +0000
Subject: [PATCH 35/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/nanomdm/http/api/api.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/mdm/nanomdm/http/api/api.go b/server/mdm/nanomdm/http/api/api.go
index 7954331dbbc..0f66fead18c 100644
--- a/server/mdm/nanomdm/http/api/api.go
+++ b/server/mdm/nanomdm/http/api/api.go
@@ -280,6 +280,7 @@ func readPEMCertAndKey(input []byte) (cert []byte, key []byte, err error) {
// if the PEM blocks are mushed together with no newline then add one
input = bytes.ReplaceAll(input, []byte("----------"), []byte("-----\n-----"))
var block *pem.Block
+loop:
for {
block, input = pem.Decode(input)
if block == nil {
@@ -291,7 +292,7 @@ func readPEMCertAndKey(input []byte) (cert []byte, key []byte, err error) {
case block.Type == "PRIVATE KEY" || strings.HasSuffix(block.Type, " PRIVATE KEY"):
if x509.IsEncryptedPEMBlock(block) {
err = errors.New("private key PEM appears to be encrypted")
- break
+ break loop
}
key = pem.EncodeToMemory(block)
default:
From 2025adbcb7e63c4ec0a1c520ceaa036307a9a790 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:27 +0000
Subject: [PATCH 36/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/nanomdm/storage/allmulti/certauth.go | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/server/mdm/nanomdm/storage/allmulti/certauth.go b/server/mdm/nanomdm/storage/allmulti/certauth.go
index 3fcec098b27..23b716d3125 100644
--- a/server/mdm/nanomdm/storage/allmulti/certauth.go
+++ b/server/mdm/nanomdm/storage/allmulti/certauth.go
@@ -12,21 +12,24 @@ func (ms *MultiAllStorage) HasCertHash(r *mdm.Request, hash string) (bool, error
val, err := ms.execStores(r.Context, func(s storage.AllStorage) (interface{}, error) {
return s.HasCertHash(r, hash)
})
- return val.(bool), err
+ b, _ := val.(bool)
+ return b, err
}
func (ms *MultiAllStorage) EnrollmentHasCertHash(r *mdm.Request, hash string) (bool, error) {
val, err := ms.execStores(r.Context, func(s storage.AllStorage) (interface{}, error) {
return s.EnrollmentHasCertHash(r, hash)
})
- return val.(bool), err
+ b, _ := val.(bool)
+ return b, err
}
func (ms *MultiAllStorage) IsCertHashAssociated(r *mdm.Request, hash string) (bool, error) {
val, err := ms.execStores(r.Context, func(s storage.AllStorage) (interface{}, error) {
return s.IsCertHashAssociated(r, hash)
})
- return val.(bool), err
+ b, _ := val.(bool)
+ return b, err
}
func (ms *MultiAllStorage) AssociateCertHash(r *mdm.Request, hash string, certNotValidAfter time.Time) error {
@@ -40,5 +43,7 @@ func (ms *MultiAllStorage) EnrollmentFromHash(ctx context.Context, hash string)
val, err := ms.execStores(ctx, func(s storage.AllStorage) (interface{}, error) {
return s.EnrollmentFromHash(ctx, hash)
})
- return val.(string), err
+ str, _ := val.(string)
+ return str, err
}
+
From 68555caffd5cbbefc961ce3bad9c45bf1fcd0eea Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:28 +0000
Subject: [PATCH 37/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
.../tables/20241210140021_AddErrorsToCronStatsTable.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/server/datastore/mysql/migrations/tables/20241210140021_AddErrorsToCronStatsTable.go b/server/datastore/mysql/migrations/tables/20241210140021_AddErrorsToCronStatsTable.go
index ee699ebe18f..c73b0659bba 100644
--- a/server/datastore/mysql/migrations/tables/20241210140021_AddErrorsToCronStatsTable.go
+++ b/server/datastore/mysql/migrations/tables/20241210140021_AddErrorsToCronStatsTable.go
@@ -6,10 +6,10 @@ import (
)
func init() {
- MigrationClient.AddMigration(Up_20241126140021, Down_20241126140021)
+ MigrationClient.AddMigration(Up_20241210140021, Down_20241210140021)
}
-func Up_20241126140021(tx *sql.Tx) error {
+func Up_20241210140021(tx *sql.Tx) error {
// Idempotent migration.
// Add columns
if !columnExists(tx, "cron_stats", "errors") {
@@ -21,6 +21,7 @@ func Up_20241126140021(tx *sql.Tx) error {
return nil
}
-func Down_20241126140021(tx *sql.Tx) error {
+func Down_20241210140021(tx *sql.Tx) error {
return nil
}
+
From 29650b1e52426655de5542832e88a0a4189e7035 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:29 +0000
Subject: [PATCH 38/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
server/mdm/apple/mobileconfig/mobileconfig.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/mdm/apple/mobileconfig/mobileconfig.go b/server/mdm/apple/mobileconfig/mobileconfig.go
index 2dab9cf1e90..e4832a9b225 100644
--- a/server/mdm/apple/mobileconfig/mobileconfig.go
+++ b/server/mdm/apple/mobileconfig/mobileconfig.go
@@ -269,7 +269,7 @@ func (mc *Mobileconfig) ScreenPayloads(allowCustomFileVault bool) error {
case FleetCustomSettingsPayloadType:
contains, err := ContainsFDEFileVaultOptionsPayload(*mc)
if err != nil {
- return fmt.Errorf("checking for FDEVileVaultOptions payload: %w", err)
+ return fmt.Errorf("checking for FDEFileVaultOptions payload: %w", err)
}
if contains && !allowCustomFileVault {
return errors.New(DiskEncryptionProfileRestrictionErrMsg)
From 6d3e3da46c5fe7de0bbf4652c9cf51afc6eb3118 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:30 +0000
Subject: [PATCH 39/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
tools/android/android.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/android/android.go b/tools/android/android.go
index c4e5c54743f..95fb6c6ea5c 100644
--- a/tools/android/android.go
+++ b/tools/android/android.go
@@ -223,7 +223,7 @@ func devicesDelete(mgmt *androidmanagement.Service, enterpriseID string, deviceI
}
_, err := mgmt.Enterprises.Devices.Delete("enterprises/" + enterpriseID + "/devices/" + deviceID).Do()
if err != nil {
- log.Fatalf("Error listing devices: %v", err)
+ log.Fatalf("Error deleting device: %v", err)
}
log.Printf("Device %s deleted", deviceID)
}
From 51dd6a06796ac8527fe6ad47bd30fbaf0e8c8432 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 21 Sep 2026 05:45:31 +0000
Subject: [PATCH 40/40] fix(adhoc-sweep-fixes): 60 review findings across 40
files
---
website/assets/js/components/multifield.component.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/assets/js/components/multifield.component.js b/website/assets/js/components/multifield.component.js
index bf386ef14a6..8a3e2aeb34e 100644
--- a/website/assets/js/components/multifield.component.js
+++ b/website/assets/js/components/multifield.component.js
@@ -170,7 +170,7 @@ parasails.registerComponent('multifield', {
}
}
this.optionsForSelect = _.clone(this.selectOptions);
- if(this.currentFieldValues === [null]){
+ if(_.isEqual(this.currentFieldValues, [null]) || _.isEqual(this.currentFieldValues, [undefined])){
this.currentFieldValues = [];
}