Skip to content

fix(adhoc-sweep-fixes): 57 review findings across 40 files - #120

Draft
flamingo[bot] wants to merge 40 commits into
mainfrom
ai-fix/adhoc-sweep-fixes-301bbcb0-f6d23861
Draft

fix(adhoc-sweep-fixes): 57 review findings across 40 files#120
flamingo[bot] wants to merge 40 commits into
mainfrom
ai-fix/adhoc-sweep-fixes-301bbcb0-f6d23861

Conversation

@flamingo

@flamingo flamingo Bot commented Aug 24, 2026

Copy link
Copy Markdown

Closes 57 review findings across 40 files.

Draft — this is a starting point, not a finished change. The fix required judgment, so read it before trusting it.

# Fix confidence Finding Location
1 🟢 95 high Wrong table name in error message: 'operating_systems table' referenced while creating windows_updates server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go:22
2 🟢 90 high errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creation server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go:14
3 🟢 92 high Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanup server/live_query/redis_live_query.go:296
4 🔴 40 low — review closely removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrapping server/live_query/redis_live_query.go:220
5 🟢 95 high Webhook.CallWebhook does not close the HTTP response body, leaking connections server/mdm/nanodep/cmd/depsyncer/webhook.go:70
6 🟡 80 medium Bare error returns without context wrapping in webhook.go server/mdm/nanodep/cmd/depsyncer/webhook.go:60
7 🟢 90 high Windows binary name check uses wrong comparison value in fleetctl-npm run.js tools/fleetctl-npm/run.js:39
8 🟢 95 high Unreachable/incorrect error message interpolates function reference instead of platform value tools/fleetctl-npm/run.js:27
9 🟢 92 high migrate-users-with-no-trial-key.js uses Array.includes on a query result of full record objects, so the membership check never matches website/scripts/migrate-users-with-no-trial-key.js:18
10 🟡 70 medium migrate-users-with-no-trial-key.js sends a placeholder/wrong subject line 'Whoops' for the trial-license email website/scripts/migrate-users-with-no-trial-key.js:56
11 🟢 95 high signingRoundTripper.RoundTrip formats signer error with %#v instead of %w ee/orbit/pkg/httpsigproxy/httpsigproxy.go:210
12 🟡 85 medium Proxy.Serve() wraps a nil-possible error from http.Server.Serve without distinguishing ErrServerClosed ee/orbit/pkg/httpsigproxy/httpsigproxy.go:138
13 🟢 92 high Assertions placed outside it() block execute at describe-time, not as part of any test frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts:79
14 🟢 90 high Assertions placed outside it() block in newFormDataIdp describe block never run as part of a test frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts:231
15 🟢 95 high getInstallErrorMessage produces malformed double-period message for fleetd-installed error frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx:58
16 🟢 95 high getUninstallErrorMessage's 'No uninstall script exists' branch also has a doubled-period frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx:92
17 🔴 40 low — review closely DisassociateAssets missing context parameter breaks caller cancellation/timeout propagation server/mdm/apple/vpp/api.go:200
18 🔴 40 low — review closely DisassociateAssets propagates bare http.NewRequest error without context wrapping in a shared package server/mdm/apple/vpp/api.go:205
19 🟢 90 high makeAndroidAppUnavailable in software_worker.go swallows detailed context on RemoveAppsFromAndroidPolicy failure server/worker/software_worker.go:279
20 🟡 75 medium makeAndroidAppAvailablePerHost hardcodes admin GlobalRole via undefined-looking helper 'new' server/worker/software_worker.go:213
21 🟢 95 high santa_status.yml has duplicate/swapped descriptions for file_logging hash columns schema/tables/santa_status.yml:40
22 🟢 90 high santa_status.yml metrics_server column typed as integer but described as an address string schema/tables/santa_status.yml:121
23 🟢 90 high runMigration calls log.Fatal on migration transaction failure, killing the whole process instead of returning an error server/goose/migration.go:46
24 🟢 90 high log.Fatal used inside FinalizeMigration failure path after fn(tx) fails, obscuring the returned error server/goose/migration.go:58
25 🟢 90 high Duplicate GenerateSingleSSIDTestWLANXMLProfiles call in TestIsWLANXML produces two identical variables server/mdm/microsoft/wlanxml/wlanxml_test.go:82
26 🟢 90 high TestEqual compares wrong variable pairs for 'hex only' vs 'name only' single-SSID cases server/mdm/microsoft/wlanxml/wlanxml_test.go:133
27 🟢 95 high Check-in handler continues to write response body after error, causing double header write server/mdm/nanomdm/http/mdm/mdm.go:48
28 🟢 95 high CommandAndReportResultsHandler falls through to Write after http.Error on failure server/mdm/nanomdm/http/mdm/mdm.go:82
29 🔴 40 low — review closely resolveBranch has unreachable duplicate return statement after the nil-lastErr branch tools/migration-cleanup/main.go:248
30 🔴 40 low — review closely Bare error return without wrapping context in resolveBranch tools/migration-cleanup/main.go:236
31 🟢 95 high Test uses non-existent ptr.String(fleet.RoleObserver) call shape inconsistently with rest of file server/service/targets_test.go:59
32 🟢 95 high TeamID pointer constructed with new(uint(1)) is invalid Go syntax server/service/targets_test.go:68
33 🟢 95 high server.ListenAndServe error in mdmproxy main() is only printed, not treated as fatal tools/mdm/migration/mdmproxy/mdmproxy.go:366
34 🟡 85 medium Duplicated auth-token validation logic between handleUpdatePercentage and handleUpdateMigrateUDIDs tools/mdm/migration/mdmproxy/mdmproxy.go:140
35 🟢 97 high INSUFFICIENT_PERMISSIONS_ERROR constant referenced but not returned in NDESForm getErrorMessage frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/NDESForm/helpers.ts:141
36 🟢 100 high Duplicated useEffect comment header in LivePolicyPage.tsx frontend/pages/policies/live/LivePolicyPage/LivePolicyPage.tsx:78
37 🟢 95 high Invalid Go syntax new(time.Unix(1, 0)) in host_cache_writes_test.go server/datastore/mysqlredis/host_cache_writes_test.go:79
38 🟢 95 high Misspelled field-doc comment 'BlcokSize' in CarveMetadata server/fleet/carves.go:18
39 🟢 95 high RetrieveCursor stats the wrong file (profileFilename instead of cursorFilename) server/mdm/nanodep/storage/file/file.go:149
40 🟢 95 high EncodeSCEPRequest POST branch ignores error from http.NewRequest before using rr server/mdm/scep/server/transport.go:107
41 🟢 98 high SSOMFAConflict message has a duplicated 'is' typo server/service/invites.go:40
42 🟢 95 high Test bug: RemediatedBy set on wrong variable (cve3 instead of cve4) server/vulnerabilities/msrc/parsed/security_bulletin_test.go:53
43 🟢 97 high LoadHostConditionalAccessStatus ignores sql.ErrNoRows path and falls through to use zero-valued struct server/datastore/mysql/conditional_access_microsoft.go:85
44 🟢 97 high Migration comment references wrong migration timestamp (copy-paste error) server/datastore/mysql/migrations/tables/20260528211626_AddClearPasscodeRefToHostMDMActions.go:13
45 🟢 95 high isMac() compares a function reference to a boolean instead of calling isIPad() frontend/pages/hosts/details/DeviceUserPage/helpers.ts:66
46 🟢 95 high isIosLockedWithLocationAvail compares hostGeolocation to null with strict inequality, which is always true for optional undefined prop frontend/pages/hosts/details/modals/LocationModal/LocationModal.tsx:137
47 🟢 95 high AddPatchPolicyModal renders duplicate flash messages on already-has-policy error frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/AddPatchPolicyModal/AddPatchPolicyModal.tsx:39
48 🟢 97 high Typo'd map key 'mdm_command_ouput' means the no-input-command response never sets mdm_command_output orbit/pkg/table/mdm_bridge/mdm_bridge.go:178
49 🟢 97 high Non-ASCII lookalike identifier used in Go test variable name server/datastore/mysql/labels_openframe_test.go:66
50 🟢 95 high Up_20210819131107 ignores the error from creating temp_host_software and wraps an empty message server/datastore/mysql/migrations/tables/20210819131107_AddCascadeToHostSoftware.go:39
51 🔴 40 low — review closely testUsersSaveMany asserts on wrong user id (gotU2 checks u3 instead of u2) server/datastore/mysql/users_test.go:396
52 🟢 95 high CA private key SelfSign sets NotBefore using unsafe negative-second offset arithmetic instead of AddDate server/mdm/scep/depot/cacert.go:116
53 🟢 95 high migrate-old-primary-buying-situation-values.js uses !== {} which is always true and never skips the intended branch website/scripts/migrate-old-primary-buying-situation-values.js:20
54 🟢 95 high Software card 'All' tab sorts by hosts_count instead of name despite constant naming frontend/pages/DashboardPage/cards/Software/Software.tsx:96
55 🟢 95 high CiscoJabberVersionTransformer doc comment states wrong version value ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go:5
56 🟢 95 high Test suite leaves dbFile nil, TearDownSuite guard is dead code ee/server/calendar/google_calendar_integration_test.go:21
57 🔴 40 low — review closely set-compliant-versions.js divides by newCompliantInstalls.length before it is populated, causing NaN/Infinity progress ee/vulnerability-dashboard/api/controllers/set-compliant-versions.js:52

What changed — and what was deliberately left — is explained per finding as inline review comments on the lines each finding touched.


Run: https://product-hub.flamingo.so/admin/code-review
Run id: f6d23861-693f-45a1-b5b3-570aa3bc9ea7

Merging this PR is recorded as acceptance of the rule that produced it;
closing it unmerged is recorded as rejection. Both feed rule health, so
closing a wrong suggestion is useful rather than merely tidy.

