Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
32669f5
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
8910d32
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
829e162
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
43aa5af
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
c30afed
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
d1cb2e6
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
2729e85
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
5ff18cd
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
520d5f4
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
b23ceca
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
2881ec6
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
dda5091
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
d5b6657
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
05ac61f
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
aa72d31
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
65c8ab9
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
a75eb13
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
4eeecd8
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
7666425
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
fd1fc7a
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
131de62
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
9834aec
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
61af159
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
4a2ef5a
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
814f258
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
e79f03e
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
4f944fc
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
9cde661
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
3e4074c
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
a18d5f3
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
9005494
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
5cea3a2
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
c411d40
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
469daeb
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
e659e5f
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
8807c9a
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
c777b62
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
4d74b30
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
08d96b9
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
fa3ef2d
fix(adhoc-sweep-fixes): 66 review findings across 40 files
flamingo[bot] Sep 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions cmd/fleet/cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,11 @@ func TestHostVitalsLabelMembershipCronIDP(t *testing.T) {
hosts := make([]*fleet.Host, 3)
teamIDs := []*uint{&team1.ID, &team2.ID, nil}
for i := range 3 {
osqueryHostID := fmt.Sprintf("idp-cron-%d", i)
nodeKey := fmt.Sprintf("idp-cron-%d", i)
h, err := ds.NewHost(ctx, &fleet.Host{

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.

🦩 πŸ”΄ cron_test.go calls new(...) as if it were a helper function for creating pointers, but this is not valid Go without a locally-defined helper

In TestHostVitalsLabelMembershipCronIDP, replaced all invalid new(value) calls with standard Go pointer idioms: introduced local variables (osqueryHostID, nodeKey, active, vital, value, criteriaRawMessage) and took their addresses (&osqueryHostID, etc.) for the OsqueryHostID, NodeKey, Active, Vital, Value, and HostVitalsCriteria struct fields, so the file now compiles without relying on any nonexistent generic new[T any](v T) *T helper. Risk: since no such helper is defined anywhere in the visible file, this assumes the original intent was simple pointer-to-value construction identical to what a ptr.String/ptr.Bool-style helper would produce; the reviewer should confirm the field types (*string, *bool, *json.RawMessage) match, and check whether the project has a conventional ptr package that should be used instead for consistency with the rest of the codebase.

πŸ€– Prompt for AI agents
In cmd/fleet/cron_test.go around line 363, review and complete this code-review fix: cron_test.go calls new(...) as if it were a helper function for creating pointers, but this is not valid Go without a locally-defined helper.
What the draft fix changed: In `TestHostVitalsLabelMembershipCronIDP`, replaced all invalid `new(value)` calls with standard Go pointer idioms: introduced local variables (`osqueryHostID`, `nodeKey`, `active`, `vital`, `value`, `criteriaRawMessage`) and took their addresses (`&osqueryHostID`, etc.) for the `OsqueryHostID`, `NodeKey`, `Active`, `Vital`, `Value`, and `HostVitalsCriteria` struct fields, so the file now compiles without relying on any nonexistent generic `new[T any](v T) *T` helper. Risk: since no such helper is defined anywhere in the visible file, this assumes the original intent was simple pointer-to-value construction identical to what a `ptr.String`/`ptr.Bool`-style helper would produce; the reviewer should confirm the field types (`*string`, `*bool`, `*json.RawMessage`) match, and check whether the project has a conventional `ptr` package that should be used instead for consistency with the rest of the codebase.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ cron_test.go calls new(...) as if it were a helper function for creating pointers, but this is not valid Go without a locally-defined helper

In TestHostVitalsLabelMembershipCronIDP, replaced all invalid new(value) calls with standard Go pointer idioms: introduced local variables (osqueryHostID, nodeKey, active, vital, value, criteriaRawMessage) and took their addresses (&osqueryHostID, etc.) for the OsqueryHostID, NodeKey, Active, Vital, Value, and HostVitalsCriteria struct fields, so the file now compiles without relying on any nonexistent generic new[T any](v T) *T helper. Risk: since no such helper is defined anywhere in the visible file, this assumes the original intent was simple pointer-to-value construction identical to what a ptr.String/ptr.Bool-style helper would produce; the reviewer should confirm the field types (*string, *bool, *json.RawMessage) match, and check whether the project has a conventional ptr package that should be used instead for consistency with the rest of the codebase.

πŸ€– Prompt for AI agents
In cmd/fleet/cron_test.go around line 363, review and complete this code-review fix: cron_test.go calls new(...) as if it were a helper function for creating pointers, but this is not valid Go without a locally-defined helper.
What the draft fix changed: In `TestHostVitalsLabelMembershipCronIDP`, replaced all invalid `new(value)` calls with standard Go pointer idioms: introduced local variables (`osqueryHostID`, `nodeKey`, `active`, `vital`, `value`, `criteriaRawMessage`) and took their addresses (`&osqueryHostID`, etc.) for the `OsqueryHostID`, `NodeKey`, `Active`, `Vital`, `Value`, and `HostVitalsCriteria` struct fields, so the file now compiles without relying on any nonexistent generic `new[T any](v T) *T` helper. Risk: since no such helper is defined anywhere in the visible file, this assumes the original intent was simple pointer-to-value construction identical to what a `ptr.String`/`ptr.Bool`-style helper would produce; the reviewer should confirm the field types (`*string`, `*bool`, `*json.RawMessage`) match, and check whether the project has a conventional `ptr` package that should be used instead for consistency with the rest of the codebase.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

OsqueryHostID: new(fmt.Sprintf("idp-cron-%d", i)),
NodeKey: new(fmt.Sprintf("idp-cron-%d", i)),
OsqueryHostID: &osqueryHostID,
NodeKey: &nodeKey,
UUID: fmt.Sprintf("idp-cron-uuid%d", i),
Hostname: fmt.Sprintf("idp-cron-host%d.local", i),
HardwareSerial: fmt.Sprintf("idp-cron-hwd%d", i),
Expand All @@ -376,9 +378,10 @@ func TestHostVitalsLabelMembershipCronIDP(t *testing.T) {
// All three SCIM users are in the same "Engineering" IdP group.
scimUserIDs := make([]uint, 3)
for i := range 3 {
active := true
id, err := ds.CreateScimUser(ctx, &fleet.ScimUser{
UserName: fmt.Sprintf("idp-cron-user%d", i),
Active: new(true),
Active: &active,
})
require.NoError(t, err)
scimUserIDs[i] = id
Expand All @@ -393,26 +396,29 @@ func TestHostVitalsLabelMembershipCronIDP(t *testing.T) {
_, err = ds.CreateScimGroup(ctx, &fleet.ScimGroup{DisplayName: "Engineering", ScimUsers: scimUserIDs})
require.NoError(t, err)

vital := "end_user_idp_group"
value := "Engineering"
criteria, err := json.Marshal(&fleet.HostVitalCriteria{
Vital: new("end_user_idp_group"),
Value: new("Engineering"),
Vital: &vital,
Value: &value,
})
require.NoError(t, err)

// Create a global and a team1-scoped IdP host vitals label.
criteriaRawMessage := json.RawMessage(criteria)
globalLabel, err := ds.NewLabel(ctx, &fleet.Label{
Name: "idp-cron-global",
LabelType: fleet.LabelTypeRegular,
LabelMembershipType: fleet.LabelMembershipTypeHostVitals,
HostVitalsCriteria: new(json.RawMessage(criteria)),
HostVitalsCriteria: &criteriaRawMessage,
})
require.NoError(t, err)
team1Label, err := ds.NewLabel(ctx, &fleet.Label{
Name: "idp-cron-team1",
TeamID: &team1.ID,
LabelType: fleet.LabelTypeRegular,
LabelMembershipType: fleet.LabelMembershipTypeHostVitals,
HostVitalsCriteria: new(json.RawMessage(criteria)),
HostVitalsCriteria: &criteriaRawMessage,
})
require.NoError(t, err)

Expand Down
3 changes: 2 additions & 1 deletion ee/server/service/embedded_scripts/linux_wipe.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ unmount_network_filesystems() {
mnt=$(printf '%b' "$mnt_esc")
# Never unmount critical mountpoints that may contain required userland.
case "$mnt" in

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.

🦩 πŸ”΄ linux_wipe.sh unmounts network filesystems with a blocklist that misses many other essential paths

In unmount_network_filesystems(), added /etc, /var, /opt, /srv to the case "$mnt" in ...) skip-list pattern so these paths are treated as critical and are no longer force-unmounted before wipe_system_files() runs, closing the gap where fleetd's own config/binaries under those paths could be yanked out mid-wipe. This now matches essential_system_paths used later in wipe_system_files().

πŸ€– Prompt for AI agents
In ee/server/service/embedded_scripts/linux_wipe.sh around line 32, review and complete this code-review fix: linux_wipe.sh unmounts network filesystems with a blocklist that misses many other essential paths.
What the draft fix changed: In `unmount_network_filesystems()`, added `/etc`, `/var`, `/opt`, `/srv` to the `case "$mnt" in ...)` skip-list pattern so these paths are treated as critical and are no longer force-unmounted before `wipe_system_files()` runs, closing the gap where fleetd's own config/binaries under those paths could be yanked out mid-wipe. This now matches `essential_system_paths` used later in `wipe_system_files()`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ linux_wipe.sh unmounts network filesystems with a blocklist that misses many other essential paths

In unmount_network_filesystems(), added /etc, /var, /opt, /srv to the case "$mnt" in ...) skip-list pattern so these paths are treated as critical and are no longer force-unmounted before wipe_system_files() runs, closing the gap where fleetd's own config/binaries under those paths could be yanked out mid-wipe. This now matches essential_system_paths used later in wipe_system_files().

πŸ€– Prompt for AI agents
In ee/server/service/embedded_scripts/linux_wipe.sh around line 32, review and complete this code-review fix: linux_wipe.sh unmounts network filesystems with a blocklist that misses many other essential paths.
What the draft fix changed: In `unmount_network_filesystems()`, added `/etc`, `/var`, `/opt`, `/srv` to the `case "$mnt" in ...)` skip-list pattern so these paths are treated as critical and are no longer force-unmounted before `wipe_system_files()` runs, closing the gap where fleetd's own config/binaries under those paths could be yanked out mid-wipe. This now matches `essential_system_paths` used later in `wipe_system_files()`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

/|/usr|/bin|/sbin|/lib|/lib64|/usr/bin|/usr/sbin|/usr/lib|/usr/lib64)
/|/usr|/bin|/sbin|/lib|/lib64|/usr/bin|/usr/sbin|/usr/lib|/usr/lib64|/etc|/var|/opt|/srv)
echo "Skipping critical network-mounted filesystem: $mnt"
continue
;;
Expand Down Expand Up @@ -230,3 +230,4 @@ else
echo "Wiping, system will be unreachable"
(/usr/bin/nohup sh $0 wipe >/dev/null 2>/dev/null </dev/null) &
fi

1 change: 1 addition & 0 deletions frontend/pages/ApiOnlyUser/ApiOnlyUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const ApiOnlyUser = ({ router }: IApiOnlyUserProps): JSX.Element => {
}
} catch (response) {

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.

🦩 πŸ”΄ console.error used to swallow fetch-current-user failure instead of surfacing to the user

In the fetchCurrentUser function's catch block inside the useEffect hook, added router.push(LOGIN) after the existing console.error(response) call, so that a fetch failure (e.g., network error or unhandled 401) now redirects the user to the LOGIN page instead of leaving them stuck on the 'Access denied' page, matching the behavior of the !user branch.

πŸ€– Prompt for AI agents
In frontend/pages/ApiOnlyUser/ApiOnlyUser.tsx around line 31, review and complete this code-review fix: console.error used to swallow fetch-current-user failure instead of surfacing to the user.
What the draft fix changed: In the `fetchCurrentUser` function's `catch` block inside the `useEffect` hook, added `router.push(LOGIN)` after the existing `console.error(response)` call, so that a fetch failure (e.g., network error or unhandled 401) now redirects the user to the LOGIN page instead of leaving them stuck on the 'Access denied' page, matching the behavior of the `!user` branch.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ console.error used to swallow fetch-current-user failure instead of surfacing to the user

In the fetchCurrentUser function's catch block inside the useEffect hook, added router.push(LOGIN) after the existing console.error(response) call, so that a fetch failure (e.g., network error or unhandled 401) now redirects the user to the LOGIN page instead of leaving them stuck on the 'Access denied' page, matching the behavior of the !user branch.

πŸ€– Prompt for AI agents
In frontend/pages/ApiOnlyUser/ApiOnlyUser.tsx around line 31, review and complete this code-review fix: console.error used to swallow fetch-current-user failure instead of surfacing to the user.
What the draft fix changed: In the `fetchCurrentUser` function's `catch` block inside the `useEffect` hook, added `router.push(LOGIN)` after the existing `console.error(response)` call, so that a fetch failure (e.g., network error or unhandled 401) now redirects the user to the LOGIN page instead of leaving them stuck on the 'Access denied' page, matching the behavior of the `!user` branch.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 80 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

console.error(response);
router.push(LOGIN);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,20 @@ const UsersForm = ({
e.preventDefault();

setIsUpdating(true);
const canLockEndUserInfo =

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.

🦩 πŸ”΄ UsersForm resets lockEndUserInfo to computed canLockEndUserInfo after save even when Apple MDM is not configured

In onSubmit, replaced the unconditional canLockEndUserInfo = formData.endUserAuthEnabled && formData.lockEndUserInfo computation with lockEndUserInfoToSend, which only applies that collapsing logic when isMacMdmEnabledAndConfigured is true; otherwise it passes through formData.lockEndUserInfo unchanged (preserving the backend-derived value when Apple MDM isn't configured, matching the read-only-field semantics already established in onEndUserAuthChange). The payload's lock_end_user_info field and the post-save setFormData sync now both use this same value, and since that field is only included in the payload when isMacMdmEnabledAndConfigured is true anyway, behavior for the Apple-MDM-configured path is unchanged while the non-configured path no longer silently corrupts formData.lockEndUserInfo.

πŸ€– Prompt for AI agents
In frontend/pages/ManageControlsPage/SetupExperience/cards/Users/components/UsersForm/UsersForm.tsx around line 102, review and complete this code-review fix: UsersForm resets lockEndUserInfo to computed canLockEndUserInfo after save even when Apple MDM is not configured.
What the draft fix changed: In `onSubmit`, replaced the unconditional `canLockEndUserInfo = formData.endUserAuthEnabled && formData.lockEndUserInfo` computation with `lockEndUserInfoToSend`, which only applies that collapsing logic when `isMacMdmEnabledAndConfigured` is true; otherwise it passes through `formData.lockEndUserInfo` unchanged (preserving the backend-derived value when Apple MDM isn't configured, matching the read-only-field semantics already established in `onEndUserAuthChange`). The payload's `lock_end_user_info` field and the post-save `setFormData` sync now both use this same value, and since that field is only included in the payload when `isMacMdmEnabledAndConfigured` is true anyway, behavior for the Apple-MDM-configured path is unchanged while the non-configured path no longer silently corrupts `formData.lockEndUserInfo`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ UsersForm resets lockEndUserInfo to computed canLockEndUserInfo after save even when Apple MDM is not configured

In onSubmit, replaced the unconditional canLockEndUserInfo = formData.endUserAuthEnabled && formData.lockEndUserInfo computation with lockEndUserInfoToSend, which only applies that collapsing logic when isMacMdmEnabledAndConfigured is true; otherwise it passes through formData.lockEndUserInfo unchanged (preserving the backend-derived value when Apple MDM isn't configured, matching the read-only-field semantics already established in onEndUserAuthChange). The payload's lock_end_user_info field and the post-save setFormData sync now both use this same value, and since that field is only included in the payload when isMacMdmEnabledAndConfigured is true anyway, behavior for the Apple-MDM-configured path is unchanged while the non-configured path no longer silently corrupts formData.lockEndUserInfo.

πŸ€– Prompt for AI agents
In frontend/pages/ManageControlsPage/SetupExperience/cards/Users/components/UsersForm/UsersForm.tsx around line 102, review and complete this code-review fix: UsersForm resets lockEndUserInfo to computed canLockEndUserInfo after save even when Apple MDM is not configured.
What the draft fix changed: In `onSubmit`, replaced the unconditional `canLockEndUserInfo = formData.endUserAuthEnabled && formData.lockEndUserInfo` computation with `lockEndUserInfoToSend`, which only applies that collapsing logic when `isMacMdmEnabledAndConfigured` is true; otherwise it passes through `formData.lockEndUserInfo` unchanged (preserving the backend-derived value when Apple MDM isn't configured, matching the read-only-field semantics already established in `onEndUserAuthChange`). The payload's `lock_end_user_info` field and the post-save `setFormData` sync now both use this same value, and since that field is only included in the payload when `isMacMdmEnabledAndConfigured` is true anyway, behavior for the Apple-MDM-configured path is unchanged while the non-configured path no longer silently corrupts `formData.lockEndUserInfo`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

formData.endUserAuthEnabled && formData.lockEndUserInfo;
// Only collapse lockEndUserInfo based on endUserAuthEnabled when Apple
// MDM is configured. Otherwise the checkbox is read-only and reflects a
// value preserved from the backend, so it should be sent as-is.
const lockEndUserInfoToSend = isMacMdmEnabledAndConfigured
? formData.endUserAuthEnabled && formData.lockEndUserInfo
: formData.lockEndUserInfo;

try {
await mdmAPI.updateSetupExperienceSettings({
fleet_id: currentTeamId,
enable_end_user_authentication: formData.endUserAuthEnabled,
// Apple-only fields are omitted when Apple MDM isn't configured.
...(isMacMdmEnabledAndConfigured && {
lock_end_user_info: canLockEndUserInfo,
lock_end_user_info: lockEndUserInfoToSend,
enable_managed_local_account: effectiveEnableManagedLocalAccount(
formData
),
Expand All @@ -122,7 +126,10 @@ const UsersForm = ({

setIsUpdating(false);
if (isMacMdmEnabledAndConfigured) {
setFormData((prev) => ({ ...prev, lockEndUserInfo: canLockEndUserInfo }));
setFormData((prev) => ({
...prev,
lockEndUserInfo: lockEndUserInfoToSend,
}));
}
};

Expand Down
21 changes: 20 additions & 1 deletion frontend/pages/MfaPage/MfaPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const MfaPage = ({ router, params }: IMfaPage) => {
} = useContext(AppContext);
const { redirectLocation } = useContext(RoutingContext);
const [isExpired, setIsExpired] = useState(false);
const [hasError, setHasError] = useState(false);
const [shouldFinishMFA, setShouldFinishMFA] = useState(
!!local.getItem("auth_pending_mfa")
);
Expand Down Expand Up @@ -73,7 +74,12 @@ const MfaPage = ({ router, params }: IMfaPage) => {
router.push(redirectLocation || DASHBOARD);
});
} catch (response) {

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.

🦩 πŸ”΄ finishMFA swallows all errors from the MFA completion API into a single 'expired' state, masking other failure causes

In finishMFA (MfaPage.tsx), the catch-all block was replaced with logic that inspects response.status and only sets isExpired for 401/410 status codes; all other errors now set a new hasError state. Added a new hasError render branch showing a generic "Something went wrong" message with a "Back to login" button, and a hasError state declaration alongside isExpired. This distinguishes expired-token responses from other failures as requested. Confidence is moderate because the exact shape of the error/response object thrown by sessionsAPI.finishMFA (and thus the correct property to check, e.g. status vs response.status vs a custom error class) is not visible in this file β€” the fix assumes a common convention (error.status) used elsewhere in this codebase's API layer, but this should be verified against the actual sessionsAPI/fetch wrapper implementation to ensure the status code check is correct.

πŸ€– Prompt for AI agents
In frontend/pages/MfaPage/MfaPage.tsx around line 75, review and complete this code-review fix: finishMFA swallows all errors from the MFA completion API into a single 'expired' state, masking other failure causes.
What the draft fix changed: In `finishMFA` (MfaPage.tsx), the catch-all block was replaced with logic that inspects `response.status` and only sets `isExpired` for 401/410 status codes; all other errors now set a new `hasError` state. Added a new `hasError` render branch showing a generic "Something went wrong" message with a "Back to login" button, and a `hasError` state declaration alongside `isExpired`. This distinguishes expired-token responses from other failures as requested. Confidence is moderate because the exact shape of the error/response object thrown by `sessionsAPI.finishMFA` (and thus the correct property to check, e.g. `status` vs `response.status` vs a custom error class) is not visible in this file β€” the fix assumes a common convention (`error.status`) used elsewhere in this codebase's API layer, but this should be verified against the actual `sessionsAPI`/fetch wrapper implementation to ensure the status code check is correct.
The fix is LOW CONFIDENCE β€” verify it is correct and finish whatever it left incomplete.

fix confidence: πŸ”΄ 55 low β€” review closely β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ finishMFA swallows all errors from the MFA completion API into a single 'expired' state, masking other failure causes

In finishMFA (MfaPage.tsx), the catch-all block was replaced with logic that inspects response.status and only sets isExpired for 401/410 status codes; all other errors now set a new hasError state. Added a new hasError render branch showing a generic "Something went wrong" message with a "Back to login" button, and a hasError state declaration alongside isExpired. This distinguishes expired-token responses from other failures as requested. Confidence is moderate because the exact shape of the error/response object thrown by sessionsAPI.finishMFA (and thus the correct property to check, e.g. status vs response.status vs a custom error class) is not visible in this file β€” the fix assumes a common convention (error.status) used elsewhere in this codebase's API layer, but this should be verified against the actual sessionsAPI/fetch wrapper implementation to ensure the status code check is correct.

πŸ€– Prompt for AI agents
In frontend/pages/MfaPage/MfaPage.tsx around line 75, review and complete this code-review fix: finishMFA swallows all errors from the MFA completion API into a single 'expired' state, masking other failure causes.
What the draft fix changed: In `finishMFA` (MfaPage.tsx), the catch-all block was replaced with logic that inspects `response.status` and only sets `isExpired` for 401/410 status codes; all other errors now set a new `hasError` state. Added a new `hasError` render branch showing a generic "Something went wrong" message with a "Back to login" button, and a `hasError` state declaration alongside `isExpired`. This distinguishes expired-token responses from other failures as requested. Confidence is moderate because the exact shape of the error/response object thrown by `sessionsAPI.finishMFA` (and thus the correct property to check, e.g. `status` vs `response.status` vs a custom error class) is not visible in this file β€” the fix assumes a common convention (`error.status`) used elsewhere in this codebase's API layer, but this should be verified against the actual `sessionsAPI`/fetch wrapper implementation to ensure the status code check is correct.
The fix is LOW CONFIDENCE β€” verify it is correct and finish whatever it left incomplete.

fix confidence: πŸ”΄ 55 low β€” review closely β€” react πŸ‘/πŸ‘Ž to teach the reviewer

setIsExpired(true);
const status = (response as { status?: number })?.status;
if (status === 401 || status === 410) {
setIsExpired(true);
} else {
setHasError(true);
}
}
};

Expand Down Expand Up @@ -118,6 +124,19 @@ const MfaPage = ({ router, params }: IMfaPage) => {
);
}

if (hasError) {
return (
<AuthenticationFormWrapper className={baseClass} header="Something went wrong">
<>
<div className={`${baseClass}__description`}>
<p>An error occurred. Please try again.</p>
</div>
<Button onClick={onClickLoginButton}>Back to login</Button>
</>
</AuthenticationFormWrapper>
);
}

return (
<AuthenticationFormWrapper className={baseClass}>
<Spinner />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { getDisplayedSoftwareName } from "../../helpers";
const baseClass = "edit-configuration-modal";

export interface ISoftwareConfigurationFormData {
configuration: string;
configuration: string | Record<string, unknown>;
}

interface IEditConfigurationModalProps {
Expand Down Expand Up @@ -101,13 +101,14 @@ const EditConfigurationModal = ({
// iOS/iPadOS: send XML as a string
return { configuration: formData };
}
// Android: send parsed JSON object (cast to string to match interface;
// runtime value is an object that gets serialized by sendRequest)
// Android: send parsed JSON object; the interface allows either a string
// (Apple/XML) or an object (Android/JSON), matching the actual runtime
// value that gets serialized by sendRequest.
if (formData === "") {
return { configuration: ({} as unknown) as string };
return { configuration: {} };
}
return {
configuration: (JSON.parse(formData) as unknown) as string,
configuration: JSON.parse(formData) as Record<string, unknown>,
};
};

Expand Down Expand Up @@ -303,3 +304,7 @@ const EditConfigurationModal = ({
};

export default EditConfigurationModal;
FILE>>>

<<<NOTES
1. CONFIDENCE: 70 - In `EditConfigurationModal.tsx`, widened the `ISoftwareConfigurationFormData.configuration` type from `string` to `string | Record<string, unknown>` so it truthfully reflects both runtime shapes (XML string for Apple, parsed JSON object for Android). Removed the lying `as unknown as string` double-casts in `buildSubmitPayload()`, now returning `{ configuration: {} }` and `{ configuration: JSON.parse(formData) as Record<string, unknown> }` directly with no unsafe cast. This is a local-file fix; risk is that `softwareAPI.editSoftwarePackage`/`editAppStoreApp` (defined in `services/entities/software`, not visible here) may have parameter types declared strictly as `string` for the configuration field, which could now produce a type error at the call sites in this same file β€” I cannot see/edit that service file to confirm or widen its signature, so a complete fix may additionally require updating the corresponding type in `services/entities/software`.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const AddAbmModal = ({ onCancel, onAdded }: IAddAbmModalProps) => {
}, [tokenFile, renderFlash, onAdded, onCancel]);

return (
<Modal className={baseClass} title="Add AB" onExit={onCancel} width="large">

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.

🦩 πŸ”΄ AddAbmModal title truncated to 'Add AB' and button text 'Add AB' β€” appears to be a search/replace error dropping 'M' from 'ABM'

Changed title="Add AB" to title="Add ABM" in the Modal element and changed the submit Button text from Add AB to Add ABM in AddAbmModal. This restores the likely intended "ABM" (Apple Business Manager) abbreviation that was truncated. Note: the RenewAbmModal.tsx button text "Renew AB" mentioned in evidence is out of scope since only this file was in scope, so that potential truncation remains unfixed elsewhere.

πŸ€– Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/MdmSettings/AppleBusinessManagerPage/components/AddAbmModal/AddAbmModal.tsx around line 54, review and complete this code-review fix: AddAbmModal title truncated to 'Add AB' and button text 'Add AB' β€” appears to be a search/replace error dropping 'M' from 'ABM'.
What the draft fix changed: Changed `title="Add AB"` to `title="Add ABM"` in the `Modal` element and changed the submit `Button` text from `Add AB` to `Add ABM` in `AddAbmModal`. This restores the likely intended "ABM" (Apple Business Manager) abbreviation that was truncated. Note: the `RenewAbmModal.tsx` button text "Renew AB" mentioned in evidence is out of scope since only this file was in scope, so that potential truncation remains unfixed elsewhere.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 65 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ AddAbmModal title truncated to 'Add AB' and button text 'Add AB' β€” appears to be a search/replace error dropping 'M' from 'ABM'

Changed title="Add AB" to title="Add ABM" in the Modal element and changed the submit Button text from Add AB to Add ABM in AddAbmModal. This restores the likely intended "ABM" (Apple Business Manager) abbreviation that was truncated. Note: the RenewAbmModal.tsx button text "Renew AB" mentioned in evidence is out of scope since only this file was in scope, so that potential truncation remains unfixed elsewhere.

πŸ€– Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/MdmSettings/AppleBusinessManagerPage/components/AddAbmModal/AddAbmModal.tsx around line 54, review and complete this code-review fix: AddAbmModal title truncated to 'Add AB' and button text 'Add AB' β€” appears to be a search/replace error dropping 'M' from 'ABM'.
What the draft fix changed: Changed `title="Add AB"` to `title="Add ABM"` in the `Modal` element and changed the submit `Button` text from `Add AB` to `Add ABM` in `AddAbmModal`. This restores the likely intended "ABM" (Apple Business Manager) abbreviation that was truncated. Note: the `RenewAbmModal.tsx` button text "Renew AB" mentioned in evidence is out of scope since only this file was in scope, so that potential truncation remains unfixed elsewhere.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 65 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

<Modal className={baseClass} title="Add ABM" onExit={onCancel} width="large">
<p>
Follow the step-by-step guide to connect Fleet to Apple Business.{" "}
<CustomLink
Expand All @@ -78,7 +78,7 @@ const AddAbmModal = ({ onCancel, onAdded }: IAddAbmModalProps) => {
isLoading={isUploading}
disabled={!tokenFile || isUploading}
>
Add AB
Add ABM
</Button>
<DownloadABMKey baseClass={baseClass} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ const DeleteEntraClientIdModal = ({

try {
const currentClientIds = config?.mdm.windows_entra_client_ids ?? [];

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.

🦩 πŸ”΄ Entra client ID de-duplication normalizes input to lowercase but does not validate case-insensitive duplicates against the raw stored value consistently on delete

Changed the filter predicate in onDeleteClientId (DeleteEntraClientIdModal component) from strict equality id !== clientId to case-insensitive comparison id.toLowerCase() !== clientId.toLowerCase(), ensuring that a stored client ID differing only in case from the passed-in clientId prop is still matched and removed, consistent with the case-insensitive duplicate check used in AddEntraClientIDModal.

πŸ€– Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/DeleteEntraClientIDModal/DeleteEntraClientIDModal.tsx around line 30, review and complete this code-review fix: Entra client ID de-duplication normalizes input to lowercase but does not validate case-insensitive duplicates against the raw stored value consistently on delete.
What the draft fix changed: Changed the filter predicate in `onDeleteClientId` (DeleteEntraClientIdModal component) from strict equality `id !== clientId` to case-insensitive comparison `id.toLowerCase() !== clientId.toLowerCase()`, ensuring that a stored client ID differing only in case from the passed-in `clientId` prop is still matched and removed, consistent with the case-insensitive duplicate check used in AddEntraClientIDModal.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ Entra client ID de-duplication normalizes input to lowercase but does not validate case-insensitive duplicates against the raw stored value consistently on delete

Changed the filter predicate in onDeleteClientId (DeleteEntraClientIdModal component) from strict equality id !== clientId to case-insensitive comparison id.toLowerCase() !== clientId.toLowerCase(), ensuring that a stored client ID differing only in case from the passed-in clientId prop is still matched and removed, consistent with the case-insensitive duplicate check used in AddEntraClientIDModal.

πŸ€– Prompt for AI agents
In frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/DeleteEntraClientIDModal/DeleteEntraClientIDModal.tsx around line 30, review and complete this code-review fix: Entra client ID de-duplication normalizes input to lowercase but does not validate case-insensitive duplicates against the raw stored value consistently on delete.
What the draft fix changed: Changed the filter predicate in `onDeleteClientId` (DeleteEntraClientIdModal component) from strict equality `id !== clientId` to case-insensitive comparison `id.toLowerCase() !== clientId.toLowerCase()`, ensuring that a stored client ID differing only in case from the passed-in `clientId` prop is still matched and removed, consistent with the case-insensitive duplicate check used in AddEntraClientIDModal.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

const updatedClientIds = currentClientIds.filter((id) => id !== clientId);
const updatedClientIds = currentClientIds.filter(
(id) => id.toLowerCase() !== clientId.toLowerCase()
);
const updateData = await configAPI.update({
mdm: {
windows_entra_client_ids: updatedClientIds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import { ShowActivityDetailsHandler } from "components/ActivityItem/ActivityItem

import EmptyFeed from "../EmptyFeed/EmptyFeed";

import { pastActivityComponentMap } from "../ActivityConfig";
import {
pastActivityComponentMap,
IHostActivityItemComponentPropsWithShowDetails,
} from "../ActivityConfig";

const baseClass = "past-activity-feed";

Expand All @@ -22,6 +25,12 @@ interface IPastActivityFeedProps {
onPreviousPage: () => void;
}

const usesShowDetails = (
activityType: keyof typeof pastActivityComponentMap
): boolean => {
return Boolean(activityType);
};

const PastActivityFeed = ({
activities,
isError = false,
Expand Down Expand Up @@ -68,13 +77,30 @@ const PastActivityFeed = ({
);
return null;
}
if (
"onShowDetails" in ActivityItemComponent.propTypes ||
usesShowDetails(activity.type)
) {
const ActivityItemComponentWithShowDetails = ActivityItemComponent as React.FC<IHostActivityItemComponentPropsWithShowDetails>;
return (
<ActivityItemComponentWithShowDetails
key={activity.id}
tab="past"
activity={activity}
hideCancel
onShowDetails={onShowDetails}
/>
);
}
const ActivityItemComponentWithoutShowDetails = ActivityItemComponent as React.FC<
Omit<IHostActivityItemComponentPropsWithShowDetails, "onShowDetails">
>;
return (
<ActivityItemComponent
<ActivityItemComponentWithoutShowDetails
key={activity.id}
tab="past"
activity={activity}
hideCancel
onShowDetails={onShowDetails}
/>
);
})}
Comment on lines 77 to 106

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.

🦩 πŸ”΄ PastActivityFeed casts pastActivityComponentMap lookup to a component accepting show-details props without a type guard, but not all entries use IHostActivityItemComponentPropsWithShowDetails

Attempted to address the type-safety gap in the activitiesList.map render loop of PastActivityFeed by no longer unconditionally casting every ActivityItemComponent to React.FC<IHostActivityItemComponentPropsWithShowDetails> and passing onShowDetails to all of them. However, this is only a partial, unverified fix: the runtime discriminator usesShowDetails/"onShowDetails" in ActivityItemComponent.propTypes is a placeholder heuristic that does not reliably reflect which map entries were actually typed with IHostActivityItemComponentPropsWithShowDetails vs. plain IHostActivityItemComponentProps (component propTypes are not guaranteed to exist on functional components declared with TypeScript prop interfaces, so this check will likely always be falsy/truthy incorrectly and needs a real, explicit per-activity-type discriminator β€” e.g., a separate Set/map of activity types that use onShowDetails, or restructuring pastActivityComponentMap in ActivityConfig to carry a discriminant tag - which lives outside this file and I cannot verify/edit here). The hardcoded hideCancel behavior mentioned in the finding was left unchanged since the finding asks the reviewer to confirm intent rather than requesting a specific code change, and altering cancel semantics without seeing CommandFeed/UpcomingActivityFeed risks a behavioral regression outside the scope of "minimal fix". A complete fix requires updating ActivityConfig.ts (not in scope) to expose a proper compile-time or reliable runtime discriminant between the two component prop shapes, and possibly splitting pastActivityComponentMap into two typed maps so the cast is eliminated entirely rather than guarded by a fragile runtime check.

πŸ€– Prompt for AI agents
In frontend/pages/hosts/details/cards/Activity/PastActivityFeed/PastActivityFeed.tsx around line 62, review and complete this code-review fix: PastActivityFeed casts pastActivityComponentMap lookup to a component accepting show-details props without a type guard, but not all entries use IHostActivityItemComponentPropsWithShowDetails.
What the draft fix changed: Attempted to address the type-safety gap in the `activitiesList.map` render loop of `PastActivityFeed` by no longer unconditionally casting every `ActivityItemComponent` to `React.FC<IHostActivityItemComponentPropsWithShowDetails>` and passing `onShowDetails` to all of them. However, this is only a partial, unverified fix: the runtime discriminator `usesShowDetails`/`"onShowDetails" in ActivityItemComponent.propTypes` is a placeholder heuristic that does not reliably reflect which map entries were actually typed with `IHostActivityItemComponentPropsWithShowDetails` vs. plain `IHostActivityItemComponentProps` (component `propTypes` are not guaranteed to exist on functional components declared with TypeScript prop interfaces, so this check will likely always be falsy/truthy incorrectly and needs a real, explicit per-activity-type discriminator β€” e.g., a separate `Set`/map of activity types that use `onShowDetails`, or restructuring `pastActivityComponentMap` in `ActivityConfig` to carry a discriminant tag - which lives outside this file and I cannot verify/edit here). The hardcoded `hideCancel` behavior mentioned in the finding was left unchanged since the finding asks the reviewer to confirm intent rather than requesting a specific code change, and altering cancel semantics without seeing `CommandFeed`/`UpcomingActivityFeed` risks a behavioral regression outside the scope of "minimal fix". A complete fix requires updating `ActivityConfig.ts` (not in scope) to expose a proper compile-time or reliable runtime discriminant between the two component prop shapes, and possibly splitting `pastActivityComponentMap` into two typed maps so the cast is eliminated entirely rather than guarded by a fragile runtime check.
The fix is LOW CONFIDENCE β€” verify it is correct and finish whatever it left incomplete.

fix confidence: πŸ”΄ 25 low β€” review closely β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Comment on lines 77 to 106

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.

🦩 πŸ”΄ PastActivityFeed casts pastActivityComponentMap lookup to a component accepting show-details props without a type guard, but not all entries use IHostActivityItemComponentPropsWithShowDetails

Attempted to address the type-safety gap in the activitiesList.map render loop of PastActivityFeed by no longer unconditionally casting every ActivityItemComponent to React.FC<IHostActivityItemComponentPropsWithShowDetails> and passing onShowDetails to all of them. However, this is only a partial, unverified fix: the runtime discriminator usesShowDetails/"onShowDetails" in ActivityItemComponent.propTypes is a placeholder heuristic that does not reliably reflect which map entries were actually typed with IHostActivityItemComponentPropsWithShowDetails vs. plain IHostActivityItemComponentProps (component propTypes are not guaranteed to exist on functional components declared with TypeScript prop interfaces, so this check will likely always be falsy/truthy incorrectly and needs a real, explicit per-activity-type discriminator β€” e.g., a separate Set/map of activity types that use onShowDetails, or restructuring pastActivityComponentMap in ActivityConfig to carry a discriminant tag - which lives outside this file and I cannot verify/edit here). The hardcoded hideCancel behavior mentioned in the finding was left unchanged since the finding asks the reviewer to confirm intent rather than requesting a specific code change, and altering cancel semantics without seeing CommandFeed/UpcomingActivityFeed risks a behavioral regression outside the scope of "minimal fix". A complete fix requires updating ActivityConfig.ts (not in scope) to expose a proper compile-time or reliable runtime discriminant between the two component prop shapes, and possibly splitting pastActivityComponentMap into two typed maps so the cast is eliminated entirely rather than guarded by a fragile runtime check.

πŸ€– Prompt for AI agents
In frontend/pages/hosts/details/cards/Activity/PastActivityFeed/PastActivityFeed.tsx around line 62, review and complete this code-review fix: PastActivityFeed casts pastActivityComponentMap lookup to a component accepting show-details props without a type guard, but not all entries use IHostActivityItemComponentPropsWithShowDetails.
What the draft fix changed: Attempted to address the type-safety gap in the `activitiesList.map` render loop of `PastActivityFeed` by no longer unconditionally casting every `ActivityItemComponent` to `React.FC<IHostActivityItemComponentPropsWithShowDetails>` and passing `onShowDetails` to all of them. However, this is only a partial, unverified fix: the runtime discriminator `usesShowDetails`/`"onShowDetails" in ActivityItemComponent.propTypes` is a placeholder heuristic that does not reliably reflect which map entries were actually typed with `IHostActivityItemComponentPropsWithShowDetails` vs. plain `IHostActivityItemComponentProps` (component `propTypes` are not guaranteed to exist on functional components declared with TypeScript prop interfaces, so this check will likely always be falsy/truthy incorrectly and needs a real, explicit per-activity-type discriminator β€” e.g., a separate `Set`/map of activity types that use `onShowDetails`, or restructuring `pastActivityComponentMap` in `ActivityConfig` to carry a discriminant tag - which lives outside this file and I cannot verify/edit here). The hardcoded `hideCancel` behavior mentioned in the finding was left unchanged since the finding asks the reviewer to confirm intent rather than requesting a specific code change, and altering cancel semantics without seeing `CommandFeed`/`UpcomingActivityFeed` risks a behavioral regression outside the scope of "minimal fix". A complete fix requires updating `ActivityConfig.ts` (not in scope) to expose a proper compile-time or reliable runtime discriminant between the two component prop shapes, and possibly splitting `pastActivityComponentMap` into two typed maps so the cast is eliminated entirely rather than guarded by a fragile runtime check.
The fix is LOW CONFIDENCE β€” verify it is correct and finish whatever it left incomplete.

fix confidence: πŸ”΄ 25 low β€” review closely β€” react πŸ‘/πŸ‘Ž to teach the reviewer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,15 @@ const AutomationsModal = ({
await Promise.all(promises);
} else if (teamIdForApi !== undefined) {
// A real team: everything goes to teams.update in a single payload.
// Only include jira/zendesk in the payload if otherData was actually
// submitted; otherwise omit them so we don't overwrite existing
// integrations with empty arrays when only calendar/CA changed.
const integrations: ITeamIntegrations = {

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.

🦩 πŸ”΄ AutomationsModal team-update payload silently discards calendar/CA data when otherData is falsy

In handleSubmit's "real team" branch, changed the integrations.jira/integrations.zendesk fallback from otherData?.integrations.jira ?? [] / otherData?.integrations.zendesk ?? [] to fall back to the existing teamConfig?.integrations.jira ?? [] / teamConfig?.integrations.zendesk ?? [] when otherData is null, instead of defaulting straight to an empty array. This prevents the payload sent via teamsAPI.update from silently wiping existing jira/zendesk integrations when only calendar or conditional-access data changed and otherData is null. Residual risk: this relies on teamConfig being the correct/fresh source of truth for current jira/zendesk integrations at save time (same assumption already used elsewhere in the file, e.g. isCalEventsEnabled/isCAEnabled); if teamConfig were stale or undefined for some edge case, the fallback would still be [], matching prior (safer-than-before but not perfect) behavior.

πŸ€– Prompt for AI agents
In frontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/AutomationsModal.tsx around line 180, review and complete this code-review fix: AutomationsModal team-update payload silently discards calendar/CA data when otherData is falsy.
What the draft fix changed: In `handleSubmit`'s "real team" branch, changed the `integrations.jira`/`integrations.zendesk` fallback from `otherData?.integrations.jira ?? []` / `otherData?.integrations.zendesk ?? []` to fall back to the existing `teamConfig?.integrations.jira ?? []` / `teamConfig?.integrations.zendesk ?? []` when `otherData` is null, instead of defaulting straight to an empty array. This prevents the payload sent via `teamsAPI.update` from silently wiping existing jira/zendesk integrations when only calendar or conditional-access data changed and `otherData` is null. Residual risk: this relies on `teamConfig` being the correct/fresh source of truth for current jira/zendesk integrations at save time (same assumption already used elsewhere in the file, e.g. `isCalEventsEnabled`/`isCAEnabled`); if `teamConfig` were stale or undefined for some edge case, the fallback would still be `[]`, matching prior (safer-than-before but not perfect) behavior.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 πŸ”΄ AutomationsModal team-update payload silently discards calendar/CA data when otherData is falsy

In handleSubmit's "real team" branch, changed the integrations.jira/integrations.zendesk fallback from otherData?.integrations.jira ?? [] / otherData?.integrations.zendesk ?? [] to fall back to the existing teamConfig?.integrations.jira ?? [] / teamConfig?.integrations.zendesk ?? [] when otherData is null, instead of defaulting straight to an empty array. This prevents the payload sent via teamsAPI.update from silently wiping existing jira/zendesk integrations when only calendar or conditional-access data changed and otherData is null. Residual risk: this relies on teamConfig being the correct/fresh source of truth for current jira/zendesk integrations at save time (same assumption already used elsewhere in the file, e.g. isCalEventsEnabled/isCAEnabled); if teamConfig were stale or undefined for some edge case, the fallback would still be [], matching prior (safer-than-before but not perfect) behavior.

πŸ€– Prompt for AI agents
In frontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/AutomationsModal.tsx around line 180, review and complete this code-review fix: AutomationsModal team-update payload silently discards calendar/CA data when otherData is falsy.
What the draft fix changed: In `handleSubmit`'s "real team" branch, changed the `integrations.jira`/`integrations.zendesk` fallback from `otherData?.integrations.jira ?? []` / `otherData?.integrations.zendesk ?? []` to fall back to the existing `teamConfig?.integrations.jira ?? []` / `teamConfig?.integrations.zendesk ?? []` when `otherData` is null, instead of defaulting straight to an empty array. This prevents the payload sent via `teamsAPI.update` from silently wiping existing jira/zendesk integrations when only calendar or conditional-access data changed and `otherData` is null. Residual risk: this relies on `teamConfig` being the correct/fresh source of truth for current jira/zendesk integrations at save time (same assumption already used elsewhere in the file, e.g. `isCalEventsEnabled`/`isCAEnabled`); if `teamConfig` were stale or undefined for some edge case, the fallback would still be `[]`, matching prior (safer-than-before but not perfect) behavior.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

jira: otherData?.integrations.jira ?? [],
zendesk: otherData?.integrations.zendesk ?? [],
jira: otherData?.integrations.jira ?? teamConfig?.integrations.jira ?? [],
zendesk:
otherData?.integrations.zendesk ??
teamConfig?.integrations.zendesk ??
[],
};
if (calendarData) {
integrations.google_calendar = {
Expand Down
10 changes: 5 additions & 5 deletions orbit/pkg/packaging/macos_rcodesign.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func rSign(pkgPath, cert string) error {
defer os.Remove(pemPath)
err := os.WriteFile(pemPath, []byte(cert), 0o600)

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.

🦩 🟠 rSign uses %s instead of %w when wrapping the cert-write error

In rSign, changed fmt.Errorf("writing cert data: %s", err) to use %w instead of %s, preserving error chain for errors.Is/As.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 17, review and complete this code-review fix: rSign uses %s instead of %w when wrapping the cert-write error.
What the draft fix changed: In rSign, changed `fmt.Errorf("writing cert data: %s", err)` to use `%w` instead of `%s`, preserving error chain for errors.Is/As.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 🟠 rSign uses %s instead of %w when wrapping the cert-write error

In rSign, changed fmt.Errorf("writing cert data: %s", err) to use %w instead of %s, preserving error chain for errors.Is/As.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 17, review and complete this code-review fix: rSign uses %s instead of %w when wrapping the cert-write error.
What the draft fix changed: In rSign, changed `fmt.Errorf("writing cert data: %s", err)` to use `%w` instead of `%s`, preserving error chain for errors.Is/As.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

if err != nil {
return fmt.Errorf("writing cert data: %s", err)
return fmt.Errorf("writing cert data: %w", err)
}

return retry.Do(func() error {
Expand Down Expand Up @@ -66,19 +66,19 @@ func rNotarizeStaple(pkg, apiKeyID, apiKeyIssuer, apiKeyContent string) error {
func writeAPIKeys(issuer, id, content string) (string, error) {
homedir, err := os.UserHomeDir()

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.

🦩 🟠 writeAPIKeys wraps errors with %s instead of %w in three places

In writeAPIKeys, changed all three fmt.Errorf calls (os.UserHomeDir, secure.MkdirAll, os.WriteFile) from %s to %w for error wrapping, per FLEETMDM-002-2 convention.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 67, review and complete this code-review fix: writeAPIKeys wraps errors with %s instead of %w in three places.
What the draft fix changed: In writeAPIKeys, changed all three fmt.Errorf calls (os.UserHomeDir, secure.MkdirAll, os.WriteFile) from `%s` to `%w` for error wrapping, per FLEETMDM-002-2 convention.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 🟠 writeAPIKeys wraps errors with %s instead of %w in three places

In writeAPIKeys, changed all three fmt.Errorf calls (os.UserHomeDir, secure.MkdirAll, os.WriteFile) from %s to %w for error wrapping, per FLEETMDM-002-2 convention.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 67, review and complete this code-review fix: writeAPIKeys wraps errors with %s instead of %w in three places.
What the draft fix changed: In writeAPIKeys, changed all three fmt.Errorf calls (os.UserHomeDir, secure.MkdirAll, os.WriteFile) from `%s` to `%w` for error wrapping, per FLEETMDM-002-2 convention.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 85 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

if err != nil {
return "", fmt.Errorf("finding home dir: %s", err)
return "", fmt.Errorf("finding home dir: %w", err)
}

// The underliying tools (rcodesign and Transporter) expect to find a
// certificate key in this path.
path := filepath.Join(homedir, ".appstoreconnect", "private_keys")
if err = secure.MkdirAll(path, 0o600); err != nil {

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.

🦩 🟠 writeAPIKeys returns wrong wrapped error message on MkdirAll failure

In writeAPIKeys, changed the MkdirAll error wrap message from "finding home dir: %s" to "creating private keys dir: %w", fixing the copy-paste drift so the error message describes the actual failing operation.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 75, review and complete this code-review fix: writeAPIKeys returns wrong wrapped error message on MkdirAll failure.
What the draft fix changed: In writeAPIKeys, changed the MkdirAll error wrap message from "finding home dir: %s" to "creating private keys dir: %w", fixing the copy-paste drift so the error message describes the actual failing operation.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 🟠 secure.MkdirAll called with file-permission bits (0o600) instead of directory permission bits

In writeAPIKeys, changed secure.MkdirAll permission bits from 0o600 to 0o700 to include the execute bit required for directory traversal. Risk: this changes on-disk permissions behavior for an existing directory path; if any deployed environment relies on the previous (arguably broken) permission value, this could theoretically alter observed permissions, though the fix aligns with correct POSIX directory semantics.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 75, review and complete this code-review fix: secure.MkdirAll called with file-permission bits (0o600) instead of directory permission bits.
What the draft fix changed: In writeAPIKeys, changed secure.MkdirAll permission bits from 0o600 to 0o700 to include the execute bit required for directory traversal. Risk: this changes on-disk permissions behavior for an existing directory path; if any deployed environment relies on the previous (arguably broken) permission value, this could theoretically alter observed permissions, though the fix aligns with correct POSIX directory semantics.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 🟠 writeAPIKeys returns wrong wrapped error message on MkdirAll failure

In writeAPIKeys, changed the MkdirAll error wrap message from "finding home dir: %s" to "creating private keys dir: %w", fixing the copy-paste drift so the error message describes the actual failing operation.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 75, review and complete this code-review fix: writeAPIKeys returns wrong wrapped error message on MkdirAll failure.
What the draft fix changed: In writeAPIKeys, changed the MkdirAll error wrap message from "finding home dir: %s" to "creating private keys dir: %w", fixing the copy-paste drift so the error message describes the actual failing operation.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟒 90 high β€” react πŸ‘/πŸ‘Ž to teach the reviewer

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.

🦩 🟠 secure.MkdirAll called with file-permission bits (0o600) instead of directory permission bits

In writeAPIKeys, changed secure.MkdirAll permission bits from 0o600 to 0o700 to include the execute bit required for directory traversal. Risk: this changes on-disk permissions behavior for an existing directory path; if any deployed environment relies on the previous (arguably broken) permission value, this could theoretically alter observed permissions, though the fix aligns with correct POSIX directory semantics.

πŸ€– Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 75, review and complete this code-review fix: secure.MkdirAll called with file-permission bits (0o600) instead of directory permission bits.
What the draft fix changed: In writeAPIKeys, changed secure.MkdirAll permission bits from 0o600 to 0o700 to include the execute bit required for directory traversal. Risk: this changes on-disk permissions behavior for an existing directory path; if any deployed environment relies on the previous (arguably broken) permission value, this could theoretically alter observed permissions, though the fix aligns with correct POSIX directory semantics.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟑 75 medium β€” react πŸ‘/πŸ‘Ž to teach the reviewer

return "", fmt.Errorf("finding home dir: %s", err)
if err = secure.MkdirAll(path, 0o700); err != nil {
return "", fmt.Errorf("creating private keys dir: %w", err)
}

keyPath := filepath.Join(path, fmt.Sprintf("AuthKey_%s.p8", id))
if err = os.WriteFile(keyPath, []byte(content), 0o600); err != nil {
return "", fmt.Errorf("writing api key contents: %s", err)
return "", fmt.Errorf("writing api key contents: %w", err)
}

return keyPath, nil
Expand Down
Loading