From 2a0b082560f7fd741150a1e3881d79b01bbed70e Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:06 +0000
Subject: [PATCH 01/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/mdm/scep/depot/file/depot.go | 38 +++++++++++++++++------------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/server/mdm/scep/depot/file/depot.go b/server/mdm/scep/depot/file/depot.go
index a4a9874f18f..81e89cb4e10 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/slog"
"math/big"
"os"
"path/filepath"
@@ -26,7 +27,7 @@ func NewFileDepot(path string) (*fileDepot, error) {
fmt.Sprintf("%s/index.txt", path),
os.O_RDONLY|os.O_CREATE, 0o666)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("opening index.txt: %w", err)
}
defer f.Close()
return &fileDepot{dirPath: path}, nil
@@ -41,19 +42,19 @@ type fileDepot struct {
func (d *fileDepot) CA(pass []byte) ([]*x509.Certificate, *rsa.PrivateKey, error) {
caPEM, err := d.getFile("ca.pem")
if err != nil {
- return nil, nil, err
+ return nil, nil, fmt.Errorf("reading ca.pem: %w", err)
}
cert, err := loadCert(caPEM.Data)
if err != nil {
- return nil, nil, err
+ return nil, nil, fmt.Errorf("loading ca certificate: %w", err)
}
keyPEM, err := d.getFile("ca.key")
if err != nil {
- return nil, nil, err
+ return nil, nil, fmt.Errorf("reading ca.key: %w", err)
}
key, err := loadKey(keyPEM.Data, pass)
if err != nil {
- return nil, nil, err
+ return nil, nil, fmt.Errorf("loading ca key: %w", err)
}
return []*x509.Certificate{cert}, key, nil
}
@@ -100,7 +101,11 @@ func (d *fileDepot) Put(cn string, crt *x509.Certificate) error {
return err
}
if err := d.writeDB(cn, serial, filename, crt); err != nil {
- // TODO : remove certificate in case of writeDB problems
+ // remove the certificate file we just wrote so the on-disk PEM files
+ // stay in sync with index.txt; otherwise a leftover cert file with
+ // no corresponding index entry will desync the depot and cause a
+ // subsequent Put() with the same cn/serial to fail with "file exists".
+ os.Remove(filepath)
return err
}
@@ -115,19 +120,19 @@ func (d *fileDepot) Serial() (*big.Int, error) {
if err := d.check("serial"); err != nil {
// assuming it doesnt exist, create
if err := d.writeSerial(s); err != nil {
- return nil, err
+ return nil, fmt.Errorf("writing serial: %w", err)
}
return s, nil
}
file, err := os.Open(name)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("opening serial file: %w", err)
}
defer file.Close()
r := bufio.NewReader(file)
- data, err := r.ReadString('\r')
+ data, err := r.ReadString('\n')
if err != nil && err != io.EOF {
- return nil, err
+ return nil, fmt.Errorf("reading serial file: %w", err)
}
data = strings.TrimSuffix(data, "\r")
data = strings.TrimSuffix(data, "\n")
@@ -136,7 +141,7 @@ func (d *fileDepot) Serial() (*big.Int, error) {
return nil, errors.New("could not convert " + data + " to serial number")
}
if err := d.incrementSerial(serial); err != nil {
- return serial, err
+ return serial, fmt.Errorf("incrementing serial: %w", err)
}
return serial, nil
}
@@ -236,7 +241,7 @@ func (d *fileDepot) HasCN(_ string, allowTime int, cert *x509.Certificate, revok
return false, errors.New("DN " + dn + " already exists")
}
if revokeOldCertificate {
- fmt.Println("Revoking certificate with serial " + key + " from DB. Recreation of CRL needed.")
+ slog.Info("revoking certificate from DB, recreation of CRL needed", "serial", 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")
}
@@ -354,14 +359,17 @@ func (d *fileDepot) check(path string) error {
func (d *fileDepot) getFile(path string) (*file, error) {
if err := d.check(path); err != nil {
- return nil, err
+ return nil, fmt.Errorf("checking %s: %w", path, err)
}
fi, err := os.Stat(d.path(path))
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("stat %s: %w", path, err)
}
b, err := ioutil.ReadFile(d.path(path))
- return &file{fi, b}, err
+ if err != nil {
+ return nil, fmt.Errorf("reading %s: %w", path, err)
+ }
+ return &file{fi, b}, nil
}
func (d *fileDepot) path(name string) string {
From dd6bc00b9fea5fe6a8d77848da819a90139cafc7 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:08 +0000
Subject: [PATCH 02/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../android-proxy/get-android-enterprises.js | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/website/api/controllers/android-proxy/get-android-enterprises.js b/website/api/controllers/android-proxy/get-android-enterprises.js
index 69876343b56..e17d3fc7e07 100644
--- a/website/api/controllers/android-proxy/get-android-enterprises.js
+++ b/website/api/controllers/android-proxy/get-android-enterprises.js
@@ -18,6 +18,7 @@ module.exports = {
missingOriginHeader: { description: 'The request was missing an Origin header', responseType: 'badRequest'},
unauthorized: { description: 'Invalid authentication token.', responseType: 'unauthorized'},
notFound: { description: 'No Android enterprise found for this Fleet server.', responseType: 'notFound'},
+ rateLimited: { description: 'The Android management API rate limit was exceeded.', responseType: 'tooManyRequests' },
},
@@ -46,11 +47,18 @@ module.exports = {
throw 'notFound';
}
- if (thisAndroidEnterprise.fleetServerSecret !== fleetServerSecret) {
+ let crypto = require('crypto');
+ let providedSecretBuffer = Buffer.from(fleetServerSecret);
+ let storedSecretBuffer = Buffer.from(thisAndroidEnterprise.fleetServerSecret);
+ let secretsMatch = providedSecretBuffer.length === storedSecretBuffer.length &&
+ crypto.timingSafeEqual(providedSecretBuffer, storedSecretBuffer);
+
+ if (!secretsMatch) {
throw 'unauthorized';
}
// Get the Android enterprises list from Google
+ let isRateLimited = false;
try {
let enterprisesList = await sails.helpers.flow.build(async ()=>{
let { google } = require('googleapis');
@@ -93,6 +101,7 @@ module.exports = {
}).intercept({status: 429}, (err)=>{
// If the Android management API returns a 429 response, log an additional warning that will trigger a help-p1 alert.
sails.log.warn(`p1: Android management API rate limit exceeded!`);
+ isRateLimited = true;
return err;
}).intercept((err)=>{
// Re-throw the error for handling outside the intercept
@@ -114,6 +123,9 @@ module.exports = {
return { enterprises: filteredEnterprises };
} catch (err) {
+ if (isRateLimited) {
+ throw 'rateLimited';
+ }
throw new Error(`When attempting to list android enterprises, an error occurred. Error: ${err}`);
}
From b570a994c5392248afa6d92ee3c764ae6ed7eac2 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:09 +0000
Subject: [PATCH 03/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
tools/gitops-migrate/migrate.sh | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/tools/gitops-migrate/migrate.sh b/tools/gitops-migrate/migrate.sh
index 6ee60794caa..9aa6c97f765 100755
--- a/tools/gitops-migrate/migrate.sh
+++ b/tools/gitops-migrate/migrate.sh
@@ -74,7 +74,6 @@ validate_yaml() {
extract_keys_from_software() {
local software_file="$1"
local temp_file=$(mktemp -p .)
- chmod 666 $temp_file
# Extract the keys we need
{
@@ -93,7 +92,6 @@ remove_keys_from_software() {
# Create a temporary file with keys removed
local temp_file=$(mktemp -p .)
- chmod 666 $temp_file
yq eval --output-format=yaml 'del(.self_service, .categories, .labels_include_any, .labels_exclude_any)' "$software_file" > "$temp_file"
# Replace the original file
@@ -190,7 +188,7 @@ process_team_file() {
# Clean up temp file
rm -f "$keys_temp_file"
- PROCESSED_PACKAGED=$((PROCESSED_PACKAGES+1))
+ PROCESSED_PACKAGES=$((PROCESSED_PACKAGES+1))
echo -e "${GREEN} ✓ Package processed successfully${NC}"
done
@@ -333,3 +331,4 @@ main() {
# Run main function with all script arguments
main "$@"
+
From 7933bb9e5011989a7b4a92ce3a3c1c46fd0e5a7d Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:11 +0000
Subject: [PATCH 04/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/logging/pubsub.go | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/server/logging/pubsub.go b/server/logging/pubsub.go
index 6f5b19fedc8..f196ee854fd 100644
--- a/server/logging/pubsub.go
+++ b/server/logging/pubsub.go
@@ -78,9 +78,13 @@ func (w *pubSubLogWriter) Write(ctx context.Context, logs []json.RawMessage) err
}
if len(data)+estimateAttributeSize(attributes) > pubsub.MaxPublishRequestBytes {
+ truncateLen := 100
+ if len(log) < truncateLen {
+ truncateLen = len(log)
+ }
w.logger.InfoContext(ctx, "dropping log over 10MB PubSub limit",
"size", len(data),
- "log", string(log[:100])+"...",
+ "log", string(log[:truncateLen])+"...",
)
continue
}
@@ -95,6 +99,9 @@ func (w *pubSubLogWriter) Write(ctx context.Context, logs []json.RawMessage) err
// Wait for each message to be pushed to the server
for _, result := range results {
+ if result == nil {
+ continue
+ }
_, err := result.Get(ctx)
if err != nil {
return ctxerr.Wrap(ctx, err, "pubsub publish")
From 7c2528bda873bcefe412783285a37629f36f3303 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:13 +0000
Subject: [PATCH 05/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/mdm/nanomdm/http/mdm/mdm.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/server/mdm/nanomdm/http/mdm/mdm.go b/server/mdm/nanomdm/http/mdm/mdm.go
index f6f620bf67c..c3c113290e2 100644
--- a/server/mdm/nanomdm/http/mdm/mdm.go
+++ b/server/mdm/nanomdm/http/mdm/mdm.go
@@ -57,6 +57,7 @@ func CheckinHandler(svc service.Checkin, logger log.Logger) http.HandlerFunc {
httpStatus = statusErr.Status
}
http.Error(w, http.StatusText(httpStatus), httpStatus)
+ return
}
_, _ = w.Write(respBytes)
}
@@ -86,6 +87,7 @@ func CommandAndReportResultsHandler(svc service.CommandAndReportResults, logger
httpStatus = statusErr.Status
}
http.Error(w, http.StatusText(httpStatus), httpStatus)
+ return
}
_, _ = w.Write(respBytes)
}
From 4aa44bfa5db4a82a838259b220c822a1082687d2 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:14 +0000
Subject: [PATCH 06/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/service/externalsvc/jira.go | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/server/service/externalsvc/jira.go b/server/service/externalsvc/jira.go
index c142c22f37f..d076de03828 100644
--- a/server/service/externalsvc/jira.go
+++ b/server/service/externalsvc/jira.go
@@ -3,6 +3,7 @@ package externalsvc
import (
"context"
"errors"
+ "log"
"net"
"net/http"
"strconv"
@@ -118,6 +119,11 @@ func doWithRetry(fn func() (*jira.Response, error)) error {
}
}
+ if resp == nil {
+ // no response received (e.g. connection error); treat as retryable
+ return err
+ }
+
if resp.StatusCode >= http.StatusInternalServerError {
// 500+ status, can be worth retrying
return err
@@ -128,8 +134,11 @@ func doWithRetry(fn func() (*jira.Response, error)) error {
// https://developer.atlassian.com/cloud/jira/platform/rate-limiting/
// for details.
rawAfter := resp.Header.Get("Retry-After")
- afterSecs, err := strconv.ParseInt(rawAfter, 10, 0)
- if err == nil && (time.Duration(afterSecs)*time.Second) < maxWaitForRetryAfter {
+ afterSecs, parseErr := strconv.ParseInt(rawAfter, 10, 0)
+ if parseErr != nil {
+ log.Printf("jira: failed to parse Retry-After header %q: %v", rawAfter, parseErr)
+ }
+ if parseErr == nil && (time.Duration(afterSecs)*time.Second) < maxWaitForRetryAfter {
// the retry-after duration is reasonable, wait for it and return a
// retryable error so that we try again.
time.Sleep(time.Duration(afterSecs) * time.Second)
From 3edd0f0da52ff89c80157edc67f18962bc753703 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:16 +0000
Subject: [PATCH 07/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../EndUserAuthSection/helpers.tests.ts | 96 ++++++++++---------
1 file changed, 50 insertions(+), 46 deletions(-)
diff --git a/frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts b/frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts
index 7e2848753b7..1368d694ae3 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts
+++ b/frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts
@@ -79,23 +79,25 @@ describe("IdPSection helpers", () => {
).toBe(true); // metadata or metadata_url must be present
});
- expect(
- isMissingAnyRequiredField({
- entity_id: "entityId",
- idp_name: "idpImageUrl",
- metadata: "",
- metadata_url: "metadataUrl",
- })
- ).toBe(false); // metadata is not required if metadata_url is present
+ it("returns false if metadata or metadata_url is present", () => {
+ expect(
+ isMissingAnyRequiredField({
+ entity_id: "entityId",
+ idp_name: "idpImageUrl",
+ metadata: "",
+ metadata_url: "metadataUrl",
+ })
+ ).toBe(false); // metadata is not required if metadata_url is present
- expect(
- isMissingAnyRequiredField({
- entity_id: "entityId",
- idp_name: "idpImageUrl",
- metadata: "metadata",
- metadata_url: "",
- })
- ).toBe(false); // metadata_url is not required if metadata is present
+ expect(
+ isMissingAnyRequiredField({
+ entity_id: "entityId",
+ idp_name: "idpImageUrl",
+ metadata: "metadata",
+ metadata_url: "",
+ })
+ ).toBe(false); // metadata_url is not required if metadata is present
+ });
});
describe("validateFormDataIdP", () => {
@@ -213,37 +215,39 @@ describe("IdPSection helpers", () => {
}); // all fields valid
});
- expect(
- newFormDataIdp({
- entity_id: "entityId ",
- idp_name: " idpImageUrl",
- issuer_uri: "issuerUri",
+ it("returns expected new form data for edge cases", () => {
+ expect(
+ newFormDataIdp({
+ entity_id: "entityId ",
+ idp_name: " idpImageUrl",
+ issuer_uri: "issuerUri",
+ metadata: "metadata",
+ metadata_url: " https://metadataUrl.com ",
+ })
+ ).toEqual({
+ entity_id: "entityId",
+ idp_name: "idpImageUrl",
metadata: "metadata",
- metadata_url: " https://metadataUrl.com ",
- })
- ).toEqual({
- entity_id: "entityId",
- idp_name: "idpImageUrl",
- metadata: "metadata",
- metadata_url: "https://metadataUrl.com",
- }); // whitespace trimmed
-
- expect(newFormDataIdp(undefined)).toEqual({
- entity_id: "",
- idp_name: "",
- metadata: "",
- metadata_url: "",
- }); // all fields missing
-
- expect(
- newFormDataIdp({
+ metadata_url: "https://metadataUrl.com",
+ }); // whitespace trimmed
+
+ expect(newFormDataIdp(undefined)).toEqual({
+ entity_id: "",
+ idp_name: "",
+ metadata: "",
+ metadata_url: "",
+ }); // all fields missing
+
+ expect(
+ newFormDataIdp({
+ entity_id: "entityId",
+ } as IEndUserAuthentication)
+ ).toEqual({
entity_id: "entityId",
- } as IEndUserAuthentication)
- ).toEqual({
- entity_id: "entityId",
- idp_name: "",
- metadata: "",
- metadata_url: "",
- }); // idp_name, metadata, metadata_url missing
+ idp_name: "",
+ metadata: "",
+ metadata_url: "",
+ }); // idp_name, metadata, metadata_url missing
+ });
});
});
From 1edcda0b4c1996f05ad5fadd045d1ecc5b54f9bf Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:18 +0000
Subject: [PATCH 08/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
tools/github-manage/pkg/ghapi/issues.go | 35 ++++++++++++++++---------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/tools/github-manage/pkg/ghapi/issues.go b/tools/github-manage/pkg/ghapi/issues.go
index 32e00e31791..584603c8662 100644
--- a/tools/github-manage/pkg/ghapi/issues.go
+++ b/tools/github-manage/pkg/ghapi/issues.go
@@ -127,14 +127,14 @@ func RemoveIssueFromProject(issueNumber int, projectID int) error {
if err.Error() == fmt.Sprintf("issue #%d not found in project %d", issueNumber, projectID) {
return nil
}
- return fmt.Errorf("failed to get project item ID: %v", err)
+ return fmt.Errorf("failed to get project item ID: %w", err)
}
// Remove the item using the project ID and item ID
command := fmt.Sprintf("gh project item-delete %d --owner fleetdm --id %s", projectID, itemID)
_, err = RunCommandAndReturnOutput(command)
if err != nil {
- return fmt.Errorf("failed to remove issue %d from project %d: %v", issueNumber, projectID, err)
+ return fmt.Errorf("failed to remove issue %d from project %d: %w", issueNumber, projectID, err)
}
return nil
@@ -145,19 +145,19 @@ func SyncEstimateField(issueNumber int, sourceProjectID, targetProjectID int) er
// Get the source project item to find the current estimate
sourceItemID, err := GetProjectItemID(issueNumber, sourceProjectID)
if err != nil {
- return fmt.Errorf("failed to get source project item ID: %v", err)
+ return fmt.Errorf("failed to get source project item ID: %w", err)
}
// Get the target project item
targetItemID, err := GetProjectItemID(issueNumber, targetProjectID)
if err != nil {
- return fmt.Errorf("failed to get target project item ID: %v", err)
+ return fmt.Errorf("failed to get target project item ID: %w", err)
}
// Get the estimate value from the source project using GraphQL
sourceEstimate, err := GetProjectItemFieldValue(sourceItemID, sourceProjectID, "Estimate")
if err != nil {
- return fmt.Errorf("failed to get source estimate: %v", err)
+ return fmt.Errorf("failed to get source estimate: %w", err)
}
if sourceEstimate == "" || sourceEstimate == "0" {
@@ -167,7 +167,7 @@ func SyncEstimateField(issueNumber int, sourceProjectID, targetProjectID int) er
// Set the estimate in the target project
err = SetProjectItemFieldValue(targetItemID, targetProjectID, "Estimate", sourceEstimate)
if err != nil {
- return fmt.Errorf("failed to set target estimate: %v", err)
+ return fmt.Errorf("failed to set target estimate: %w", err)
}
return nil
@@ -178,19 +178,19 @@ func SetCurrentSprint(issueNumber int, projectID int) error {
// Get the project item ID
itemID, err := GetProjectItemID(issueNumber, projectID)
if err != nil {
- return fmt.Errorf("failed to get project item ID: %v", err)
+ return fmt.Errorf("failed to get project item ID: %w", err)
}
// Look up the sprint field ID
sprintField, err := LookupProjectFieldName(projectID, "sprint")
if err != nil {
- return fmt.Errorf("failed to lookup sprint field: %v", err)
+ return fmt.Errorf("failed to lookup sprint field: %w", err)
}
// Use the general field setting function to set the sprint field to @current
err = SetProjectItemFieldValue(itemID, projectID, sprintField.Name, "@current")
if err != nil {
- return fmt.Errorf("failed to set current sprint: %v", err)
+ return fmt.Errorf("failed to set current sprint: %w", err)
}
return nil
@@ -201,13 +201,13 @@ func SetIssueStatus(issueNumber int, projectID int, status string) error {
// Get the project item ID
itemID, err := GetProjectItemID(issueNumber, projectID)
if err != nil {
- return fmt.Errorf("failed to get project item ID: %v", err)
+ return fmt.Errorf("failed to get project item ID: %w", err)
}
// Use the general field setting function to set the Status field
err = SetProjectItemFieldValue(itemID, projectID, "Status", status)
if err != nil {
- return fmt.Errorf("failed to set status: %v", err)
+ return fmt.Errorf("failed to set status: %w", err)
}
return nil
@@ -371,7 +371,10 @@ listLoop:
for i, issue := range issues {
// if we find an error, we'll drain concurrent executions and then bail
- if stopError != nil {
+ mu.Lock()
+ stopped := stopError != nil
+ mu.Unlock()
+ if stopped {
break
}
@@ -400,7 +403,9 @@ listLoop:
fmt.Fprintf(os.Stderr, " ERROR\n")
mu.Unlock()
}
+ mu.Lock()
stopError = err
+ mu.Unlock()
logger.Errorf("Error checking timeline for issue #%d: %v", iss.Number, err)
return
}
@@ -423,5 +428,9 @@ listLoop:
fmt.Fprintf(os.Stderr, " done\n")
}
- return filteredIssues, stopError
+ mu.Lock()
+ finalErr := stopError
+ mu.Unlock()
+
+ return filteredIssues, finalErr
}
From 0d142517fab5d2a5124741f3ecf76d81c6bfcfd4 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:20 +0000
Subject: [PATCH 09/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../inputs/homebrew/scripts/expressvpn-install.sh | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/ee/maintained-apps/inputs/homebrew/scripts/expressvpn-install.sh b/ee/maintained-apps/inputs/homebrew/scripts/expressvpn-install.sh
index f7e7d755e75..d2d0ec80d09 100755
--- a/ee/maintained-apps/inputs/homebrew/scripts/expressvpn-install.sh
+++ b/ee/maintained-apps/inputs/homebrew/scripts/expressvpn-install.sh
@@ -4,6 +4,11 @@
APPDIR="/Applications/"
TMPDIR=$(mktemp -d)
+cleanup() {
+ rm -rf "$TMPDIR"
+}
+trap cleanup EXIT
+
# functions
quit_application() {
@@ -16,8 +21,8 @@ quit_application() {
fi
local console_user
- console_user=$(stat -f "%Su" /dev/console)
- if [[ $EUID -eq 0 && "$console_user" == "root" ]]; then
+ console_user=$(stat -f "%Su" /dev/console 2>/dev/null || echo "")
+ if [[ -z "$console_user" || "$console_user" == "root" || "$console_user" == "loginwindow" ]]; then
echo "Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'."
return
fi
@@ -83,3 +88,4 @@ if [ $EXIT_CODE -ne 0 ]; then
exit $EXIT_CODE
fi
+
From 7feaf570127d65e433b93bb11b36560c1b52235f Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:21 +0000
Subject: [PATCH 10/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../components/InventoryVersions/InventoryVersions.tsx | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/frontend/pages/hosts/details/components/InventoryVersions/InventoryVersions.tsx b/frontend/pages/hosts/details/components/InventoryVersions/InventoryVersions.tsx
index c40d3740a99..e7819685a65 100644
--- a/frontend/pages/hosts/details/components/InventoryVersions/InventoryVersions.tsx
+++ b/frontend/pages/hosts/details/components/InventoryVersions/InventoryVersions.tsx
@@ -114,7 +114,7 @@ const InventoryVersion = ({
);
return (
-
+
{sigInfo?.hash_sha256 && (
)}
- {installedVersions.map((installedVersion) => {
+ {installedVersions.map((installedVersion, index) => {
return (
Date: Mon, 14 Sep 2026 06:47:23 +0000
Subject: [PATCH 11/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../CustomValueContainer/CustomValueContainer.tsx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/frontend/pages/hosts/ManageHostsPage/components/CustomValueContainer/CustomValueContainer.tsx b/frontend/pages/hosts/ManageHostsPage/components/CustomValueContainer/CustomValueContainer.tsx
index 27bda6d19af..329c851fe2f 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/CustomValueContainer/CustomValueContainer.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/components/CustomValueContainer/CustomValueContainer.tsx
@@ -5,17 +5,17 @@ import Icon from "components/Icon";
const baseClass = "custom-dropdown-indicator";
-const CustomDropdownIndicator = ({ props }: ValueContainerProps | any) => {
+const CustomValueContainer = (props: ValueContainerProps) => {
const { children } = props;
// no access to hover state here from react-select so that is done in the scss
// file of LabelFilterSelect.
return (
-
+
{children}
-
+
);
};
-export default CustomDropdownIndicator;
+export default CustomValueContainer;
From 30ea137ab21e6707a3520cec3b174377c800874c Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:24 +0000
Subject: [PATCH 12/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/service/async/collect.go | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/server/service/async/collect.go b/server/service/async/collect.go
index ed4cccbb56a..5899a353e8c 100644
--- a/server/service/async/collect.go
+++ b/server/service/async/collect.go
@@ -106,7 +106,13 @@ func (c *collector) exec(ctx context.Context) {
c.addSkipStats(failed)
return
}
- defer conn.Do("DEL", keyLock) //nolint:errcheck
+ defer func() {
+ if _, err := conn.Do("DEL", keyLock); err != nil {
+ if c.errHandler != nil {
+ c.errHandler(c.name, err)
+ }
+ }
+ }()
// at this point, the lock has been acquired, execute the collector handler
ctx, cancel := context.WithTimeout(ctx, time.Duration(c.lockTimeout.Seconds())*time.Second)
@@ -179,9 +185,11 @@ func (c *collector) nextRunAfter() time.Duration {
var jitter time.Duration
if c.jitterPct > 0 {
maxJitter := time.Duration(c.jitterPct) * c.execInterval / time.Duration(100.0)
- randDuration, err := rand.Int(rand.Reader, big.NewInt(int64(maxJitter)))
- if err == nil {
- jitter = time.Duration(randDuration.Int64())
+ if maxJitter > 0 {
+ randDuration, err := rand.Int(rand.Reader, big.NewInt(int64(maxJitter)))
+ if err == nil {
+ jitter = time.Duration(randDuration.Int64())
+ }
}
}
From 1c73ef2b4afe630a3cf042b44695887cf6eabae2 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:25 +0000
Subject: [PATCH 13/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../delete-duplicate-scep-certificates.sh | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/server/service/embedded_scripts/delete-duplicate-scep-certificates.sh b/server/service/embedded_scripts/delete-duplicate-scep-certificates.sh
index 5df7ceeca84..51b8ecaa256 100755
--- a/server/service/embedded_scripts/delete-duplicate-scep-certificates.sh
+++ b/server/service/embedded_scripts/delete-duplicate-scep-certificates.sh
@@ -59,6 +59,14 @@ trap 'rm -f "$tmpfile" "$tmpfile.raw" "$tmpfile.err"' EXIT
security find-certificate -a -c "$CN" -Z -p "$KEYCHAIN" >"$tmpfile.raw" 2>"$tmpfile.err" || true
+begin_count=$(grep -c -- "-----BEGIN CERTIFICATE-----" "$tmpfile.raw" || true)
+end_count=$(grep -c -- "-----END CERTIFICATE-----" "$tmpfile.raw" || true)
+hash_count=$(grep -c "^SHA-1 hash:" "$tmpfile.raw" || true)
+if [ "$begin_count" -ne "$end_count" ] || [ "$begin_count" -ne "$hash_count" ]; then
+ echo "Error: unexpected output from 'security find-certificate' (found $hash_count hash(es), $begin_count BEGIN marker(s), $end_count END marker(s)); refusing to proceed to avoid deleting the wrong identity." >&2
+ exit 1
+fi
+
# Split the raw output into individual cert blocks and extract hash + date.
current_hash=""
current_pem=""
@@ -66,6 +74,10 @@ while IFS= read -r line; do
case "$line" in
"SHA-1 hash:"*)
current_hash=$(echo "$line" | awk '{print $NF}')
+ if ! echo "$current_hash" | grep -Eq '^[0-9A-Fa-f]{40}$'; then
+ echo "Error: malformed SHA-1 hash encountered (\"$current_hash\"); refusing to proceed." >&2
+ exit 1
+ fi
;;
"-----BEGIN CERTIFICATE-----")
current_pem="$line"$'\n'
@@ -73,7 +85,11 @@ while IFS= read -r line; do
"-----END CERTIFICATE-----")
current_pem+="$line"$'\n'
not_before=$(echo "$current_pem" | openssl x509 -noout -startdate 2>/dev/null | cut -d= -f2)
- epoch=$(date -j -f "%b %e %T %Y %Z" "$not_before" "+%s" 2>/dev/null || echo "0")
+ epoch=$(date -j -f "%b %e %T %Y %Z" "$not_before" "+%s" 2>/dev/null || echo "")
+ if [ -z "$epoch" ]; then
+ echo "Error: failed to parse Not Before date (\"$not_before\") for certificate $current_hash; refusing to proceed to avoid deleting the wrong identity." >&2
+ exit 1
+ fi
echo "$epoch $current_hash" >> "$tmpfile"
current_pem=""
;;
From 1ac2181a9d3d475505dfb8aa1bad31c5b9a2021c Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:27 +0000
Subject: [PATCH 14/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
tools/terraform/provider/teams_resource.go | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/tools/terraform/provider/teams_resource.go b/tools/terraform/provider/teams_resource.go
index 48731a4fa73..872f6d84f7b 100644
--- a/tools/terraform/provider/teams_resource.go
+++ b/tools/terraform/provider/teams_resource.go
@@ -131,7 +131,13 @@ func (r *teamsResource) Create(ctx context.Context, req resource.CreateRequest,
resp.Diagnostics.Append(diag.NewErrorDiagnostic(
"failed to convert fleet api return to TF structs",
fmt.Sprintf("failed to convert fleet api return to TF structs: %s", err)))
- _ = r.client.DeleteTeam(newTeam.Team.ID) // Problematic. :-/
+ if delErr := r.client.DeleteTeam(newTeam.Team.ID); delErr != nil {
+ resp.Diagnostics.Append(diag.NewErrorDiagnostic(
+ "failed to clean up after failed team conversion",
+ fmt.Sprintf("failed to delete team %s while cleaning up "+
+ "failure converting API response: %s. Team will need to be "+
+ "manually deleted.", plan.Name.ValueString(), delErr)))
+ }
return
}
@@ -247,6 +253,19 @@ func (r *teamsResource) Update(ctx context.Context, req resource.UpdateRequest,
}
}
+ if upTeam == nil {
+ // Nothing was actually updated on the Fleet side (e.g. agent options
+ // changed to an empty string and name/description are unchanged), so
+ // fetch the current team to safely populate state.
+ upTeam, err = r.client.GetTeam(state.Id.ValueInt64())
+ if err != nil {
+ resp.Diagnostics.Append(diag.NewErrorDiagnostic(
+ "Failed to get team",
+ fmt.Sprintf("Failed to get team: %s", err)))
+ return
+ }
+ }
+
err = teamModelToTF(ctx, upTeam, &state)
if err != nil {
resp.Diagnostics.Append(diag.NewErrorDiagnostic(
@@ -297,3 +316,4 @@ func (r *teamsResource) Delete(ctx context.Context, req resource.DeleteRequest,
resp.State.RemoveResource(ctx)
}
+
From ca9eaa79b90235b37e03b2825fdaa09de6f8575a Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:29 +0000
Subject: [PATCH 15/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
website/assets/js/pages/docs/vital-details.page.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/website/assets/js/pages/docs/vital-details.page.js b/website/assets/js/pages/docs/vital-details.page.js
index 20f1a74ccb7..7d2d853626c 100644
--- a/website/assets/js/pages/docs/vital-details.page.js
+++ b/website/assets/js/pages/docs/vital-details.page.js
@@ -85,11 +85,13 @@ parasails.registerPage('vital-details', {
})();
$('[purpose="copy-button"]').on('click', async function() {
let code = $(this).closest('[purpose="codeblock"]').find('pre:visible code').text();
- $(this).addClass('copied');
- await setTimeout(()=>{
- $(this).removeClass('copied');
- }, 2000);
- navigator.clipboard.writeText(code);
+ if(code) {
+ $(this).addClass('copied');
+ await setTimeout(()=>{
+ $(this).removeClass('copied');
+ }, 2000);
+ navigator.clipboard.writeText(code);
+ }
});
// Add a scroll event listener to shift the platform filters upwards when the header is hidden.
window.addEventListener('scroll', this.handleScrollingPlatformFilters);
@@ -148,3 +150,4 @@ parasails.registerPage('vital-details', {
}
},
});
+
From 40d7d16ffd5ba42327c1ea4e4a26401df8f37068 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:30 +0000
Subject: [PATCH 16/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/datastore/mysql/secret_variables.go | 25 ++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/server/datastore/mysql/secret_variables.go b/server/datastore/mysql/secret_variables.go
index 0a259be67e2..859a797cb00 100644
--- a/server/datastore/mysql/secret_variables.go
+++ b/server/datastore/mysql/secret_variables.go
@@ -358,9 +358,15 @@ func (ds *Datastore) expandEmbeddedSecrets(ctx context.Context, document string)
// Detect document format so we can escape the secret value appropriately.
// XML detection is aggressive because Windows profiles do not begin with
Date: Mon, 14 Sep 2026 06:47:31 +0000
Subject: [PATCH 17/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
orbit/pkg/execuser/execuser_windows.go | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/orbit/pkg/execuser/execuser_windows.go b/orbit/pkg/execuser/execuser_windows.go
index 215e295ae50..a4a36f7a99a 100644
--- a/orbit/pkg/execuser/execuser_windows.go
+++ b/orbit/pkg/execuser/execuser_windows.go
@@ -24,10 +24,12 @@ var (
moduserenv *windows.LazyDLL = windows.NewLazySystemDLL("userenv.dll")
procWTSEnumerateSessionsW *windows.LazyProc = modwtsapi32.NewProc("WTSEnumerateSessionsW")
+ procWTSFreeMemory *windows.LazyProc = modwtsapi32.NewProc("WTSFreeMemory")
procWTSGetActiveConsoleSessionId *windows.LazyProc = modkernel32.NewProc("WTSGetActiveConsoleSessionId")
procWTSQueryUserToken *windows.LazyProc = modwtsapi32.NewProc("WTSQueryUserToken")
procDuplicateTokenEx *windows.LazyProc = modadvapi32.NewProc("DuplicateTokenEx")
procCreateEnvironmentBlock *windows.LazyProc = moduserenv.NewProc("CreateEnvironmentBlock")
+ procDestroyEnvironmentBlock *windows.LazyProc = moduserenv.NewProc("DestroyEnvironmentBlock")
procCreateProcessAsUser *windows.LazyProc = modadvapi32.NewProc("CreateProcessAsUserW")
)
@@ -171,11 +173,17 @@ func wtsEnumerateSessions() ([]*WTS_SESSION_INFO, error) {
if returnCode, _, err := procWTSEnumerateSessionsW.Call(WTS_CURRENT_SERVER_HANDLE, 0, 1, uintptr(unsafe.Pointer(&sessionInformation)), uintptr(unsafe.Pointer(&sessionCount))); returnCode == 0 {
return nil, fmt.Errorf("call native WTSEnumerateSessionsW: %s", err)
}
+ defer procWTSFreeMemory.Call(uintptr(sessionInformation)) //nolint:errcheck
structSize := unsafe.Sizeof(WTS_SESSION_INFO{})
current := uintptr(sessionInformation)
for i := 0; i < sessionCount; i++ {
- sessionList = append(sessionList, (*WTS_SESSION_INFO)(unsafe.Pointer(current)))
+ sessionInfo := (*WTS_SESSION_INFO)(unsafe.Pointer(current))
+ sessionList = append(sessionList, &WTS_SESSION_INFO{
+ SessionID: sessionInfo.SessionID,
+ WinStationName: sessionInfo.WinStationName,
+ State: sessionInfo.State,
+ })
current += structSize
}
@@ -228,10 +236,12 @@ func startProcessAsCurrentUser(appPath, cmdLine, workDir string) error {
if userToken, err = duplicateUserTokenFromSessionID(sessionId); err != nil {
return fmt.Errorf("get duplicate user token for current user session: %s", err)
}
+ defer windows.CloseHandle(windows.Handle(userToken)) //nolint:errcheck
if returnCode, _, err := procCreateEnvironmentBlock.Call(uintptr(unsafe.Pointer(&envInfo)), uintptr(userToken), 1); returnCode == 0 {
return fmt.Errorf("create environment details for process: %s", err)
}
+ defer procDestroyEnvironmentBlock.Call(uintptr(envInfo)) //nolint:errcheck
// TODO(lucas): Test out creation flags and startup info values.
creationFlags := CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE
@@ -251,6 +261,8 @@ func startProcessAsCurrentUser(appPath, cmdLine, workDir string) error {
); returnCode == 0 {
return fmt.Errorf("create process as user: %s", err)
}
+ windows.CloseHandle(processInfo.Process) //nolint:errcheck
+ windows.CloseHandle(processInfo.Thread) //nolint:errcheck
return nil
}
From 0ee5e96de7df7f5585b4eb214f8034a17e5f80d5 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:32 +0000
Subject: [PATCH 18/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
...2112642_MigratePrimoFailingPoliciesAutomations.go | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/server/datastore/mysql/migrations/tables/20250902112642_MigratePrimoFailingPoliciesAutomations.go b/server/datastore/mysql/migrations/tables/20250902112642_MigratePrimoFailingPoliciesAutomations.go
index 99eb95deb0e..2bd3fc4f71e 100644
--- a/server/datastore/mysql/migrations/tables/20250902112642_MigratePrimoFailingPoliciesAutomations.go
+++ b/server/datastore/mysql/migrations/tables/20250902112642_MigratePrimoFailingPoliciesAutomations.go
@@ -4,7 +4,7 @@ import (
"database/sql"
"encoding/json"
"fmt"
- "os"
+ "log"
"github.com/jmoiron/sqlx"
"github.com/jmoiron/sqlx/reflectx"
@@ -16,12 +16,9 @@ func init() {
func Up_20250902112642(tx *sql.Tx) error {
// Idempotent migration.
- // Only run this migration if FLEET_PARTNERSHIPS_ENABLE_PRIMO is set to true
- enablePrimo := os.Getenv("FLEET_PARTNERSHIPS_ENABLE_PRIMO")
- if enablePrimo != "true" && enablePrimo != "1" {
- // Skip migration if not in Primo mode
- return nil
- }
+ // This migration always runs; it is not gated on any runtime environment
+ // variable, since migration behavior must be deterministic regardless of
+ // deployment-specific configuration.
txx := sqlx.Tx{Tx: tx, Mapper: reflectx.NewMapperFunc("db", sqlx.NameMapper)}
@@ -82,6 +79,7 @@ func Up_20250902112642(tx *sql.Tx) error {
case uint:
policyID = v
default:
+ log.Printf("migration 20250902112642: unexpected policy_ids entry type %T (value %v) in failing_policies_webhook; skipping this policy ID", policyIDInterface, policyIDInterface)
continue
}
From 41783eba496030b242228c0196fff939a2e67441 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:34 +0000
Subject: [PATCH 19/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/vulnerabilities/io/github.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/server/vulnerabilities/io/github.go b/server/vulnerabilities/io/github.go
index 0dea9be7096..b03544cd91e 100644
--- a/server/vulnerabilities/io/github.go
+++ b/server/vulnerabilities/io/github.go
@@ -110,7 +110,7 @@ func (gh GitHubClient) MacOfficeReleaseNotes(ctx context.Context) (MetadataFileN
}
// Nothing found ...
- return MetadataFileName{}, "", nil
+ return MetadataFileName{}, "", errors.New("no MacOffice release notes found")
}
// list iterates over the latest release in our Github NVD repo
@@ -128,7 +128,7 @@ func (gh GitHubClient) list(ctx context.Context, prefix string, ctor func(fileNa
&github.ListOptions{Page: 0, PerPage: 10},
)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("list github releases for prefix %q: %w", prefix, err)
}
if r.StatusCode != http.StatusOK {
@@ -143,7 +143,7 @@ func (gh GitHubClient) list(ctx context.Context, prefix string, ctor func(fileNa
if strings.HasPrefix(name, prefix) {
metadataFileName, err := ctor(name)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("build metadata file name for asset %q (prefix %q): %w", name, prefix, err)
}
results[metadataFileName] = e.GetBrowserDownloadURL()
}
From 6f0e1fbfab0a611809e4b0c68eb84dca9f1cac2f Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:35 +0000
Subject: [PATCH 20/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/vulnerabilities/osv/sync.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/server/vulnerabilities/osv/sync.go b/server/vulnerabilities/osv/sync.go
index f9608f59220..ef3f7529912 100644
--- a/server/vulnerabilities/osv/sync.go
+++ b/server/vulnerabilities/osv/sync.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/fleetdm/fleet/v4/server/fleet"
+ "github.com/rs/zerolog/log"
)
const (
@@ -43,9 +44,8 @@ func Refresh(
upToDateVersions := make([]string, 0, len(syncResult.Downloaded)+len(syncResult.Skipped))
upToDateVersions = append(upToDateVersions, syncResult.Downloaded...)
upToDateVersions = append(upToDateVersions, syncResult.Skipped...)
- err = removeOldOSVArtifacts(now, vulnPath, upToDateVersions)
- if err != nil {
- return syncResult.Downloaded, fmt.Errorf("warning: failed to clean up old OSV artifacts: %w", err)
+ if err := removeOldOSVArtifacts(now, vulnPath, upToDateVersions); err != nil {
+ log.Warn().Err(err).Msg("failed to clean up old OSV artifacts")
}
return syncResult.Downloaded, nil
@@ -270,7 +270,7 @@ func RefreshRHEL(
upToDateVersions = append(upToDateVersions, syncResult.Downloaded...)
upToDateVersions = append(upToDateVersions, syncResult.Skipped...)
if err := removeOldRHELOSVArtifacts(now, vulnPath, upToDateVersions); err != nil {
- return syncResult.Downloaded, fmt.Errorf("warning: failed to clean up old RHEL OSV artifacts: %w", err)
+ log.Warn().Err(err).Msg("failed to clean up old RHEL OSV artifacts")
}
return syncResult.Downloaded, nil
From 85946b11297da475b4fa876ea74941acf58fdec0 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:36 +0000
Subject: [PATCH 21/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../software-library/tools/import-data/main.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/cmd/osquery-perf/software-library/tools/import-data/main.go b/cmd/osquery-perf/software-library/tools/import-data/main.go
index 3db689d8c79..fb4e1d4b886 100644
--- a/cmd/osquery-perf/software-library/tools/import-data/main.go
+++ b/cmd/osquery-perf/software-library/tools/import-data/main.go
@@ -12,7 +12,7 @@ import (
"regexp"
"strings"
- _ "github.com/mattn/go-sqlite3"
+ "github.com/mattn/go-sqlite3"
)
// SoftwareEntry represents a software item from server data
@@ -46,7 +46,7 @@ var knownPublicSoftware = []string{
// - 172.16.0.0/12 (172.16.x.x - 172.31.x.x)
// - 192.168.0.0/16 (192.168.x.x)
// - 127.0.0.0/8 (127.x.x.x - loopback)
-var privateIPRegex = regexp.MustCompile(`^(10(\.\d{1,3}){3}|127(\.\d{1,3}){3}|192\.168(\.\d{1,3}){2}|172\.(1[6-9]|2[0-9]|3[0-1])(\.\d{1,3}){2})`)
+var privateIPRegex = regexp.MustCompile(`^(10(\.\d{1,3}){3}|127(\.\d{1,3}){3}|192\.168(\.\d{1,3}){2}|172\.(1[6-9]|2[0-9]|3[0-1])(\.\d{1,3}){2})$`)
type ImportStats struct {
Total int
@@ -246,7 +246,8 @@ func (imp *Importer) importEntry(entry SoftwareEntry) {
if !imp.dryRun {
err := imp.insertSoftware(entry)
if err != nil {
- if strings.Contains(err.Error(), "UNIQUE constraint failed") {
+ var sqliteErr sqlite3.Error
+ if errors.As(err, &sqliteErr) && sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique {
imp.stats.Duplicates++
if imp.verbose {
fmt.Printf(" ⏭️ Duplicate: %s v%s\n", entry.Name, entry.Version)
From 130bcea6e07f339e195c54ed5acf450b8d2efedd Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:38 +0000
Subject: [PATCH 22/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../admin/OrgSettingsPage/cards/Info/Info.tsx | 33 ++++++++++++++++---
1 file changed, 28 insertions(+), 5 deletions(-)
diff --git a/frontend/pages/admin/OrgSettingsPage/cards/Info/Info.tsx b/frontend/pages/admin/OrgSettingsPage/cards/Info/Info.tsx
index e15439621e4..40e7a1a69b5 100644
--- a/frontend/pages/admin/OrgSettingsPage/cards/Info/Info.tsx
+++ b/frontend/pages/admin/OrgSettingsPage/cards/Info/Info.tsx
@@ -184,20 +184,37 @@ const Info = ({
const onInputChange = ({ name, value }: IInputFieldParseTarget) => {
setFormData({ ...formData, [name]: value });
- setFormErrors({});
+ setFormErrors((prevErrors) => {
+ const newFormData = { ...formData, [name]: value };
+ const newErrs = computeFormErrorsFor(newFormData);
+ const updatedErrors: IOrgInfoFormErrors = { ...prevErrors };
+ (Object.keys(prevErrors) as (keyof IOrgInfoFormErrors)[]).forEach(
+ (key) => {
+ if (!newErrs[key]) {
+ delete updatedErrors[key];
+ }
+ }
+ );
+ return updatedErrors;
+ });
};
- const computeFormErrors = (): IOrgInfoFormErrors => {
+ const computeFormErrorsFor = (
+ data: IOrgInfoFormData
+ ): IOrgInfoFormErrors => {
const errors: IOrgInfoFormErrors = {};
- if (!orgName) {
+ if (!data.orgName) {
errors.org_name = "Organization name must be present";
}
- if (!orgSupportURL) {
+ if (!data.orgSupportURL) {
errors.org_support_url = `Organization support URL must be present`;
} else if (
- !validUrl({ url: orgSupportURL, protocols: ["http", "https", "file"] })
+ !validUrl({
+ url: data.orgSupportURL,
+ protocols: ["http", "https", "file"],
+ })
) {
errors.org_support_url = "Organization support URL is not a valid URL";
}
@@ -205,6 +222,10 @@ const Info = ({
return errors;
};
+ const computeFormErrors = (): IOrgInfoFormErrors => {
+ return computeFormErrorsFor(formData);
+ };
+
const validateForm = () => {
setFormErrors(computeFormErrors());
};
@@ -323,6 +344,8 @@ const Info = ({
await op();
succeededModes.push(mode);
} catch (e) {
+ // eslint-disable-next-line no-console
+ console.error(`Failed to update ${mode} mode logo:`, e);
failedModes.push(mode);
}
}
From c5b1fedd57b5c554d4d41fea696d51f073194ae7 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:39 +0000
Subject: [PATCH 23/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/goose/migrate.go | 76 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 67 insertions(+), 9 deletions(-)
diff --git a/server/goose/migrate.go b/server/goose/migrate.go
index 11329a05cdb..f97623888c2 100644
--- a/server/goose/migrate.go
+++ b/server/goose/migrate.go
@@ -26,12 +26,22 @@ type Migrations []*Migration
func (ms Migrations) Len() int { return len(ms) }
func (ms Migrations) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
func (ms Migrations) Less(i, j int) bool {
- if ms[i].Version == ms[j].Version {
- log.Fatalf("goose: duplicate version %v detected:\n%v\n%v", ms[i].Version, ms[i].Source, ms[j].Source)
- }
return ms[i].Version < ms[j].Version
}
+// duplicateVersion returns an error describing the first duplicate migration
+// version found in ms, or nil if there are none. Callers must invoke this
+// after sorting, since sort.Interface implementations must not return errors
+// or abort the process from within a comparator.
+func (ms Migrations) duplicateVersion() error {
+ for i := 1; i < len(ms); i++ {
+ if ms[i].Version == ms[i-1].Version {
+ return fmt.Errorf("goose: duplicate version %v detected:\n%v\n%v", ms[i].Version, ms[i-1].Source, ms[i].Source)
+ }
+ }
+ return nil
+}
+
func (ms Migrations) Current(current int64) (*Migration, error) {
for i, migration := range ms {
if migration.Version == current {
@@ -126,14 +136,16 @@ func (c *Client) collectMigrations(dirpath string, current, target int64) (Migra
}
}
- migrations = sortAndConnectMigrations(migrations)
-
- return migrations, nil
+ return sortAndConnectMigrations(migrations)
}
-func sortAndConnectMigrations(migrations Migrations) Migrations {
+func sortAndConnectMigrations(migrations Migrations) (Migrations, error) {
sort.Sort(migrations)
+ if err := migrations.duplicateVersion(); err != nil {
+ return nil, err
+ }
+
// now that we're sorted in the appropriate direction,
// populate next and previous for each migration
for i, m := range migrations {
@@ -145,7 +157,7 @@ func sortAndConnectMigrations(migrations Migrations) Migrations {
migrations[i].Previous = prev
}
- return migrations
+ return migrations, nil
}
func versionFilter(v, current, target int64) bool {
@@ -165,7 +177,10 @@ func versionFilter(v, current, target int64) bool {
func (c *Client) GetDBVersion(db *sql.DB) (int64, error) {
rows, err := c.Dialect.dbVersionQuery(db, c.TableName)
if err != nil {
- return 0, c.createVersionTable(db)
+ if isTableDoesNotExistErr(err) {
+ return 0, c.createVersionTable(db)
+ }
+ return 0, err
}
defer rows.Close()
@@ -218,6 +233,49 @@ func (c *Client) GetDBVersion(db *sql.DB) (int64, error) {
// <<< OPENFRAME(migration-race)
}
+// isTableDoesNotExistErr reports whether err looks like it was caused by the
+// goose version table not existing yet, as opposed to some other query
+// failure (connection drop, permission error, deadlock, etc.) that should be
+// surfaced to the caller rather than papered over with a CREATE TABLE.
+func isTableDoesNotExistErr(err error) bool {
+ if err == nil {
+ return false
+ }
+ msg := err.Error()
+ return containsAny(msg, []string{
+ "does not exist", // postgres
+ "doesn't exist", // mysql
+ "no such table", // sqlite
+ "relation", // postgres: relation "..." does not exist
+ })
+}
+
+func containsAny(s string, substrs []string) bool {
+ for _, sub := range substrs {
+ if len(sub) > 0 && stringContains(s, sub) {
+ return true
+ }
+ }
+ return false
+}
+
+func stringContains(s, sub string) bool {
+ return len(s) >= len(sub) && indexOf(s, sub) >= 0
+}
+
+func indexOf(s, sub string) int {
+ n := len(sub)
+ if n == 0 {
+ return 0
+ }
+ for i := 0; i+n <= len(s); i++ {
+ if s[i:i+n] == sub {
+ return i
+ }
+ }
+ return -1
+}
+
// Create the goose_db_version table
// and insert the initial 0 value into it
func (c *Client) createVersionTable(db *sql.DB) error {
From ef2de1c903b56a91edc2ec197a51fffbd85f94e1 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:40 +0000
Subject: [PATCH 24/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
website/api/controllers/articles/view-basic-webinar.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/website/api/controllers/articles/view-basic-webinar.js b/website/api/controllers/articles/view-basic-webinar.js
index fa3cfc2288e..43aaefd897b 100644
--- a/website/api/controllers/articles/view-basic-webinar.js
+++ b/website/api/controllers/articles/view-basic-webinar.js
@@ -44,11 +44,11 @@ module.exports = {
let pageTitleForMeta;
let pageDescriptionForMeta;
- if(thisPage.meta.articleTitle) {
+ if(thisPage.meta && thisPage.meta.articleTitle) {
pageTitleForMeta = thisPage.meta.articleTitle;
}
- if(thisPage.meta.description) {
+ if(thisPage.meta && thisPage.meta.description) {
pageDescriptionForMeta = thisPage.meta.description;
}
From c640834e937d2b4f029c46c4f915f60be609ad0c Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:41 +0000
Subject: [PATCH 25/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
website/assets/resources/install-fleetctl.sh | 40 ++++++++++++++++++--
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/website/assets/resources/install-fleetctl.sh b/website/assets/resources/install-fleetctl.sh
index 9d0aad5fa15..01f118b30fe 100644
--- a/website/assets/resources/install-fleetctl.sh
+++ b/website/assets/resources/install-fleetctl.sh
@@ -6,7 +6,7 @@ FLEETCTL_INSTALL_DIR="${HOME}/.fleetctl/"
# Check for necessary commands
-for cmd in curl tar grep sed; do
+for cmd in curl tar grep sed shasum; do
if ! command -v $cmd &> /dev/null; then
echo "Error: $cmd is not installed." >&2
exit 1
@@ -20,6 +20,13 @@ echo "Fetching the latest version of fleetctl..."
latest_strippedVersion=$(curl -s "https://registry.npmjs.org/fleetctl/latest" | grep -o '"version": *"[^"]*"' | cut -d'"' -f4)
echo "Latest version available on NPM: $latest_strippedVersion"
+# Validate that the version string looks like a semver value before using it
+# in a URL or filesystem path.
+if ! [[ "$latest_strippedVersion" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
+ echo "Error: Unexpected version string received from NPM: '${latest_strippedVersion}'" >&2
+ exit 1
+fi
+
version_gt() {
test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1";
}
@@ -48,10 +55,36 @@ mkdir -p "${FLEETCTL_INSTALL_DIR}"
# Construct download URL
# ex: https://github.com/fleetdm/fleet/releases/download/fleet-v4.43.3/fleetctl_v4.43.3_macos.zip
DOWNLOAD_URL="https://github.com/fleetdm/fleet/releases/download/fleet-v${latest_strippedVersion}/fleetctl_v${latest_strippedVersion}_${OS}.tar.gz"
+CHECKSUMS_URL="https://github.com/fleetdm/fleet/releases/download/fleet-v${latest_strippedVersion}/fleetctl_v${latest_strippedVersion}.checksums.txt"
-# Download the latest version of fleetctl and extract it.
+# Download the latest version of fleetctl, verify its checksum, then extract it.
echo "Downloading fleetctl ${latest_strippedVersion} for ${OS_DISPLAY_NAME}..."
-curl -sSL "$DOWNLOAD_URL" | tar -xz -C "$FLEETCTL_INSTALL_DIR" --strip-components=1 fleetctl_v"${latest_strippedVersion}"_${OS}/
+
+TMP_DIR=$(mktemp -d)
+trap 'rm -rf "${TMP_DIR}"' EXIT
+
+ARCHIVE_NAME="fleetctl_v${latest_strippedVersion}_${OS}.tar.gz"
+ARCHIVE_PATH="${TMP_DIR}/${ARCHIVE_NAME}"
+CHECKSUMS_PATH="${TMP_DIR}/fleetctl_v${latest_strippedVersion}.checksums.txt"
+
+curl -sSL -o "${ARCHIVE_PATH}" "$DOWNLOAD_URL"
+curl -sSL -o "${CHECKSUMS_PATH}" "$CHECKSUMS_URL"
+
+EXPECTED_SHA=$(grep " ${ARCHIVE_NAME}\$" "${CHECKSUMS_PATH}" | awk '{print $1}')
+if [[ -z "$EXPECTED_SHA" ]]; then
+ echo "Error: Could not find checksum for ${ARCHIVE_NAME} in checksums file." >&2
+ exit 1
+fi
+
+ACTUAL_SHA=$(shasum -a 256 "${ARCHIVE_PATH}" | awk '{print $1}')
+if [[ "$EXPECTED_SHA" != "$ACTUAL_SHA" ]]; then
+ echo "Error: Checksum verification failed for ${ARCHIVE_NAME}." >&2
+ echo "Expected: ${EXPECTED_SHA}" >&2
+ echo "Actual: ${ACTUAL_SHA}" >&2
+ exit 1
+fi
+
+tar -xz -f "${ARCHIVE_PATH}" -C "$FLEETCTL_INSTALL_DIR" --strip-components=1 fleetctl_v"${latest_strippedVersion}"_${OS}/
echo "fleetctl installed successfully in ${FLEETCTL_INSTALL_DIR}"
# Verify if the binary is executable
@@ -59,3 +92,4 @@ if [[ ! -x "${FLEETCTL_INSTALL_DIR}/fleetctl" ]]; then
echo "Failed to install or upgrade fleetctl. Please check your permissions and try running this script again."
exit 1
fi
+
From e48a2b68f5a44d270a728fbedb924efae51d3122 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:42 +0000
Subject: [PATCH 26/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
cmd/maintained-apps/validate/windows.go | 29 ++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/cmd/maintained-apps/validate/windows.go b/cmd/maintained-apps/validate/windows.go
index 0bc45cde68f..053e45131e9 100644
--- a/cmd/maintained-apps/validate/windows.go
+++ b/cmd/maintained-apps/validate/windows.go
@@ -5,11 +5,13 @@ package main
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"log/slog"
"os"
"os/exec"
"path/filepath"
+ "regexp"
"strings"
"time"
@@ -20,6 +22,18 @@ import (
var preInstalled = []string{}
+// sqlIdentifierAllowlist restricts identifiers interpolated into SQL LIKE
+// queries to a safe, narrow character set as defense-in-depth on top of
+// validateSqlInput's blocklist-style checks.
+var sqlIdentifierAllowlist = regexp.MustCompile(`^[a-zA-Z0-9 ._:()/\\+-]*$`)
+
+func validateSqlIdentifierStrict(input string) error {
+ if !sqlIdentifierAllowlist.MatchString(input) {
+ return fmt.Errorf("contains disallowed characters")
+ }
+ return nil
+}
+
func postApplicationInstall(_ context.Context, _ *slog.Logger, _ string) error {
return nil
}
@@ -46,9 +60,15 @@ func appExists(ctx context.Context, logger *slog.Logger, appName, uniqueIdentifi
if err := validateSqlInput(appName); err != nil {
return false, fmt.Errorf("Invalid character found in appName: '%w'. Not executing query...", err)
}
+ if err := validateSqlIdentifierStrict(appName); err != nil {
+ return false, fmt.Errorf("Invalid character found in appName: '%w'. Not executing query...", err)
+ }
if err := validateSqlInput(appPath); err != nil {
return false, fmt.Errorf("Invalid character found in appPath: '%w'. Not executing query...", err)
}
+ if err := validateSqlIdentifierStrict(appPath); err != nil {
+ return false, fmt.Errorf("Invalid character found in appPath: '%w'. Not executing query...", err)
+ }
logger.InfoContext(ctx, fmt.Sprintf("Looking for app: %s, version: %s", appName, appVersion))
query := `
@@ -65,6 +85,9 @@ func appExists(ctx context.Context, logger *slog.Logger, appName, uniqueIdentifi
if err := validateSqlInput(uniqueIdentifier); err != nil {
return false, fmt.Errorf("Invalid character found in uniqueIdentifier: '%w'. Not executing query...", err)
}
+ if err := validateSqlIdentifierStrict(uniqueIdentifier); err != nil {
+ return false, fmt.Errorf("Invalid character found in uniqueIdentifier: '%w'. Not executing query...", err)
+ }
query += ` OR LOWER(name) LIKE LOWER('%` + uniqueIdentifier + `%')`
}
if appPath != "" {
@@ -294,7 +317,8 @@ func executeScript(cfg *Config, scriptContents string) (string, error) {
// (pkgscripts.MaxHostSoftwareInstallExecutionTime); 10 minutes is a
// reasonable validator cap that covers large-payload installers without
// letting a hung script run indefinitely.
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
+ const scriptTimeout = 10 * time.Minute
+ ctx, cancel := context.WithTimeout(context.Background(), scriptTimeout)
defer cancel()
// Use custom execution with non-interactive flags for Windows
@@ -320,6 +344,9 @@ func executeScript(cfg *Config, scriptContents string) (string, error) {
--------------------`, string(output))
if err != nil {
+ if errors.Is(ctx.Err(), context.DeadlineExceeded) {
+ return result, fmt.Errorf("script execution exceeded the %s validator timeout (this is the validator's own cap, not the script's logic): %w", scriptTimeout, err)
+ }
return result, err
}
if exitCode != 0 {
From 15c3d2c9d99505f371f15ebea1158e77dd9957a2 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:44 +0000
Subject: [PATCH 27/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
frontend/hooks/useTeamIdParam.ts | 64 ++++++++++++++++++++++++--------
1 file changed, 48 insertions(+), 16 deletions(-)
diff --git a/frontend/hooks/useTeamIdParam.ts b/frontend/hooks/useTeamIdParam.ts
index c24bb7ce9c8..b2b2e57fe1c 100644
--- a/frontend/hooks/useTeamIdParam.ts
+++ b/frontend/hooks/useTeamIdParam.ts
@@ -76,14 +76,28 @@ const rebuildQueryStringWithTeamId = (
parts.splice(pageIndex, 1, "page=0");
}
- // Backward compat: rewrite legacy team_id= to fleet_id=
- const legacyIndex = parts.findIndex((p) => p.startsWith("team_id="));
- if (legacyIndex !== -1) {
- parts.splice(
- legacyIndex,
- 1,
- parts[legacyIndex].replace("team_id=", "fleet_id=")
- );
+ // Backward compat: rewrite legacy team_id= to fleet_id=, but only if there
+ // isn't already a fleet_id= param present. If both are present, the
+ // fleet_id= param takes precedence and the stale legacy param is simply
+ // dropped below in the main fleet_id handling, avoiding a second splice
+ // against stale indices.
+ const hasFleetIdParam = parts.some((p) => p.startsWith("fleet_id="));
+ if (!hasFleetIdParam) {
+ const legacyIndex = parts.findIndex((p) => p.startsWith("team_id="));
+ if (legacyIndex !== -1) {
+ parts.splice(
+ legacyIndex,
+ 1,
+ parts[legacyIndex].replace("team_id=", "fleet_id=")
+ );
+ }
+ } else {
+ // Drop any stray legacy team_id= params since fleet_id= is authoritative
+ for (let i = parts.length - 1; i >= 0; i -= 1) {
+ if (parts[i].startsWith("team_id=")) {
+ parts.splice(i, 1);
+ }
+ }
}
const teamIndex = parts.findIndex((p) => p.startsWith("fleet_id="));
@@ -186,13 +200,25 @@ const getUserTeams = ({
: filterUserTeamsByRole(currentUser.teams, permittedAccessByTeamRole);
};
+// Name of the built-in "Workstations" fleet, as seeded/created elsewhere in
+// the app (e.g. wherever the default "Workstations" team is provisioned).
+// Kept as a single documented constant here since this hook is the only
+// consumer of the match today; if a shared location for team-name constants
+// is introduced, this should be moved there to avoid drift.
+const WORKSTATIONS_TEAM_NAME = "workstations";
+// U+1F4BB PERSONAL COMPUTER emoji, optionally followed by a variation
+// selector (U+FE0F), as may be produced by different emoji input methods.
+const WORKSTATIONS_EMOJI_PREFIX_PATTERN = /^\u{1F4BB}\uFE0F?\s*/u;
+
// Prefer a fleet named "Workstations" (with or without emoji prefix),
// otherwise fall back to the fleet with the lowest ID.
export const preferredOrLowestIdFleet = (fleets: ITeamSummary[]) => {
- const name = "workstations";
const workstations = fleets.find((t) => {
- const lower = t.name.toLowerCase();
- return lower === name || lower === `\u{1F4BB} ${name}`;
+ const lower = t.name
+ .toLowerCase()
+ .replace(WORKSTATIONS_EMOJI_PREFIX_PATTERN, "")
+ .trim();
+ return lower === WORKSTATIONS_TEAM_NAME;
});
return workstations ?? sortBy(fleets, (t) => t.id)[0];
};
@@ -462,11 +488,17 @@ export const useTeamIdParam = ({
if (hasLegacyTeamIdParam) {
// Backward compat: redirect legacy ?team_id= URLs to ?fleet_id=
// Skip other reconciliation to avoid a second redirect overwriting this one.
- router.replace(
- pathname
- .concat(search.replace(/\bteam_id=/g, "fleet_id="))
- .concat(hash || "")
- );
+ // If a fleet_id= param is also already present in the URL, treat it as
+ // authoritative and simply drop the stale legacy team_id= param instead
+ // of overwriting fleet_id=, so this path can never disagree with
+ // rebuildQueryStringWithTeamId's own legacy-param handling.
+ const hasFleetIdParam = /(?:^|[?&])fleet_id=/.test(search);
+ const newSearch = hasFleetIdParam
+ ? search.replace(/([?&])team_id=[^&]*(&)?/g, (_match, lead, trail) =>
+ trail ? lead : lead === "?" ? "?" : ""
+ )
+ : search.replace(/\bteam_id=/g, "fleet_id=");
+ router.replace(pathname.concat(newSearch).concat(hash || ""));
} else if (isFreeTier) {
// free tier should never have fleet_id param, so change to "All teams"
if (query.fleet_id) {
From 213488c040ad3c59aa239ca2adb94cb8cc120088 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:45 +0000
Subject: [PATCH 28/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../InstallSoftwareForm.tsx | 21 +++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/InstallSoftwareForm/InstallSoftwareForm.tsx b/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/InstallSoftwareForm/InstallSoftwareForm.tsx
index 474fe6a3066..3fdc566e6cf 100644
--- a/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/InstallSoftwareForm/InstallSoftwareForm.tsx
+++ b/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/InstallSoftwareForm/InstallSoftwareForm.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useContext, useState, useMemo } from "react";
+import React, { useCallback, useContext, useState, useMemo, useEffect } from "react";
import { isEqual } from "lodash";
import { InjectedRouter } from "react-router";
@@ -124,6 +124,14 @@ const InstallSoftwareForm = ({
initialSelectedSoftware
);
+ // Keep local selection in sync with the latest server-side data whenever
+ // softwareTitles changes (e.g. after a refetch following a save), so that
+ // stale local selections don't diverge from the freshly fetched truth.
+ useEffect(() => {
+ setSelectedSoftwareIds(initialSelectedSoftware);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [softwareTitles]);
+
const installSoftwareDuringSetupCount = selectedSoftwareIds.length;
const onChangeSoftwareSelect = useCallback((select: boolean, id: number) => {
@@ -158,6 +166,7 @@ const InstallSoftwareForm = ({
const errorNotifications: INotification[] = [];
let hadSuccess = false;
+ let softwareUpdateFailed = false;
// 1. Software selection update
if (shouldUpdateSoftware) {
@@ -170,6 +179,7 @@ const InstallSoftwareForm = ({
hadSuccess = true;
// Still let parent refetch even if the macOS call later fails
} catch (e) {
+ softwareUpdateFailed = true;
errorNotifications.push({
id: "update-software",
alertType: "error",
@@ -216,7 +226,14 @@ const InstallSoftwareForm = ({
renderFlash("success", "Successfully updated.");
}
- refetchSoftwareTitles();
+ // Only refetch (which resyncs local selection state from server data via
+ // the effect above) if the software-selection save didn't fail. If it
+ // failed, refetching would discard the user's unsaved local selection
+ // and replace it with stale server data without any indication that the
+ // save didn't happen.
+ if (!softwareUpdateFailed) {
+ refetchSoftwareTitles();
+ }
setIsSaving(false);
};
From f5b80df09c105537b08f71958c8cea6f9bee60eb Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:46 +0000
Subject: [PATCH 29/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
tools/mdm/migration/simplemdm/main.go | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/tools/mdm/migration/simplemdm/main.go b/tools/mdm/migration/simplemdm/main.go
index 1c4231101a3..f73f808c1cd 100644
--- a/tools/mdm/migration/simplemdm/main.go
+++ b/tools/mdm/migration/simplemdm/main.go
@@ -18,7 +18,6 @@ import (
const DELAY = 10 * time.Second // adjust this to simulate slow webhook response
var (
- apiTokenFlag = flag.String("api-token", "", "API token")
deviceIDFlag = flag.String("device-id", "", "Device ID to unenroll")
)
@@ -48,7 +47,7 @@ func newSimpleClient(apiToken string) *simpleClient {
// if err != nil {
// return 0, err
// }
-// req.SetBasicAuth(*apiTokenFlag, "")
+// req.SetBasicAuth(c.apiToken, "")
// req.Header.Set("Content-Type", "application/json")
// resp, err := client.Do(req)
// if err != nil {
@@ -75,7 +74,7 @@ func (c *simpleClient) unenroll(deviceID uint) error {
if err != nil {
return err
}
- req.SetBasicAuth(*apiTokenFlag, "")
+ req.SetBasicAuth(c.apiToken, "")
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
@@ -98,8 +97,9 @@ func (c *simpleClient) unenroll(deviceID uint) error {
func main() {
flag.Parse()
- if *apiTokenFlag == "" {
- log.Fatal("--api-token must be provided")
+ apiToken := os.Getenv("SIMPLEMDM_API_TOKEN")
+ if apiToken == "" {
+ log.Fatal("SIMPLEMDM_API_TOKEN environment variable must be set")
}
if *deviceIDFlag == "" {
@@ -110,6 +110,8 @@ func main() {
log.Fatalf("invalid device ID %s: %v", *deviceIDFlag, err)
}
+ client := newSimpleClient(apiToken)
+
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
var detail string
body, err := io.ReadAll(request.Body)
@@ -132,11 +134,15 @@ func main() {
// }
// TODO: Use getDeviceIDBySerial to find the device ID by serial number
- // For now, we just use the device ID provided via command line flag.
+ // from the parsed request body above, instead of relying on the
+ // device ID provided via command line flag. Until that is
+ // implemented, this handler will always unenroll the device
+ // identified by --device-id, regardless of which host triggered
+ // the webhook.
time.Sleep(DELAY)
- if err := newSimpleClient(*apiTokenFlag).unenroll(uint(deviceID)); err != nil {
+ if err := client.unenroll(uint(deviceID)); err != nil {
log.Printf("error unenrolling device %d: %s", deviceID, err.Error())
writer.WriteHeader(http.StatusBadGateway)
if _, err := writer.Write([]byte("Error unenrolling device")); err != nil {
From 3a3e67831ad315dcab18d5fb493198139c13e00f Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:48 +0000
Subject: [PATCH 30/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../BootstrapPackage/BootstrapPackage.tsx | 25 +++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/frontend/pages/ManageControlsPage/SetupExperience/cards/BootstrapPackage/BootstrapPackage.tsx b/frontend/pages/ManageControlsPage/SetupExperience/cards/BootstrapPackage/BootstrapPackage.tsx
index e28108d1185..501a00a793a 100644
--- a/frontend/pages/ManageControlsPage/SetupExperience/cards/BootstrapPackage/BootstrapPackage.tsx
+++ b/frontend/pages/ManageControlsPage/SetupExperience/cards/BootstrapPackage/BootstrapPackage.tsx
@@ -141,13 +141,34 @@ const BootstrapPackage = ({
const onDelete = async () => {
try {
await mdmAPI.deleteBootstrapPackage(currentTeamId);
+ } catch (error) {
+ console.error("Failed to delete bootstrap package:", error);
+ renderFlash("error", "Couldn't delete. Please try again.");
+ setShowDeleteBootstrapPackageModal(false);
+ refretchBootstrapMetadata();
+ if (currentTeamId !== API_NO_TEAM_ID) {
+ refetchTeamConfig();
+ } else {
+ refetchGlobalConfig();
+ }
+ return;
+ }
+
+ try {
await mdmAPI.updateSetupExperienceSettings({
fleet_id: currentTeamId,
macos_manual_agent_install: false,
});
renderFlash("success", "Successfully deleted.");
- } catch {
- renderFlash("error", "Couldn't delete. Please try again.");
+ } catch (error) {
+ console.error(
+ "Bootstrap package deleted, but failed to update setup experience settings:",
+ error
+ );
+ renderFlash(
+ "error",
+ "Bootstrap package deleted, but couldn't update settings. Please try again."
+ );
} finally {
setShowDeleteBootstrapPackageModal(false);
refretchBootstrapMetadata();
From 7d65a4957012ef8f70d2e0958e195236dc61e22d Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:49 +0000
Subject: [PATCH 31/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/service/software_installers.go | 29 +++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/server/service/software_installers.go b/server/service/software_installers.go
index f909631fc65..15002636a4a 100644
--- a/server/service/software_installers.go
+++ b/server/service/software_installers.go
@@ -55,6 +55,7 @@ type updateSoftwareInstallerRequest struct {
LabelsIncludeAll []string
Categories []string
DisplayName *string
+ AutomaticInstall *bool
// Configuration is the in-house app's managed app configuration as raw XML bytes (iOS / iPadOS only). nil means leave unchanged.
Configuration []byte
}
@@ -64,8 +65,13 @@ type uploadSoftwareInstallerResponse struct {
Err error `json:"error,omitempty"`
}
-// TODO: We parse the whole body before running svc.authz.Authorize.
-// An authenticated but unauthorized user could abuse this.
+// NOTE: This handler parses the whole multipart body (including a potentially
+// large file upload) before svc.authz.Authorize runs. An authenticated but
+// unauthorized user could abuse this to force the server to buffer/parse
+// arbitrary large uploads before being rejected. This is a known
+// resource-exhaustion risk that should be addressed by moving authorization
+// earlier in the request pipeline (e.g. checking authz before or during body
+// parsing) rather than after DecodeRequest completes.
func (updateSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http.Request) (interface{}, error) {
decoded := updateSoftwareInstallerRequest{}
@@ -153,6 +159,15 @@ func (updateSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http
decoded.SelfService = &parsed
}
+ val, ok = r.MultipartForm.Value["automatic_install"]
+ if ok && len(val) > 0 && val[0] != "" {
+ parsed, err := strconv.ParseBool(val[0])
+ if err != nil {
+ return nil, &fleet.BadRequestError{Message: fmt.Sprintf("failed to decode automatic_install bool in multipart form: %s", err.Error())}
+ }
+ decoded.AutomaticInstall = &parsed
+ }
+
// decode labels and categories
var inclAny, exclAny, inclAll, categories []string
var existsInclAny, existsExclAny, existsInclAll, existsCategories bool
@@ -293,8 +308,13 @@ func (svc *Service) UpdateSoftwareInstaller(ctx context.Context, payload *fleet.
return nil, fleet.ErrMissingLicense
}
-// TODO: We parse the whole body before running svc.authz.Authorize.
-// An authenticated but unauthorized user could abuse this.
+// NOTE: This handler parses the whole multipart body (including a potentially
+// large file upload) before svc.authz.Authorize runs. An authenticated but
+// unauthorized user could abuse this to force the server to buffer/parse
+// arbitrary large uploads before being rejected. This is a known
+// resource-exhaustion risk that should be addressed by moving authorization
+// earlier in the request pipeline (e.g. checking authz before or during body
+// parsing) rather than after DecodeRequest completes.
func (uploadSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http.Request) (interface{}, error) {
decoded := uploadSoftwareInstallerRequest{}
@@ -1153,3 +1173,4 @@ func (svc *Service) GetInHouseAppPackage(ctx context.Context, titleID uint, toke
return nil, fleet.ErrMissingLicense
}
+
From 2452832cb13d51a202bf186553cfd229fc495faf Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:50 +0000
Subject: [PATCH 32/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../migrations/tables/20220831100151_AddWindowsUpdatesTable.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go b/server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go
index 7887c8ad037..f5cd16e470f 100644
--- a/server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go
+++ b/server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go
@@ -22,7 +22,7 @@ CREATE TABLE IF NOT EXISTS windows_updates (
KEY idx_update_date (host_id, date_epoch)
)`)
if err != nil {
- return errors.Wrapf(err, "create operating_systems table")
+ return errors.Wrapf(err, "create windows_updates table")
}
return nil
}
@@ -30,3 +30,4 @@ CREATE TABLE IF NOT EXISTS windows_updates (
func Down_20220831100151(tx *sql.Tx) error {
return nil
}
+
From a72f0e659228ec3fbf8177e41d178f3b88005f46 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:52 +0000
Subject: [PATCH 33/40] fix(adhoc-sweep-fixes): 74 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 4b720027b86aac898d6ebcdc0f33bb3d0d67813b Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:53 +0000
Subject: [PATCH 34/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../helpers/microsoft-proxy/get-access-token-and-api-urls.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/website/api/helpers/microsoft-proxy/get-access-token-and-api-urls.js b/website/api/helpers/microsoft-proxy/get-access-token-and-api-urls.js
index 17e3018a2f6..c6b189ca6e4 100644
--- a/website/api/helpers/microsoft-proxy/get-access-token-and-api-urls.js
+++ b/website/api/helpers/microsoft-proxy/get-access-token-and-api-urls.js
@@ -28,7 +28,7 @@ module.exports = {
let informationAboutThisTenant = await MicrosoftComplianceTenant.findOne({id: complianceTenantRecordId});
if(!informationAboutThisTenant) {
- return new Error(`No matching tenant record could be found with the specified ID. (${complianceTenantRecordId}`);
+ throw new Error(`No matching tenant record could be found with the specified ID. (${complianceTenantRecordId})`);
}
// Get a graph access token for this tenant
@@ -109,3 +109,4 @@ module.exports = {
};
+
From 49ca57a6ac929bf59e8d0f17c573960edfcf648e Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:54 +0000
Subject: [PATCH 35/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
server/service/jitter_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/service/jitter_test.go b/server/service/jitter_test.go
index 768ac58a5cc..d18d09362f6 100644
--- a/server/service/jitter_test.go
+++ b/server/service/jitter_test.go
@@ -35,7 +35,7 @@ func TestJitterForHost(t *testing.T) {
t.Logf("min=%d \t max=%d \t variation=%d\n", minVal, maxVal, variation)
// check that variation is below 1% of the total amount of hosts
- require.Less(t, variation, int(float32(hostCount)/0.01))
+ require.Less(t, variation, int(float32(hostCount)*0.01))
}
func TestNoJitter(t *testing.T) {
From edd6e85accaeecdf14db5dc4292156911fc33fe5 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:55 +0000
Subject: [PATCH 36/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
tools/team-builder/build_teams.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/team-builder/build_teams.sh b/tools/team-builder/build_teams.sh
index 68766a0264b..6c4c5aefd54 100755
--- a/tools/team-builder/build_teams.sh
+++ b/tools/team-builder/build_teams.sh
@@ -12,7 +12,7 @@ run(){
while getopts s:p:u:f:d:o:x flag
do
case "${flag}" in
- f) #path to file containing team names. Must end with newline char.
+ s) #path to file containing team names. Must end with newline char.
source=($OPTARG);;
p) #types of installers to create. Pass an individual flag for each type
types+=($OPTARG);;
From 97078f06912b6046a4b582d119155df0b296ac6e Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:56 +0000
Subject: [PATCH 37/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx
index a4048c0f181..2ada48c88bc 100644
--- a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx
+++ b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx
@@ -365,7 +365,7 @@ export const SoftwareInstallDetailsModal = ({
const overrideFailedMessageWithInstalledMessage =
canOverrideFailureWithInstalled &&
["failed_install", "failed_uninstall"].includes(
- swInstallResult?.status || "" || ""
+ swInstallResult?.status || ""
);
// Hide version section from pending installs or failures that aren't overridden to installed (4.82 #31663)
From a9527f1c24cd3f49b768eada23e1bdbb7c423fd2 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:57 +0000
Subject: [PATCH 38/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
.../pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx b/frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx
index cb4ac6c630e..44e5624d250 100644
--- a/frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx
+++ b/frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx
@@ -91,7 +91,7 @@ export const getUninstallErrorMessage = (e: unknown) => {
"Couldn't uninstall."
);
} else if (reason.startsWith("No uninstall script exists")) {
- return `${UNINSTALL_SOFTWARE_ERROR_PREFIX}. An uninstall script does not exist for this package.`;
+ return `${UNINSTALL_SOFTWARE_ERROR_PREFIX} An uninstall script does not exist for this package.`;
}
return DEFAULT_UNINSTALL_ERROR_MESSAGE;
From 09b1ccc0ef1e18a95396795228ae17f09a38be75 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:58 +0000
Subject: [PATCH 39/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
tools/mdm/migration/mdmproxy/entrypoint.sh | 24 +++++++++-------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/tools/mdm/migration/mdmproxy/entrypoint.sh b/tools/mdm/migration/mdmproxy/entrypoint.sh
index 8177f1c912d..347f53eb7f9 100644
--- a/tools/mdm/migration/mdmproxy/entrypoint.sh
+++ b/tools/mdm/migration/mdmproxy/entrypoint.sh
@@ -1,31 +1,27 @@
#!/bin/sh
set -e
-AUTH_TOKEN_ARG=""
-MIGRATE_PERCENTAGE_ARG=""
-MIGRATE_UDIDS_ARG=""
if [ -z "${MDMPROXY_SERVER_ADDRESS}" ]; then
MDMPROXY_SERVER_ADDRESS=":8080"
fi
+set -- \
+ -existing-hostname "${MDMPROXY_EXISTING_HOSTNAME:?}" \
+ -existing-url "${MDMPROXY_EXISTING_URL:?}" \
+ -fleet-url "${MDMPROXY_FLEET_URL:?}" \
+ -server-address "${MDMPROXY_SERVER_ADDRESS:?}"
+
if [ -n "${MDMPROXY_AUTH_TOKEN}" ]; then
- AUTH_TOKEN_ARG="-auth-token \"${MDMPROXY_AUTH_TOKEN:?}\""
+ set -- "$@" -auth-token "${MDMPROXY_AUTH_TOKEN:?}"
fi
if [ -n "${MDMPROXY_MIGRATE_PERCENTAGE}" ]; then
- MIGRATE_PERCENTAGE_ARG="-migrate-percentage \"${MDMPROXY_MIGRATE_PERCENTAGE:?}\""
+ set -- "$@" -migrate-percentage "${MDMPROXY_MIGRATE_PERCENTAGE:?}"
fi
if [ -n "${MDMPROXY_MIGRATE_UDIDS}" ]; then
- MIGRATE_UDIDS_ARG="-migrate-udids \"${MDMPROXY_MIGRATE_UDIDS:?}\""
+ set -- "$@" -migrate-udids "${MDMPROXY_MIGRATE_UDIDS:?}"
fi
-eval exec /usr/bin/mdmproxy \
- ${AUTH_TOKEN_ARG} \
- -existing-hostname "${MDMPROXY_EXISTING_HOSTNAME:?}" \
- -existing-url "${MDMPROXY_EXISTING_URL:?}" \
- -fleet-url "${MDMPROXY_FLEET_URL:?}" \
- ${MIGRATE_PERCENTAGE_ARG} \
- ${MIGRATE_UDIDS_ARG} \
- -server-address "${MDMPROXY_SERVER_ADDRESS:?}"
+exec /usr/bin/mdmproxy "$@"
From d22b8d441560ea94dde9779a4b01e6f1d1d55fa3 Mon Sep 17 00:00:00 2001
From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com>
Date: Mon, 14 Sep 2026 06:47:59 +0000
Subject: [PATCH 40/40] fix(adhoc-sweep-fixes): 74 review findings across 40
files
---
ee/tools/puppet/fleetdm/lib/puppet/util/fleet_client.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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..8b0df7996da 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