flamingo Bot added 30 commits August 24, 2026 06:35

@flamingo flamingo Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 What this fix changed, finding by finding

57 finding(s) fixed in this draft — 57 explained inline on the diff; 7 low-confidence hunk(s) need close review before merging.

@@ -22,7 +21,7 @@ CREATE TABLE IF NOT EXISTS windows_updates (
KEY idx_update_date (host_id, date_epoch)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Wrong table name in error message: 'operating_systems table' referenced while creating windows_updates

In Up_20220831100151, changed the error message text from "create operating_systems table" to "create windows_updates table" to correctly reflect the table being created.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go around line 22, review and complete this code-review fix: Wrong table name in error message: 'operating_systems table' referenced while creating windows_updates.
What the draft fix changed: In Up_20220831100151, changed the error message text from "create operating_systems table" to "create windows_updates table" to correctly reflect the table being created.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 2 to 8

import (
"database/sql"

"github.com/pkg/errors"
"fmt"
)

func init() {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creation

In Up_20220831100151, replaced errors.Wrapf(err, "...") from github.com/pkg/errors with fmt.Errorf("create windows_updates table: %w", err), and updated the import block to remove github.com/pkg/errors and add fmt, matching the pattern used elsewhere in the migrations package.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go around line 14, review and complete this code-review fix: errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creation.
What the draft fix changed: In Up_20220831100151, replaced `errors.Wrapf(err, "...")` from `github.com/pkg/errors` with `fmt.Errorf("create windows_updates table: %w", err)`, and updated the import block to remove `github.com/pkg/errors` and add `fmt`, matching the pattern used elsewhere in the migrations package.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

Comment on lines 315 to 324
var args redigo.Args
args = args.Add(activeQueriesKey)
args = args.AddFlat(names)
_, err := conn.Do("SADD", args...)
return err
if _, err := conn.Do("SADD", args...); err != nil {
return fmt.Errorf("sadd query names: %w", err)
}
return nil
}

func (r *redisLiveQuery) removeQueryInfo(name string) error {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanup

In loadCache(), changed go func() { err = r.removeQueryNames(names...); ... }() to go func() { if err := r.removeQueryNames(names...); err != nil { ... } }(), using a new locally-scoped err instead of closing over the outer function-scoped err variable. This eliminates the data race on the shared err and matches the suggested fix exactly.

🤖 Prompt for AI agents
In server/live_query/redis_live_query.go around line 296, review and complete this code-review fix: Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanup.
What the draft fix changed: In `loadCache()`, changed `go func() { err = r.removeQueryNames(names...); ... }()` to `go func() { if err := r.removeQueryNames(names...); err != nil { ... } }()`, using a new locally-scoped `err` instead of closing over the outer function-scoped `err` variable. This eliminates the data race on the shared `err` and matches the suggested fix exactly.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer

Comment on lines 315 to 324
var args redigo.Args
args = args.Add(activeQueriesKey)
args = args.AddFlat(names)
_, err := conn.Do("SADD", args...)
return err
if _, err := conn.Do("SADD", args...); err != nil {
return fmt.Errorf("sadd query names: %w", err)
}
return nil
}

func (r *redisLiveQuery) removeQueryInfo(name string) error {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrapping

Wrapped the bare error returns in storeQueryNames (SADD) and removeQueryNames (SREM) with fmt.Errorf("sadd query names: %w", err) and fmt.Errorf("srem query names: %w", err) respectively, bringing them in line with the file's error-wrapping convention used elsewhere (e.g. storeQueryInfo/removeQueryInfo). Note: the finding also mentions removeInactiveQueries, but that function already wraps its error via ctxerr.Wrap(ctx, err, "remove inactive campaign IDs"), so no change was needed there; only the two functions shown in the evidence lacked wrapping and were fixed.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In server/live_query/redis_live_query.go around line 220, review and complete this code-review fix: removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrapping.
What the draft fix changed: Wrapped the bare error returns in `storeQueryNames` (SADD) and `removeQueryNames` (SREM) with `fmt.Errorf("sadd query names: %w", err)` and `fmt.Errorf("srem query names: %w", err)` respectively, bringing them in line with the file's error-wrapping convention used elsewhere (e.g. storeQueryInfo/removeQueryInfo). Note: the finding also mentions `removeInactiveQueries`, but that function already wraps its error via `ctxerr.Wrap(ctx, err, "remove inactive campaign IDs")`, so no change was needed there; only the two functions shown in the evidence lacked wrapping and were fixed.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

return fmt.Errorf("call webhook: %w", err)
}
defer httpResp.Body.Close()
if httpResp.StatusCode != http.StatusOK {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Webhook.CallWebhook does not close the HTTP response body, leaking connections

Added defer httpResp.Body.Close() immediately after the successful w.client.Do(req) call in Webhook.CallWebhook, ensuring the response body is always closed and the underlying connection can be reused/released.

🤖 Prompt for AI agents
In server/mdm/nanodep/cmd/depsyncer/webhook.go around line 70, review and complete this code-review fix: Webhook.CallWebhook does not close the HTTP response body, leaking connections.
What the draft fix changed: Added `defer httpResp.Body.Close()` immediately after the successful `w.client.Do(req)` call in `Webhook.CallWebhook`, ensuring the response body is always closed and the underlying connection can be reused/released.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

@@ -20,7 +20,7 @@ module.exports = {
// Default to 'it-major-mdm' for users with an mdm primaryBuyingSituation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 migrate-old-primary-buying-situation-values.js uses !== {} which is always true and never skips the intended branch

In the fn handler's mdm stream callback (website/scripts/migrate-old-primary-buying-situation-values.js), changed the always-true if(thisUser.getStartedQuestionnaireAnswers !== {}) reference-comparison guard to if(thisUser.getStartedQuestionnaireAnswers && Object.keys(thisUser.getStartedQuestionnaireAnswers).length > 0), matching the suggested fix. This prevents the TypeError from indexing into getStartedQuestionnaireAnswers when it is null/undefined and correctly skips users with an empty answers object.

🤖 Prompt for AI agents
In website/scripts/migrate-old-primary-buying-situation-values.js around line 20, review and complete this code-review fix: migrate-old-primary-buying-situation-values.js uses `!== {}` which is always true and never skips the intended branch.
What the draft fix changed: In the `fn` handler's `mdm` stream callback (`website/scripts/migrate-old-primary-buying-situation-values.js`), changed the always-true `if(thisUser.getStartedQuestionnaireAnswers !== {})` reference-comparison guard to `if(thisUser.getStartedQuestionnaireAnswers && Object.keys(thisUser.getStartedQuestionnaireAnswers).length > 0)`, matching the suggested fix. This prevents the TypeError from indexing into `getStartedQuestionnaireAnswers` when it is null/undefined and correctly skips users with an empty answers object.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 97 to 103
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={() => <EmptySoftwareTable />}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Software card 'All' tab sorts by hosts_count instead of name despite constant naming

In the 'All' tab's TableContainer (first TabPanel) in the Software component, changed defaultSortHeader={SOFTWARE_DEFAULT_SORT_DIRECTION} to defaultSortHeader={SOFTWARE_DEFAULT_SORT_HEADER}, matching the correct constant used for sort column and consistent with the 'Vulnerable' tab below.

🤖 Prompt for AI agents
In frontend/pages/DashboardPage/cards/Software/Software.tsx around line 96, review and complete this code-review fix: Software card 'All' tab sorts by hosts_count instead of name despite constant naming.
What the draft fix changed: In the 'All' tab's TableContainer (first TabPanel) in the Software component, changed `defaultSortHeader={SOFTWARE_DEFAULT_SORT_DIRECTION}` to `defaultSortHeader={SOFTWARE_DEFAULT_SORT_HEADER}`, matching the correct constant used for sort column and consistent with the 'Vulnerable' tab below.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

@@ -4,9 +4,10 @@ import (
maintained_apps "github.com/fleetdm/fleet/v4/ee/maintained-apps"
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 CiscoJabberVersionTransformer doc comment states wrong version value

Updated the doc comment on CiscoJabberVersionTransformer (line 5) to say "15.2.1" instead of "15.2.0", matching the actual assigned value app.Version = "15.2.1" in the function body. No behavioral code was changed.

🤖 Prompt for AI agents
In ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go around line 5, review and complete this code-review fix: CiscoJabberVersionTransformer doc comment states wrong version value.
What the draft fix changed: Updated the doc comment on CiscoJabberVersionTransformer (line 5) to say "15.2.1" instead of "15.2.0", matching the actual assigned value `app.Version = "15.2.1"` in the function body. No behavioral code was changed.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 24 to 30
func (s *googleCalendarIntegrationTestSuite) SetupSuite() {
dbFile, err := os.CreateTemp("", "calendar.db")
s.Require().NoError(err)
s.dbFile = dbFile
handler, err := calendartest.Configure(dbFile.Name())
s.Require().NoError(err)
server := httptest.NewUnstartedServer(handler)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Test suite leaves dbFile nil, TearDownSuite guard is dead code

In SetupSuite, added s.dbFile = dbFile immediately after os.CreateTemp succeeds, so the struct field is populated and TearDownSuite's if s.dbFile != nil guard now correctly closes and removes the temp file on cleanup.

🤖 Prompt for AI agents
In ee/server/calendar/google_calendar_integration_test.go around line 21, review and complete this code-review fix: Test suite leaves dbFile nil, TearDownSuite guard is dead code.
What the draft fix changed: In `SetupSuite`, added `s.dbFile = dbFile` immediately after `os.CreateTemp` succeeds, so the struct field is populated and `TearDownSuite`'s `if s.dbFile != nil` guard now correctly closes and removes the temp file on cleanup.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 76 to 82
await CriticalInstall.update({softwareType: complianceType}).set({isCompliant: false});
let numberOfTheseInstalls = await CriticalInstall.count({softwareType: complianceType});
newCompliantVersions = await CriticalInstall.update({fleetApid: {in: compliantVersions}}).set({isCompliant: true}).fetch();
newPatchProgress = Math.floor(newCompliantInstalls.length /numberOfTheseInstalls * 100);
newPatchProgress = Math.floor(newCompliantVersions.length /numberOfTheseInstalls * 100);
}


Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 set-compliant-versions.js divides by newCompliantInstalls.length before it is populated, causing NaN/Infinity progress

In the final else branch of the fn function in set-compliant-versions.js, changed newPatchProgress = Math.floor(newCompliantInstalls.length /numberOfTheseInstalls * 100); to newPatchProgress = Math.floor(newCompliantVersions.length /numberOfTheseInstalls * 100);, using the populated newCompliantVersions array (from .fetch()) instead of the always-empty module-level newCompliantInstalls array, matching the suggested fix exactly.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In ee/vulnerability-dashboard/api/controllers/set-compliant-versions.js around line 52, review and complete this code-review fix: set-compliant-versions.js divides by newCompliantInstalls.length before it is populated, causing NaN/Infinity progress.
What the draft fix changed: In the final `else` branch of the `fn` function in `set-compliant-versions.js`, changed `newPatchProgress = Math.floor(newCompliantInstalls.length /numberOfTheseInstalls * 100);` to `newPatchProgress = Math.floor(newCompliantVersions.length /numberOfTheseInstalls * 100);`, using the populated `newCompliantVersions` array (from `.fetch()`) instead of the always-empty module-level `newCompliantInstalls` array, matching the suggested fix exactly.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

@flamingo flamingo Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 What this fix changed, finding by finding

57 finding(s) fixed in this draft — 57 explained inline on the diff; 7 low-confidence hunk(s) need close review before merging.

@@ -22,7 +21,7 @@ CREATE TABLE IF NOT EXISTS windows_updates (
KEY idx_update_date (host_id, date_epoch)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Wrong table name in error message: 'operating_systems table' referenced while creating windows_updates

In Up_20220831100151, changed the error message text from "create operating_systems table" to "create windows_updates table" to correctly reflect the table being created.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go around line 22, review and complete this code-review fix: Wrong table name in error message: 'operating_systems table' referenced while creating windows_updates.
What the draft fix changed: In Up_20220831100151, changed the error message text from "create operating_systems table" to "create windows_updates table" to correctly reflect the table being created.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 2 to 8

import (
"database/sql"

"github.com/pkg/errors"
"fmt"
)

func init() {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creation

In Up_20220831100151, replaced errors.Wrapf(err, "...") from github.com/pkg/errors with fmt.Errorf("create windows_updates table: %w", err), and updated the import block to remove github.com/pkg/errors and add fmt, matching the pattern used elsewhere in the migrations package.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go around line 14, review and complete this code-review fix: errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creation.
What the draft fix changed: In Up_20220831100151, replaced `errors.Wrapf(err, "...")` from `github.com/pkg/errors` with `fmt.Errorf("create windows_updates table: %w", err)`, and updated the import block to remove `github.com/pkg/errors` and add `fmt`, matching the pattern used elsewhere in the migrations package.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

Comment on lines 315 to 324
var args redigo.Args
args = args.Add(activeQueriesKey)
args = args.AddFlat(names)
_, err := conn.Do("SADD", args...)
return err
if _, err := conn.Do("SADD", args...); err != nil {
return fmt.Errorf("sadd query names: %w", err)
}
return nil
}

func (r *redisLiveQuery) removeQueryInfo(name string) error {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanup

In loadCache(), changed go func() { err = r.removeQueryNames(names...); ... }() to go func() { if err := r.removeQueryNames(names...); err != nil { ... } }(), using a new locally-scoped err instead of closing over the outer function-scoped err variable. This eliminates the data race on the shared err and matches the suggested fix exactly.

🤖 Prompt for AI agents
In server/live_query/redis_live_query.go around line 296, review and complete this code-review fix: Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanup.
What the draft fix changed: In `loadCache()`, changed `go func() { err = r.removeQueryNames(names...); ... }()` to `go func() { if err := r.removeQueryNames(names...); err != nil { ... } }()`, using a new locally-scoped `err` instead of closing over the outer function-scoped `err` variable. This eliminates the data race on the shared `err` and matches the suggested fix exactly.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer

Comment on lines 315 to 324
var args redigo.Args
args = args.Add(activeQueriesKey)
args = args.AddFlat(names)
_, err := conn.Do("SADD", args...)
return err
if _, err := conn.Do("SADD", args...); err != nil {
return fmt.Errorf("sadd query names: %w", err)
}
return nil
}

func (r *redisLiveQuery) removeQueryInfo(name string) error {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrapping

Wrapped the bare error returns in storeQueryNames (SADD) and removeQueryNames (SREM) with fmt.Errorf("sadd query names: %w", err) and fmt.Errorf("srem query names: %w", err) respectively, bringing them in line with the file's error-wrapping convention used elsewhere (e.g. storeQueryInfo/removeQueryInfo). Note: the finding also mentions removeInactiveQueries, but that function already wraps its error via ctxerr.Wrap(ctx, err, "remove inactive campaign IDs"), so no change was needed there; only the two functions shown in the evidence lacked wrapping and were fixed.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In server/live_query/redis_live_query.go around line 220, review and complete this code-review fix: removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrapping.
What the draft fix changed: Wrapped the bare error returns in `storeQueryNames` (SADD) and `removeQueryNames` (SREM) with `fmt.Errorf("sadd query names: %w", err)` and `fmt.Errorf("srem query names: %w", err)` respectively, bringing them in line with the file's error-wrapping convention used elsewhere (e.g. storeQueryInfo/removeQueryInfo). Note: the finding also mentions `removeInactiveQueries`, but that function already wraps its error via `ctxerr.Wrap(ctx, err, "remove inactive campaign IDs")`, so no change was needed there; only the two functions shown in the evidence lacked wrapping and were fixed.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

return fmt.Errorf("call webhook: %w", err)
}
defer httpResp.Body.Close()
if httpResp.StatusCode != http.StatusOK {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Webhook.CallWebhook does not close the HTTP response body, leaking connections

Added defer httpResp.Body.Close() immediately after the successful w.client.Do(req) call in Webhook.CallWebhook, ensuring the response body is always closed and the underlying connection can be reused/released.

🤖 Prompt for AI agents
In server/mdm/nanodep/cmd/depsyncer/webhook.go around line 70, review and complete this code-review fix: Webhook.CallWebhook does not close the HTTP response body, leaking connections.
What the draft fix changed: Added `defer httpResp.Body.Close()` immediately after the successful `w.client.Do(req)` call in `Webhook.CallWebhook`, ensuring the response body is always closed and the underlying connection can be reused/released.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

@@ -20,7 +20,7 @@ module.exports = {
// Default to 'it-major-mdm' for users with an mdm primaryBuyingSituation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 migrate-old-primary-buying-situation-values.js uses !== {} which is always true and never skips the intended branch

In the fn handler's mdm stream callback (website/scripts/migrate-old-primary-buying-situation-values.js), changed the always-true if(thisUser.getStartedQuestionnaireAnswers !== {}) reference-comparison guard to if(thisUser.getStartedQuestionnaireAnswers && Object.keys(thisUser.getStartedQuestionnaireAnswers).length > 0), matching the suggested fix. This prevents the TypeError from indexing into getStartedQuestionnaireAnswers when it is null/undefined and correctly skips users with an empty answers object.

🤖 Prompt for AI agents
In website/scripts/migrate-old-primary-buying-situation-values.js around line 20, review and complete this code-review fix: migrate-old-primary-buying-situation-values.js uses `!== {}` which is always true and never skips the intended branch.
What the draft fix changed: In the `fn` handler's `mdm` stream callback (`website/scripts/migrate-old-primary-buying-situation-values.js`), changed the always-true `if(thisUser.getStartedQuestionnaireAnswers !== {})` reference-comparison guard to `if(thisUser.getStartedQuestionnaireAnswers && Object.keys(thisUser.getStartedQuestionnaireAnswers).length > 0)`, matching the suggested fix. This prevents the TypeError from indexing into `getStartedQuestionnaireAnswers` when it is null/undefined and correctly skips users with an empty answers object.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 97 to 103
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={() => <EmptySoftwareTable />}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Software card 'All' tab sorts by hosts_count instead of name despite constant naming

In the 'All' tab's TableContainer (first TabPanel) in the Software component, changed defaultSortHeader={SOFTWARE_DEFAULT_SORT_DIRECTION} to defaultSortHeader={SOFTWARE_DEFAULT_SORT_HEADER}, matching the correct constant used for sort column and consistent with the 'Vulnerable' tab below.

🤖 Prompt for AI agents
In frontend/pages/DashboardPage/cards/Software/Software.tsx around line 96, review and complete this code-review fix: Software card 'All' tab sorts by hosts_count instead of name despite constant naming.
What the draft fix changed: In the 'All' tab's TableContainer (first TabPanel) in the Software component, changed `defaultSortHeader={SOFTWARE_DEFAULT_SORT_DIRECTION}` to `defaultSortHeader={SOFTWARE_DEFAULT_SORT_HEADER}`, matching the correct constant used for sort column and consistent with the 'Vulnerable' tab below.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

@@ -4,9 +4,10 @@ import (
maintained_apps "github.com/fleetdm/fleet/v4/ee/maintained-apps"
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 CiscoJabberVersionTransformer doc comment states wrong version value

Updated the doc comment on CiscoJabberVersionTransformer (line 5) to say "15.2.1" instead of "15.2.0", matching the actual assigned value app.Version = "15.2.1" in the function body. No behavioral code was changed.

🤖 Prompt for AI agents
In ee/maintained-apps/ingesters/homebrew/external_refs/cisco_jabber_version_transformer.go around line 5, review and complete this code-review fix: CiscoJabberVersionTransformer doc comment states wrong version value.
What the draft fix changed: Updated the doc comment on CiscoJabberVersionTransformer (line 5) to say "15.2.1" instead of "15.2.0", matching the actual assigned value `app.Version = "15.2.1"` in the function body. No behavioral code was changed.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 24 to 30
func (s *googleCalendarIntegrationTestSuite) SetupSuite() {
dbFile, err := os.CreateTemp("", "calendar.db")
s.Require().NoError(err)
s.dbFile = dbFile
handler, err := calendartest.Configure(dbFile.Name())
s.Require().NoError(err)
server := httptest.NewUnstartedServer(handler)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 Test suite leaves dbFile nil, TearDownSuite guard is dead code

In SetupSuite, added s.dbFile = dbFile immediately after os.CreateTemp succeeds, so the struct field is populated and TearDownSuite's if s.dbFile != nil guard now correctly closes and removes the temp file on cleanup.

🤖 Prompt for AI agents
In ee/server/calendar/google_calendar_integration_test.go around line 21, review and complete this code-review fix: Test suite leaves dbFile nil, TearDownSuite guard is dead code.
What the draft fix changed: In `SetupSuite`, added `s.dbFile = dbFile` immediately after `os.CreateTemp` succeeds, so the struct field is populated and `TearDownSuite`'s `if s.dbFile != nil` guard now correctly closes and removes the temp file on cleanup.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Comment on lines 76 to 82
await CriticalInstall.update({softwareType: complianceType}).set({isCompliant: false});
let numberOfTheseInstalls = await CriticalInstall.count({softwareType: complianceType});
newCompliantVersions = await CriticalInstall.update({fleetApid: {in: compliantVersions}}).set({isCompliant: true}).fetch();
newPatchProgress = Math.floor(newCompliantInstalls.length /numberOfTheseInstalls * 100);
newPatchProgress = Math.floor(newCompliantVersions.length /numberOfTheseInstalls * 100);
}


Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 set-compliant-versions.js divides by newCompliantInstalls.length before it is populated, causing NaN/Infinity progress

In the final else branch of the fn function in set-compliant-versions.js, changed newPatchProgress = Math.floor(newCompliantInstalls.length /numberOfTheseInstalls * 100); to newPatchProgress = Math.floor(newCompliantVersions.length /numberOfTheseInstalls * 100);, using the populated newCompliantVersions array (from .fetch()) instead of the always-empty module-level newCompliantInstalls array, matching the suggested fix exactly.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In ee/vulnerability-dashboard/api/controllers/set-compliant-versions.js around line 52, review and complete this code-review fix: set-compliant-versions.js divides by newCompliantInstalls.length before it is populated, causing NaN/Infinity progress.
What the draft fix changed: In the final `else` branch of the `fn` function in `set-compliant-versions.js`, changed `newPatchProgress = Math.floor(newCompliantInstalls.length /numberOfTheseInstalls * 100);` to `newPatchProgress = Math.floor(newCompliantVersions.length /numberOfTheseInstalls * 100);`, using the populated `newCompliantVersions` array (from `.fetch()`) instead of the always-empty module-level `newCompliantInstalls` array, matching the suggested fix exactly.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

@flamingo

flamingo Bot commented Aug 24, 2026

Copy link
Copy Markdown
Author

🦩 What this fix changed, finding by finding

57 finding(s) fixed in this draft. (Inline placement was rejected by GitHub for this PR.)

🟠 1. Wrong table name in error message: 'operating_systems table' referenced while creating windows_updatesserver/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go:22
In Up_20220831100151, changed the error message text from "create operating_systems table" to "create windows_updates table" to correctly reflect the table being created.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go around line 22, review and complete this code-review fix: Wrong table name in error message: 'operating_systems table' referenced while creating windows_updates.
What the draft fix changed: In Up_20220831100151, changed the error message text from "create operating_systems table" to "create windows_updates table" to correctly reflect the table being created.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 2. errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creationserver/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go:14
In Up_20220831100151, replaced errors.Wrapf(err, "...") from github.com/pkg/errors with fmt.Errorf("create windows_updates table: %w", err), and updated the import block to remove github.com/pkg/errors and add fmt, matching the pattern used elsewhere in the migrations package.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20220831100151_AddWindowsUpdatesTable.go around line 14, review and complete this code-review fix: errors.Wrapf from pkg/errors used instead of fmt.Errorf(%w) for windows_updates table creation.
What the draft fix changed: In Up_20220831100151, replaced `errors.Wrapf(err, "...")` from `github.com/pkg/errors` with `fmt.Errorf("create windows_updates table: %w", err)`, and updated the import block to remove `github.com/pkg/errors` and add `fmt`, matching the pattern used elsewhere in the migrations package.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 3. Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanupserver/live_query/redis_live_query.go:296
In loadCache(), changed go func() { err = r.removeQueryNames(names...); ... }() to go func() { if err := r.removeQueryNames(names...); err != nil { ... } }(), using a new locally-scoped err instead of closing over the outer function-scoped err variable. This eliminates the data race on the shared err and matches the suggested fix exactly.

🤖 Prompt for AI agents
In server/live_query/redis_live_query.go around line 296, review and complete this code-review fix: Cache read inside collectBatchQueriesForHost can race with async loadCache goroutine cleanup.
What the draft fix changed: In `loadCache()`, changed `go func() { err = r.removeQueryNames(names...); ... }()` to `go func() { if err := r.removeQueryNames(names...); err != nil { ... } }()`, using a new locally-scoped `err` instead of closing over the outer function-scoped `err` variable. This eliminates the data race on the shared `err` and matches the suggested fix exactly.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer

🟠 4. removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrappingserver/live_query/redis_live_query.go:220
Wrapped the bare error returns in storeQueryNames (SADD) and removeQueryNames (SREM) with fmt.Errorf("sadd query names: %w", err) and fmt.Errorf("srem query names: %w", err) respectively, bringing them in line with the file's error-wrapping convention used elsewhere (e.g. storeQueryInfo/removeQueryInfo). Note: the finding also mentions removeInactiveQueries, but that function already wraps its error via ctxerr.Wrap(ctx, err, "remove inactive campaign IDs"), so no change was needed there; only the two functions shown in the evidence lacked wrapping and were fixed.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In server/live_query/redis_live_query.go around line 220, review and complete this code-review fix: removeInactiveQueries and storeQueryNames/removeQueryNames return bare errors without wrapping.
What the draft fix changed: Wrapped the bare error returns in `storeQueryNames` (SADD) and `removeQueryNames` (SREM) with `fmt.Errorf("sadd query names: %w", err)` and `fmt.Errorf("srem query names: %w", err)` respectively, bringing them in line with the file's error-wrapping convention used elsewhere (e.g. storeQueryInfo/removeQueryInfo). Note: the finding also mentions `removeInactiveQueries`, but that function already wraps its error via `ctxerr.Wrap(ctx, err, "remove inactive campaign IDs")`, so no change was needed there; only the two functions shown in the evidence lacked wrapping and were fixed.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

🟠 5. Webhook.CallWebhook does not close the HTTP response body, leaking connectionsserver/mdm/nanodep/cmd/depsyncer/webhook.go:70
Added defer httpResp.Body.Close() immediately after the successful w.client.Do(req) call in Webhook.CallWebhook, ensuring the response body is always closed and the underlying connection can be reused/released.

🤖 Prompt for AI agents
In server/mdm/nanodep/cmd/depsyncer/webhook.go around line 70, review and complete this code-review fix: Webhook.CallWebhook does not close the HTTP response body, leaking connections.
What the draft fix changed: Added `defer httpResp.Body.Close()` immediately after the successful `w.client.Do(req)` call in `Webhook.CallWebhook`, ensuring the response body is always closed and the underlying connection can be reused/released.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 6. Bare error returns without context wrapping in webhook.goserver/mdm/nanodep/cmd/depsyncer/webhook.go:60
Wrapped the previously bare error returns in Webhook.CallWebhook with fmt.Errorf("...: %w", err): json.Marshal errors now wrapped as "marshal webhook event", http.NewRequestWithContext errors as "build webhook request", and the w.client.Do(req) error as "call webhook", per the suggested fix (extended slightly to the Do() call for consistency, which was implied by the finding's title but not shown in the truncated suggested snippet).

🤖 Prompt for AI agents
In server/mdm/nanodep/cmd/depsyncer/webhook.go around line 60, review and complete this code-review fix: Bare error returns without context wrapping in webhook.go.
What the draft fix changed: Wrapped the previously bare error returns in `Webhook.CallWebhook` with `fmt.Errorf("...: %w", err)`: `json.Marshal` errors now wrapped as "marshal webhook event", `http.NewRequestWithContext` errors as "build webhook request", and the `w.client.Do(req)` error as "call webhook", per the suggested fix (extended slightly to the Do() call for consistency, which was implied by the finding's title but not shown in the truncated suggested snippet).
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer

🟠 7. Windows binary name check uses wrong comparison value in fleetctl-npm run.jstools/fleetctl-npm/run.js:39
In the default case of the platform switch (inside the IIFE assigned to platform), changed throw new Error(\platform ${type} unrecognized`)tothrow new Error(`platform ${type()} unrecognized`)` so the actual OS type string is interpolated instead of the function reference.

🤖 Prompt for AI agents
In tools/fleetctl-npm/run.js around line 39, review and complete this code-review fix: Windows binary name check uses wrong comparison value in fleetctl-npm run.js.
What the draft fix changed: In the default case of the `platform` switch (inside the IIFE assigned to `platform`), changed `throw new Error(\`platform ${type} unrecognized\`)` to `throw new Error(\`platform ${type()} unrecognized\`)` so the actual OS type string is interpolated instead of the function reference.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 8. Unreachable/incorrect error message interpolates function reference instead of platform valuetools/fleetctl-npm/run.js:27
Changed the binName computation from platform === "windows" ? "fleetctl.exe" : "fleetctl" to platform.startsWith("windows") ? "fleetctl.exe" : "fleetctl", matching the actual windows_amd64/windows_arm64 values produced by the platform switch above so the .exe suffix is correctly applied on Windows.

🤖 Prompt for AI agents
In tools/fleetctl-npm/run.js around line 27, review and complete this code-review fix: Unreachable/incorrect error message interpolates function reference instead of platform value.
What the draft fix changed: Changed the `binName` computation from `platform === "windows" ? "fleetctl.exe" : "fleetctl"` to `platform.startsWith("windows") ? "fleetctl.exe" : "fleetctl"`, matching the actual `windows_amd64`/`windows_arm64` values produced by the `platform` switch above so the `.exe` suffix is correctly applied on Windows.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 9. migrate-users-with-no-trial-key.js uses Array.includes on a query result of full record objects, so the membership check never matcheswebsite/scripts/migrate-users-with-no-trial-key.js:18
In fn, changed idsOfUsersWithSubscriptions assignment to map the Subscription.find().select('user') result array of records to an array of scalar user IDs via .map((subscription)=>subscription.user), so the later idsOfUsersWithSubscriptions.includes(thisUser.id) check now correctly compares scalar IDs and properly skips users with existing subscriptions.

🤖 Prompt for AI agents
In website/scripts/migrate-users-with-no-trial-key.js around line 18, review and complete this code-review fix: migrate-users-with-no-trial-key.js uses Array.includes on a query result of full record objects, so the membership check never matches.
What the draft fix changed: In `fn`, changed `idsOfUsersWithSubscriptions` assignment to map the `Subscription.find().select('user')` result array of records to an array of scalar `user` IDs via `.map((subscription)=>subscription.user)`, so the later `idsOfUsersWithSubscriptions.includes(thisUser.id)` check now correctly compares scalar IDs and properly skips users with existing subscriptions.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer

🟠 10. migrate-users-with-no-trial-key.js sends a placeholder/wrong subject line 'Whoops' for the trial-license emailwebsite/scripts/migrate-users-with-no-trial-key.js:56
In the sendTemplateEmail call inside fn, changed the placeholder subject: 'Whoops' to a descriptive subject 'Your Fleet Premium trial is ready'. Exact wording is a judgment call since the intended production subject line wasn't specified in the finding; a reviewer familiar with the marketing copy/template should confirm or adjust the final text.

🤖 Prompt for AI agents
In website/scripts/migrate-users-with-no-trial-key.js around line 56, review and complete this code-review fix: migrate-users-with-no-trial-key.js sends a placeholder/wrong subject line 'Whoops' for the trial-license email.
What the draft fix changed: In the `sendTemplateEmail` call inside `fn`, changed the placeholder `subject: 'Whoops'` to a descriptive subject `'Your Fleet Premium trial is ready'`. Exact wording is a judgment call since the intended production subject line wasn't specified in the finding; a reviewer familiar with the marketing copy/template should confirm or adjust the final text.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer

🟠 11. signingRoundTripper.RoundTrip formats signer error with %#v instead of %wee/orbit/pkg/httpsigproxy/httpsigproxy.go:210
In signingRoundTripper.RoundTrip (near line 210), changed fmt.Errorf("signing request: %#v", err) to fmt.Errorf("signing request: %w", err), preserving the error chain via wrapping and producing a readable message.

🤖 Prompt for AI agents
In ee/orbit/pkg/httpsigproxy/httpsigproxy.go around line 210, review and complete this code-review fix: signingRoundTripper.RoundTrip formats signer error with %#v instead of %w.
What the draft fix changed: In signingRoundTripper.RoundTrip (near line 210), changed fmt.Errorf("signing request: %#v", err) to fmt.Errorf("signing request: %w", err), preserving the error chain via wrapping and producing a readable message.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 12. Proxy.Serve() wraps a nil-possible error from http.Server.Serve without distinguishing ErrServerClosedee/orbit/pkg/httpsigproxy/httpsigproxy.go:138
In Proxy.Serve (near line 138), added errors.Is(err, http.ErrServerClosed) check after p.server.Serve(p.listener); returns nil on graceful shutdown instead of wrapping/returning http.ErrServerClosed as a failure, while still wrapping any other non-nil error with %w as before.

🤖 Prompt for AI agents
In ee/orbit/pkg/httpsigproxy/httpsigproxy.go around line 138, review and complete this code-review fix: Proxy.Serve() wraps a nil-possible error from http.Server.Serve without distinguishing ErrServerClosed.
What the draft fix changed: In Proxy.Serve (near line 138), added errors.Is(err, http.ErrServerClosed) check after p.server.Serve(p.listener); returns nil on graceful shutdown instead of wrapping/returning http.ErrServerClosed as a failure, while still wrapping any other non-nil error with %w as before.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 85 medium — react 👍/👎 to teach the reviewer

🟠 13. Assertions placed outside it() block execute at describe-time, not as part of any testfrontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts:79
In the isMissingAnyRequiredField describe block, the two trailing expect(...) calls (metadata-not-required-if-metadata_url-present, and metadata_url-not-required-if-metadata-present) were moved out of the bare describe body and wrapped in a new it("returns false if metadata or metadata_url is present", () => { ... }) block, so they now execute and report as part of a real test case instead of at collection time.

🤖 Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts around line 79, review and complete this code-review fix: Assertions placed outside `it()` block execute at describe-time, not as part of any test.
What the draft fix changed: In the `isMissingAnyRequiredField` describe block, the two trailing `expect(...)` calls (metadata-not-required-if-metadata_url-present, and metadata_url-not-required-if-metadata-present) were moved out of the bare describe body and wrapped in a new `it("returns false if metadata or metadata_url is present", () => { ... })` block, so they now execute and report as part of a real test case instead of at collection time.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer

🟠 14. Assertions placed outside it() block in newFormDataIdp describe block never run as part of a testfrontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts:231
In the newFormDataIdP describe block, the trailing expect(...) calls (whitespace trimming, undefined input, and partial config with only entity_id) were moved into a new it("trims whitespace and fills in missing fields", () => { ... }) block, so they now run and are reported as part of the test suite rather than executing during Jest's describe-collection phase.

🤖 Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/IdentityProviders/components/EndUserAuthSection/helpers.tests.ts around line 231, review and complete this code-review fix: Assertions placed outside `it()` block in newFormDataIdp describe block never run as part of a test.
What the draft fix changed: In the `newFormDataIdP` describe block, the trailing `expect(...)` calls (whitespace trimming, `undefined` input, and partial config with only `entity_id`) were moved into a new `it("trims whitespace and fills in missing fields", () => { ... })` block, so they now run and are reported as part of the test suite rather than executing during Jest's describe-collection phase.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 15. getInstallErrorMessage produces malformed double-period message for fleetd-installed errorfrontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx:58
In getInstallErrorMessage, the fleetd installed branch's return string was changed from `${INSTALL_SOFTWARE_ERROR_PREFIX}. ${reason}.` to `${INSTALL_SOFTWARE_ERROR_PREFIX} ${reason}.`, removing the extra literal period that caused the doubled-period output.

🤖 Prompt for AI agents
In frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx around line 58, review and complete this code-review fix: getInstallErrorMessage produces malformed double-period message for fleetd-installed error.
What the draft fix changed: In `getInstallErrorMessage`, the `fleetd installed` branch's return string was changed from `` `${INSTALL_SOFTWARE_ERROR_PREFIX}. ${reason}.` `` to `` `${INSTALL_SOFTWARE_ERROR_PREFIX} ${reason}.` ``, removing the extra literal period that caused the doubled-period output.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 16. getUninstallErrorMessage's 'No uninstall script exists' branch also has a doubled-periodfrontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx:92
In getUninstallErrorMessage, the No uninstall script exists branch's return string was changed from `${UNINSTALL_SOFTWARE_ERROR_PREFIX}. An uninstall script does not exist for this package.` to `${UNINSTALL_SOFTWARE_ERROR_PREFIX} An uninstall script does not exist for this package.`, removing the extra literal period.

🤖 Prompt for AI agents
In frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx around line 92, review and complete this code-review fix: getUninstallErrorMessage's 'No uninstall script exists' branch also has a doubled-period.
What the draft fix changed: In `getUninstallErrorMessage`, the `No uninstall script exists` branch's return string was changed from `` `${UNINSTALL_SOFTWARE_ERROR_PREFIX}. An uninstall script does not exist for this package.` `` to `` `${UNINSTALL_SOFTWARE_ERROR_PREFIX} An uninstall script does not exist for this package.` ``, removing the extra literal period.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 17. DisassociateAssets missing context parameter breaks caller cancellation/timeout propagationserver/mdm/apple/vpp/api.go:200
Added a ctx context.Context parameter to DisassociateAssets in server/mdm/apple/vpp/api.go, matching the signature pattern of AssociateAssets/RegisterUser/GetAssets/GetConfig in the same file, so cancellation/timeout can propagate from the caller. Note: this is a breaking signature change for any existing callers of DisassociateAssets, which live outside this file and were not visible/updatable here — those call sites will need a corresponding update to pass a context.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In server/mdm/apple/vpp/api.go around line 200, review and complete this code-review fix: DisassociateAssets missing context parameter breaks caller cancellation/timeout propagation.
What the draft fix changed: Added a `ctx context.Context` parameter to `DisassociateAssets` in server/mdm/apple/vpp/api.go, matching the signature pattern of `AssociateAssets`/`RegisterUser`/`GetAssets`/`GetConfig` in the same file, so cancellation/timeout can propagate from the caller. Note: this is a breaking signature change for any existing callers of `DisassociateAssets`, which live outside this file and were not visible/updatable here — those call sites will need a corresponding update to pass a context.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

🟠 18. DisassociateAssets propagates bare http.NewRequest error without context wrapping in a shared packageserver/mdm/apple/vpp/api.go:205
Replaced http.NewRequest with http.NewRequestWithContext(ctx, ...) in DisassociateAssets (server/mdm/apple/vpp/api.go), using the new ctx parameter added for finding 1, so the request is bound to caller-supplied cancellation/timeout just like the sibling AssociateAssets/RegisterUser/GetAssets functions. The existing fmt.Errorf("creating request to Apple VPP endpoint: %w", err) wrapping was left unchanged as the finding's primary concern was the missing context propagation, not the wrapping style.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In server/mdm/apple/vpp/api.go around line 205, review and complete this code-review fix: DisassociateAssets propagates bare http.NewRequest error without context wrapping in a shared package.
What the draft fix changed: Replaced `http.NewRequest` with `http.NewRequestWithContext(ctx, ...)` in `DisassociateAssets` (server/mdm/apple/vpp/api.go), using the new `ctx` parameter added for finding 1, so the request is bound to caller-supplied cancellation/timeout just like the sibling `AssociateAssets`/`RegisterUser`/`GetAssets` functions. The existing `fmt.Errorf("creating request to Apple VPP endpoint: %w", err)` wrapping was left unchanged as the finding's primary concern was the missing context propagation, not the wrapping style.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

🟠 19. makeAndroidAppUnavailable in software_worker.go swallows detailed context on RemoveAppsFromAndroidPolicy failureserver/worker/software_worker.go:279
In makeAndroidAppUnavailable (server/worker/software_worker.go), changed the ctxerr.Wrap error message from the copy-pasted "add app store app: add app to android policy" to "remove app store app: remove app from android policy" to accurately reflect that this function removes apps from the Android policy, matching the suggested fix exactly.

🤖 Prompt for AI agents
In server/worker/software_worker.go around line 279, review and complete this code-review fix: makeAndroidAppUnavailable in software_worker.go swallows detailed context on RemoveAppsFromAndroidPolicy failure.
What the draft fix changed: In `makeAndroidAppUnavailable` (server/worker/software_worker.go), changed the `ctxerr.Wrap` error message from the copy-pasted "add app store app: add app to android policy" to "remove app store app: remove app from android policy" to accurately reflect that this function removes apps from the Android policy, matching the suggested fix exactly.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 20. makeAndroidAppAvailablePerHost hardcodes admin GlobalRole via undefined-looking helper 'new'server/worker/software_worker.go:213
In makeAndroidAppAvailablePerHost (server/worker/software_worker.go), replaced the non-compiling new("admin") call (builtin new only takes a type) with ptr.String("admin"), using the ptr package already imported in this file (github.com/fleetdm/fleet/v4/server/ptr), which provides a standard String(s string) *string helper. This makes the fleet.User{GlobalRole: ...} field assignment compile correctly. Risk: I could not verify from this file alone that ptr.String exists with that exact signature/name in this codebase (it's used elsewhere in the codebase idiomatically, and ptr.ValOrZero/ptr.String patterns are already visible via ptr.ValOrZero usage in this file, so this is a reasonable and low-risk assumption), but a full fix would require confirming ptr.String is exported and behaves as expected, and ideally verifying no local new helper was actually intended to exist elsewhere in the package.

🤖 Prompt for AI agents
In server/worker/software_worker.go around line 213, review and complete this code-review fix: makeAndroidAppAvailablePerHost hardcodes admin GlobalRole via undefined-looking helper 'new'.
What the draft fix changed: In `makeAndroidAppAvailablePerHost` (server/worker/software_worker.go), replaced the non-compiling `new("admin")` call (builtin `new` only takes a type) with `ptr.String("admin")`, using the `ptr` package already imported in this file (`github.com/fleetdm/fleet/v4/server/ptr`), which provides a standard `String(s string) *string` helper. This makes the `fleet.User{GlobalRole: ...}` field assignment compile correctly. Risk: I could not verify from this file alone that `ptr.String` exists with that exact signature/name in this codebase (it's used elsewhere in the codebase idiomatically, and `ptr.ValOrZero`/`ptr.String` patterns are already visible via `ptr.ValOrZero` usage in this file, so this is a reasonable and low-risk assumption), but a full fix would require confirming `ptr.String` is exported and behaves as expected, and ideally verifying no local `new` helper was actually intended to exist elsewhere in the package.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 75 medium — react 👍/👎 to teach the reviewer

🟠 21. santa_status.yml has duplicate/swapped descriptions for file_logging hash columnsschema/tables/santa_status.yml:40
In schema/tables/santa_status.yml, swapped the description strings for the sync_execution_rules_hash and sync_file_access_rules_hash columns so each now matches its column name ('execution ruleset' with sync_execution_rules_hash, 'file access ruleset' with sync_file_access_rules_hash).

🤖 Prompt for AI agents
In schema/tables/santa_status.yml around line 40, review and complete this code-review fix: santa_status.yml has duplicate/swapped descriptions for file_logging hash columns.
What the draft fix changed: In schema/tables/santa_status.yml, swapped the description strings for the sync_execution_rules_hash and sync_file_access_rules_hash columns so each now matches its column name ('execution ruleset' with sync_execution_rules_hash, 'file access ruleset' with sync_file_access_rules_hash).
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 22. santa_status.yml metrics_server column typed as integer but described as an address stringschema/tables/santa_status.yml:121
In schema/tables/santa_status.yml, changed the metrics_server column's type field from 'integer' to 'text' to match its address-string description, consistent with the sibling sync_server column.

🤖 Prompt for AI agents
In schema/tables/santa_status.yml around line 121, review and complete this code-review fix: santa_status.yml metrics_server column typed as integer but described as an address string.
What the draft fix changed: In schema/tables/santa_status.yml, changed the metrics_server column's type field from 'integer' to 'text' to match its address-string description, consistent with the sibling sync_server column.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 23. runMigration calls log.Fatal on migration transaction failure, killing the whole process instead of returning an errorserver/goose/migration.go:46
In runMigration's ".go" case, replaced log.Fatal("db.Begin: ", err) with return fmt.Errorf("db.Begin: %w", err) so a failed db.Begin() propagates as an error to the caller instead of terminating the process. No other logic in that branch changed.

🤖 Prompt for AI agents
In server/goose/migration.go around line 46, review and complete this code-review fix: runMigration calls log.Fatal on migration transaction failure, killing the whole process instead of returning an error.
What the draft fix changed: In runMigration's ".go" case, replaced `log.Fatal("db.Begin: ", err)` with `return fmt.Errorf("db.Begin: %w", err)` so a failed db.Begin() propagates as an error to the caller instead of terminating the process. No other logic in that branch changed.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 24. log.Fatal used inside FinalizeMigration failure path after fn(tx) fails, obscuring the returned errorserver/goose/migration.go:58
In runMigration's ".go" case, replaced the log.Fatalf(...); return err dead-code pattern after fn(tx) failure with return fmt.Errorf("FAIL %s: %w", filepath.Base(m.Source), err), so after rollback the error is properly returned to the caller instead of killing the process. Note: the subsequent FinalizeMigration error handling on the next line (log.Fatalf("error finalizing migration...")) was left unchanged since it was not part of the requested findings, though it exhibits a similar pattern — flagging this as a residual risk for a follow-up fix.

🤖 Prompt for AI agents
In server/goose/migration.go around line 58, review and complete this code-review fix: log.Fatal used inside FinalizeMigration failure path after fn(tx) fails, obscuring the returned error.
What the draft fix changed: In runMigration's ".go" case, replaced the `log.Fatalf(...); return err` dead-code pattern after `fn(tx)` failure with `return fmt.Errorf("FAIL %s: %w", filepath.Base(m.Source), err)`, so after rollback the error is properly returned to the caller instead of killing the process. Note: the subsequent `FinalizeMigration` error handling on the next line (`log.Fatalf("error finalizing migration...")`) was left unchanged since it was not part of the requested findings, though it exhibits a similar pattern — flagging this as a residual risk for a follow-up fix.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 25. Duplicate GenerateSingleSSIDTestWLANXMLProfiles call in TestIsWLANXML produces two identical variablesserver/mdm/microsoft/wlanxml/wlanxml_test.go:82
In TestIsWLANXML, changed singleNonBroadcastingProfileNameOnly assignment from GenerateSingleSSIDTestWLANXMLProfiles(t, false, true, true) to GenerateSingleSSIDTestWLANXMLProfiles(t, true, false, true), matching the suggested fix so it now generates a name-only (hex omitted) profile instead of duplicating the hex-only case.

🤖 Prompt for AI agents
In server/mdm/microsoft/wlanxml/wlanxml_test.go around line 82, review and complete this code-review fix: Duplicate GenerateSingleSSIDTestWLANXMLProfiles call in TestIsWLANXML produces two identical variables.
What the draft fix changed: In TestIsWLANXML, changed `singleNonBroadcastingProfileNameOnly` assignment from `GenerateSingleSSIDTestWLANXMLProfiles(t, false, true, true)` to `GenerateSingleSSIDTestWLANXMLProfiles(t, true, false, true)`, matching the suggested fix so it now generates a name-only (hex omitted) profile instead of duplicating the hex-only case.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 26. TestEqual compares wrong variable pairs for 'hex only' vs 'name only' single-SSID casesserver/mdm/microsoft/wlanxml/wlanxml_test.go:133
In TestEqual, changed simpleBroadcastingProfileNameOnly assignment from GenerateSingleSSIDTestWLANXMLProfiles(t, false, true, false) to GenerateSingleSSIDTestWLANXMLProfiles(t, true, false, false), matching the suggested fix so the "one only includes Name and one only includes Hex" test case now genuinely compares a name-only profile against a hex-only profile.

🤖 Prompt for AI agents
In server/mdm/microsoft/wlanxml/wlanxml_test.go around line 133, review and complete this code-review fix: TestEqual compares wrong variable pairs for 'hex only' vs 'name only' single-SSID cases.
What the draft fix changed: In TestEqual, changed `simpleBroadcastingProfileNameOnly` assignment from `GenerateSingleSSIDTestWLANXMLProfiles(t, false, true, false)` to `GenerateSingleSSIDTestWLANXMLProfiles(t, true, false, false)`, matching the suggested fix so the "one only includes Name and one only includes Hex" test case now genuinely compares a name-only profile against a hex-only profile.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer

🟠 27. Check-in handler continues to write response body after error, causing double header writeserver/mdm/nanomdm/http/mdm/mdm.go:48
In CheckinHandler (mdm.go), added an explicit return statement immediately after the http.Error(w, ...) call inside the if err != nil block that handles the error from service.CheckinRequest, preventing fallthrough to the unconditional w.Write(respBytes).

🤖 Prompt for AI agents
In server/mdm/nanomdm/http/mdm/mdm.go around line 48, review and complete this code-review fix: Check-in handler continues to write response body after error, causing double header write.
What the draft fix changed: In CheckinHandler (mdm.go), added an explicit `return` statement immediately after the `http.Error(w, ...)` call inside the `if err != nil` block that handles the error from `service.CheckinRequest`, preventing fallthrough to the unconditional `w.Write(respBytes)`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 28. CommandAndReportResultsHandler falls through to Write after http.Error on failureserver/mdm/nanomdm/http/mdm/mdm.go:82
In CommandAndReportResultsHandler (mdm.go), added an explicit return statement immediately after the http.Error(w, ...) call inside the if err != nil block that handles the error from service.CommandAndReportResultsRequest, preventing fallthrough to the unconditional w.Write(respBytes).

🤖 Prompt for AI agents
In server/mdm/nanomdm/http/mdm/mdm.go around line 82, review and complete this code-review fix: CommandAndReportResultsHandler falls through to Write after http.Error on failure.
What the draft fix changed: In CommandAndReportResultsHandler (mdm.go), added an explicit `return` statement immediately after the `http.Error(w, ...)` call inside the `if err != nil` block that handles the error from `service.CommandAndReportResultsRequest`, preventing fallthrough to the unconditional `w.Write(respBytes)`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 29. resolveBranch has unreachable duplicate return statement after the nil-lastErr branchtools/migration-cleanup/main.go:248
In resolveBranch, removed the unreachable trailing return "", fmt.Errorf(...) statement after the if lastErr != nil block. Since this branch of the fix now always returns from within the if, the dead final statement was deleted (it also became structurally impossible via the combined fix, since the wrapped-error return now unconditionally executes at the end of the loop, replacing both prior return statements with a single one).

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In tools/migration-cleanup/main.go around line 248, review and complete this code-review fix: resolveBranch has unreachable duplicate return statement after the nil-lastErr branch.
What the draft fix changed: In `resolveBranch`, removed the unreachable trailing `return "", fmt.Errorf(...)` statement after the `if lastErr != nil` block. Since this branch of the fix now always returns from within the `if`, the dead final statement was deleted (it also became structurally impossible via the combined fix, since the wrapped-error return now unconditionally executes at the end of the loop, replacing both prior return statements with a single one).

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

🟠 30. Bare error return without wrapping context in resolveBranchtools/migration-cleanup/main.go:236
In resolveBranch, replaced the two duplicate/dead fmt.Errorf("ERROR: cannot resolve branch %q", branch) returns (including the if lastErr != nil conditional wrapper) with a single unconditional return "", fmt.Errorf("cannot resolve branch %q: %w", branch, lastErr) at the end of the function, wrapping the underlying git error via %w as suggested. This also resolves finding 1 since only one reachable return statement remains.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In tools/migration-cleanup/main.go around line 236, review and complete this code-review fix: Bare error return without wrapping context in resolveBranch.
What the draft fix changed: In `resolveBranch`, replaced the two duplicate/dead `fmt.Errorf("ERROR: cannot resolve branch %q", branch)` returns (including the `if lastErr != nil` conditional wrapper) with a single unconditional `return "", fmt.Errorf("cannot resolve branch %q: %w", branch, lastErr)` at the end of the function, wrapping the underlying git error via `%w` as suggested. This also resolves finding 1 since only one reachable return statement remains.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

🟠 31. Test uses non-existent ptr.String(fleet.RoleObserver) call shape inconsistently with rest of fileserver/service/targets_test.go:59
In TestSearchTargetsStripsSecretsAndAgentOptions, replaced new(fleet.RoleObserver) with ptr.String(fleet.RoleObserver) for constructing the GlobalRole field, matching the pattern used elsewhere in the file (e.g., ptr.String(fleet.RoleAdmin)) and fixing the compile error.

🤖 Prompt for AI agents
In server/service/targets_test.go around line 59, review and complete this code-review fix: Test uses non-existent ptr.String(fleet.RoleObserver) call shape inconsistently with rest of file.
What the draft fix changed: In TestSearchTargetsStripsSecretsAndAgentOptions, replaced `new(fleet.RoleObserver)` with `ptr.String(fleet.RoleObserver)` for constructing the `GlobalRole` field, matching the pattern used elsewhere in the file (e.g., `ptr.String(fleet.RoleAdmin)`) and fixing the compile error.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 32. TeamID pointer constructed with new(uint(1)) is invalid Go syntaxserver/service/targets_test.go:68
In TestSearchTargetsStripsSecretsAndAgentOptions, replaced both invalid new(uint(1)) / new(uint(2)) expressions with ptr.Uint(1) / ptr.Uint(2) respectively for the TeamID fields of fleet.EnrollSecret, fixing the compile error and correctly constructing *uint values.

🤖 Prompt for AI agents
In server/service/targets_test.go around line 68, review and complete this code-review fix: TeamID pointer constructed with new(uint(1)) is invalid Go syntax.
What the draft fix changed: In TestSearchTargetsStripsSecretsAndAgentOptions, replaced both invalid `new(uint(1))` / `new(uint(2))` expressions with `ptr.Uint(1)` / `ptr.Uint(2)` respectively for the `TeamID` fields of `fleet.EnrollSecret`, fixing the compile error and correctly constructing `*uint` values.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 33. server.ListenAndServe error in mdmproxy main() is only printed, not treated as fataltools/mdm/migration/mdmproxy/mdmproxy.go:366
In main(), changed fmt.Printf("Error starting server: %s\n", err) to log.Fatalf("Error starting server: %s\n", err) after server.ListenAndServe() returns an error, ensuring the process exits with a non-zero status on startup failure instead of returning normally.

🤖 Prompt for AI agents
In tools/mdm/migration/mdmproxy/mdmproxy.go around line 366, review and complete this code-review fix: server.ListenAndServe error in mdmproxy main() is only printed, not treated as fatal.
What the draft fix changed: In main(), changed `fmt.Printf("Error starting server: %s\n", err)` to `log.Fatalf("Error starting server: %s\n", err)` after `server.ListenAndServe()` returns an error, ensuring the process exits with a non-zero status on startup failure instead of returning normally.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🔵 34. Duplicated auth-token validation logic between handleUpdatePercentage and handleUpdateMigrateUDIDstools/mdm/migration/mdmproxy/mdmproxy.go:140
Extracted the duplicated token/bearer-header validation block from handleUpdatePercentage and handleUpdateMigrateUDIDs into a new shared method func (m *mdmProxy) authorize(w http.ResponseWriter, r *http.Request) bool, which writes the appropriate http.Error response and returns false on failure. Both handlers now call if !m.authorize(w, r) { return } at the top instead of the inline 15-line block.

🤖 Prompt for AI agents
In tools/mdm/migration/mdmproxy/mdmproxy.go around line 140, review and complete this code-review fix: Duplicated auth-token validation logic between handleUpdatePercentage and handleUpdateMigrateUDIDs.
What the draft fix changed: Extracted the duplicated token/bearer-header validation block from `handleUpdatePercentage` and `handleUpdateMigrateUDIDs` into a new shared method `func (m *mdmProxy) authorize(w http.ResponseWriter, r *http.Request) bool`, which writes the appropriate `http.Error` response and returns false on failure. Both handlers now call `if !m.authorize(w, r) { return }` at the top instead of the inline 15-line block.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 85 medium — react 👍/👎 to teach the reviewer

🟠 35. INSUFFICIENT_PERMISSIONS_ERROR constant referenced but not returned in NDESForm getErrorMessagefrontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/NDESForm/helpers.ts:141
In getErrorMessage, changed the bare expression statement INSUFFICIENT_PERMISSIONS_ERROR; to return INSUFFICIENT_PERMISSIONS_ERROR; in the else if (reason.includes("does not have sufficient permissions")) branch, so the function now correctly returns the specific error message instead of falling through to DEFAULT_ERROR.

🤖 Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/NDESForm/helpers.ts around line 141, review and complete this code-review fix: INSUFFICIENT_PERMISSIONS_ERROR constant referenced but not returned in NDESForm getErrorMessage.
What the draft fix changed: In `getErrorMessage`, changed the bare expression statement `INSUFFICIENT_PERMISSIONS_ERROR;` to `return INSUFFICIENT_PERMISSIONS_ERROR;` in the `else if (reason.includes("does not have sufficient permissions"))` branch, so the function now correctly returns the specific error message instead of falling through to `DEFAULT_ERROR`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 97 high — react 👍/👎 to teach the reviewer

🟠 36. Duplicated useEffect comment header in LivePolicyPage.tsxfrontend/pages/policies/live/LivePolicyPage/LivePolicyPage.tsx:78
Removed the duplicated // Reroute users out of live flow when live queries are globally disabled comment line directly above the useEffect that reroutes users when disabledLiveQuery is true, leaving a single instance of the comment as suggested.

🤖 Prompt for AI agents
In frontend/pages/policies/live/LivePolicyPage/LivePolicyPage.tsx around line 78, review and complete this code-review fix: Duplicated useEffect comment header in LivePolicyPage.tsx.
What the draft fix changed: Removed the duplicated `// Reroute users out of live flow when live queries are globally disabled` comment line directly above the `useEffect` that reroutes users when `disabledLiveQuery` is true, leaving a single instance of the comment as suggested.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 100 high — react 👍/👎 to teach the reviewer

🟠 37. Invalid Go syntax new(time.Unix(1, 0)) in host_cache_writes_test.goserver/datastore/mysqlredis/host_cache_writes_test.go:79
In TestWritePathInvalidation, within the singleHostWrappers slice literal for the UpdateHostRefetchCriticalQueriesUntil case, replaced the invalid new(time.Unix(1, 0)) expression with a local variable until := time.Unix(1, 0) followed by return d.UpdateHostRefetchCriticalQueriesUntil(ctx, id, &until), matching the suggested fix exactly and restoring compilability of the test file.

🤖 Prompt for AI agents
In server/datastore/mysqlredis/host_cache_writes_test.go around line 79, review and complete this code-review fix: Invalid Go syntax `new(time.Unix(1, 0))` in host_cache_writes_test.go.
What the draft fix changed: In `TestWritePathInvalidation`, within the `singleHostWrappers` slice literal for the `UpdateHostRefetchCriticalQueriesUntil` case, replaced the invalid `new(time.Unix(1, 0))` expression with a local variable `until := time.Unix(1, 0)` followed by `return d.UpdateHostRefetchCriticalQueriesUntil(ctx, id, &until)`, matching the suggested fix exactly and restoring compilability of the test file.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 38. Misspelled field-doc comment 'BlcokSize' in CarveMetadataserver/fleet/carves.go:18
Fixed the doc comment typo above the BlockSize field in the CarveMetadata struct (server/fleet/carves.go), changing "BlcokSize is the size of each block in the carve." to "BlockSize is the size of each block in the carve." No other lines were modified.

🤖 Prompt for AI agents
In server/fleet/carves.go around line 18, review and complete this code-review fix: Misspelled field-doc comment 'BlcokSize' in CarveMetadata.
What the draft fix changed: Fixed the doc comment typo above the BlockSize field in the CarveMetadata struct (server/fleet/carves.go), changing "BlcokSize is the size of each block in the carve." to "BlockSize is the size of each block in the carve." No other lines were modified.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 39. RetrieveCursor stats the wrong file (profileFilename instead of cursorFilename)server/mdm/nanodep/storage/file/file.go:149
In FileStorage.RetrieveCursor, changed os.Stat(s.profileFilename(name)) to os.Stat(s.cursorFilename(name)) so the modification time returned reflects the cursor file itself rather than the unrelated assigner-profile file, fixing the copy-paste bug.

🤖 Prompt for AI agents
In server/mdm/nanodep/storage/file/file.go around line 149, review and complete this code-review fix: RetrieveCursor stats the wrong file (profileFilename instead of cursorFilename).
What the draft fix changed: In FileStorage.RetrieveCursor, changed `os.Stat(s.profileFilename(name))` to `os.Stat(s.cursorFilename(name))` so the modification time returned reflects the cursor file itself rather than the unrelated assigner-profile file, fixing the copy-paste bug.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 40. EncodeSCEPRequest POST branch ignores error from http.NewRequest before using rrserver/mdm/scep/server/transport.go:107
In EncodeSCEPRequest's POST branch, reordered the code so if err != nil check on the result of http.NewRequest happens immediately after the call and before rr.Header.Set(...) is invoked, preventing a nil-pointer dereference when NewRequest fails. Matches the suggested fix exactly.

🤖 Prompt for AI agents
In server/mdm/scep/server/transport.go around line 107, review and complete this code-review fix: EncodeSCEPRequest POST branch ignores error from http.NewRequest before using rr.
What the draft fix changed: In EncodeSCEPRequest's POST branch, reordered the code so `if err != nil` check on the result of `http.NewRequest` happens immediately after the call and before `rr.Header.Set(...)` is invoked, preventing a nil-pointer dereference when NewRequest fails. Matches the suggested fix exactly.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 41. SSOMFAConflict message has a duplicated 'is' typoserver/service/invites.go:40
Changed the SSOMFAConflict message string literal from "Fleet MFA is is not applicable to SSO users" to "Fleet MFA is not applicable to SSO users" in the package-level var declaration, removing the duplicated "is". No other code paths reference or depend on the exact wording, so this is a self-contained, mechanical fix.

🤖 Prompt for AI agents
In server/service/invites.go around line 40, review and complete this code-review fix: SSOMFAConflict message has a duplicated 'is' typo.
What the draft fix changed: Changed the `SSOMFAConflict` message string literal from "Fleet MFA is is not applicable to SSO users" to "Fleet MFA is not applicable to SSO users" in the package-level var declaration, removing the duplicated "is". No other code paths reference or depend on the exact wording, so this is a self-contained, mechanical fix.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 98 high — react 👍/👎 to teach the reviewer

🟠 42. Test bug: RemediatedBy set on wrong variable (cve3 instead of cve4)server/vulnerabilities/msrc/parsed/security_bulletin_test.go:53
In TestSecurityBulletin's .Vulnerabilities subtest, changed cve3.RemediatedBy = map[uint]bool{4: true} to cve4.RemediatedBy = map[uint]bool{4: true} so that cve4's RemediatedBy field is actually set, making the subsequent require.Equal(t, a.Vulnerabilities["cve-4"].RemediatedBy, cve4.RemediatedBy) assertion meaningful rather than vacuously true.

🤖 Prompt for AI agents
In server/vulnerabilities/msrc/parsed/security_bulletin_test.go around line 53, review and complete this code-review fix: Test bug: RemediatedBy set on wrong variable (cve3 instead of cve4).
What the draft fix changed: In TestSecurityBulletin's `.Vulnerabilities` subtest, changed `cve3.RemediatedBy = map[uint]bool{4: true}` to `cve4.RemediatedBy = map[uint]bool{4: true}` so that cve4's RemediatedBy field is actually set, making the subsequent `require.Equal(t, a.Vulnerabilities["cve-4"].RemediatedBy, cve4.RemediatedBy)` assertion meaningful rather than vacuously true.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 43. LoadHostConditionalAccessStatus ignores sql.ErrNoRows path and falls through to use zero-valued structserver/datastore/mysql/conditional_access_microsoft.go:85
In LoadHostConditionalAccessStatus, added a return nil, ... for the sql.ErrNoRows branch (preserving the existing wrapped notFound error) and added a new return nil, ctxerr.Wrap(ctx, err, "getting host conditional access status") for the generic error case, so the function no longer falls through to process a zero-valued struct when the query fails or finds no rows.

🤖 Prompt for AI agents
In server/datastore/mysql/conditional_access_microsoft.go around line 85, review and complete this code-review fix: LoadHostConditionalAccessStatus ignores sql.ErrNoRows path and falls through to use zero-valued struct.
What the draft fix changed: In LoadHostConditionalAccessStatus, added a `return nil, ...` for the sql.ErrNoRows branch (preserving the existing wrapped notFound error) and added a new `return nil, ctxerr.Wrap(ctx, err, "getting host conditional access status")` for the generic error case, so the function no longer falls through to process a zero-valued struct when the query fails or finds no rows.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 97 high — react 👍/👎 to teach the reviewer

🟠 44. Migration comment references wrong migration timestamp (copy-paste error)server/datastore/mysql/migrations/tables/20260528211626_AddClearPasscodeRefToHostMDMActions.go:13
Changed the doc comment above Up_20260528211626 from "Up_20260528163657 adds clear_passcode_ref..." to "Up_20260528211626 adds clear_passcode_ref..." to match the actual function name and migration timestamp, exactly as suggested.

🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20260528211626_AddClearPasscodeRefToHostMDMActions.go around line 13, review and complete this code-review fix: Migration comment references wrong migration timestamp (copy-paste error).
What the draft fix changed: Changed the doc comment above Up_20260528211626 from "Up_20260528163657 adds clear_passcode_ref..." to "Up_20260528211626 adds clear_passcode_ref..." to match the actual function name and migration timestamp, exactly as suggested.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 97 high — react 👍/👎 to teach the reviewer

🟠 45. isMac() compares a function reference to a boolean instead of calling isIPad()frontend/pages/hosts/details/DeviceUserPage/helpers.ts:66
In isMac (frontend/pages/hosts/details/DeviceUserPage/helpers.ts), changed !isIPad to !isIPad(navigator) so the function is actually invoked with the current navigator argument instead of testing the truthiness of the function reference, restoring the intended iPad exclusion from Mac detection.

🤖 Prompt for AI agents
In frontend/pages/hosts/details/DeviceUserPage/helpers.ts around line 66, review and complete this code-review fix: isMac() compares a function reference to a boolean instead of calling isIPad().
What the draft fix changed: In `isMac` (frontend/pages/hosts/details/DeviceUserPage/helpers.ts), changed `!isIPad` to `!isIPad(navigator)` so the function is actually invoked with the current `navigator` argument instead of testing the truthiness of the function reference, restoring the intended iPad exclusion from Mac detection.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

🟠 46. isIosLockedWithLocationAvail compares hostGeolocation to null with strict inequality, which is always true for optional undefined propfrontend/pages/hosts/details/modals/LocationModal/LocationModal.tsx:137
Changed the isIosLockedWithLocationAvail computation in LocationModal component to use Boolean(hostGeolocation) instead of `hostGeoloca

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants