fix(FLEETMDM-002-2): CU-86akj32d7 62 review findings across 40 files - #175
flamingo[bot] wants to merge 40 commits into
Conversation
| @@ -72,8 +81,8 @@ func writeAPIKeys(issuer, id, content string) (string, error) { | |||
| // The underliying tools (rcodesign and Transporter) expect to find a | |||
| // certificate key in this path. | |||
| path := filepath.Join(homedir, ".appstoreconnect", "private_keys") | |||
There was a problem hiding this comment.
🦩 🟠 writeAPIKeys error message says 'finding home dir' when the actual failing operation is MkdirAll
Changed the error message in writeAPIKeys (macos_rcodesign.go) for the secure.MkdirAll failure from "finding home dir" to "creating private keys dir", correctly describing the failing operation.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 74, review and complete this code-review fix: writeAPIKeys error message says 'finding home dir' when the actual failing operation is MkdirAll.
What the draft fix changed: Changed the error message in writeAPIKeys (macos_rcodesign.go) for the secure.MkdirAll failure from "finding home dir" to "creating private keys dir", correctly describing the failing operation.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer
| @@ -72,8 +81,8 @@ func writeAPIKeys(issuer, id, content string) (string, error) { | |||
| // The underliying tools (rcodesign and Transporter) expect to find a | |||
| // certificate key in this path. | |||
| path := filepath.Join(homedir, ".appstoreconnect", "private_keys") | |||
There was a problem hiding this comment.
🦩 🟠 secure.MkdirAll called with file-permission mode 0o600 instead of a directory mode
Changed the mode argument passed to secure.MkdirAll in writeAPIKeys from 0o600 to 0o700, giving the owner execute/traversal permission needed for a usable directory.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 74, review and complete this code-review fix: secure.MkdirAll called with file-permission mode 0o600 instead of a directory mode.
What the draft fix changed: Changed the mode argument passed to secure.MkdirAll in writeAPIKeys from 0o600 to 0o700, giving the owner execute/traversal permission needed for a usable directory.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
| @@ -30,8 +41,7 @@ func rSign(pkgPath, cert string) error { | |||
| cmd.Stdout = &outBuf | |||
| cmd.Stderr = &outBuf | |||
| if err := cmd.Run(); err != nil { | |||
There was a problem hiding this comment.
🦩 🟠 rSign swallows underlying error detail by printing to stdout instead of wrapping into returned error
In rSign, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign: %w: %s"), so the rcodesign output is available to callers/error handling.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 32, review and complete this code-review fix: rSign swallows underlying error detail by printing to stdout instead of wrapping into returned error.
What the draft fix changed: In rSign, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign: %w: %s"), so the rcodesign output is available to callers/error handling.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer
| @@ -56,8 +66,7 @@ func rNotarizeStaple(pkg, apiKeyID, apiKeyIssuer, apiKeyContent string) error { | |||
| cmd.Stdout = &outBuf | |||
| cmd.Stderr = &outBuf | |||
| if err := cmd.Run(); err != nil { | |||
There was a problem hiding this comment.
🦩 🟠 rNotarizeStaple swallows rcodesign notarize output instead of returning it in the error
In rNotarizeStaple, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign notarize: %w: %s"), preserving diagnostic output in the error itself.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 58, review and complete this code-review fix: rNotarizeStaple swallows rcodesign notarize output instead of returning it in the error.
What the draft fix changed: In rNotarizeStaple, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign notarize: %w: %s"), preserving diagnostic output in the error itself.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer
| @@ -12,12 +12,23 @@ import ( | |||
| ) | |||
|
|
|||
| func rSign(pkgPath, cert string) error { | |||
There was a problem hiding this comment.
🦩 🟠 Private key material written to a predictable path in the shared OS temp directory
In rSign, replaced the fixed-name os.TempDir()/cert.pem file write with os.CreateTemp("", "cert-*.pem") to get a uniquely named temp file, explicitly chmod'd to 0o600 before writing the cert contents, reducing the predictable-path/TOCTOU race window. This changes control flow slightly (explicit Chmod + WriteString + Close with error handling); behavior should be equivalent but the additional error paths introduced are unverified against existing tests, and true hardening would also want O_EXCL semantics guaranteed by CreateTemp (which it already provides) plus possibly restricting the temp dir itself.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 14, review and complete this code-review fix: Private key material written to a predictable path in the shared OS temp directory.
What the draft fix changed: In rSign, replaced the fixed-name os.TempDir()/cert.pem file write with os.CreateTemp("", "cert-*.pem") to get a uniquely named temp file, explicitly chmod'd to 0o600 before writing the cert contents, reducing the predictable-path/TOCTOU race window. This changes control flow slightly (explicit Chmod + WriteString + Close with error handling); behavior should be equivalent but the additional error paths introduced are unverified against existing tests, and true hardening would also want O_EXCL semantics guaranteed by CreateTemp (which it already provides) plus possibly restricting the temp dir itself.
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
| @@ -57,7 +57,7 @@ func buildNFPM(opt Options, pkger nfpm.Packager) (string, error) { | |||
| } | |||
|
|
|||
| if opt.Architecture != ArchAmd64 && opt.Architecture != ArchArm64 { | |||
There was a problem hiding this comment.
🦩 🟠 buildNFPM bare return without wrapping for architecture validation error
In buildNFPM (orbit/pkg/packaging/linux_shared.go), changed the error string from "Invalid architecture: %s" to "invalid architecture: %s" to conform to Go error string conventions (lowercase, no punctuation) consistent with other errors in the file. Purely a string literal change, no behavior change.
🤖 Prompt for AI agents
In orbit/pkg/packaging/linux_shared.go around line 59, review and complete this code-review fix: buildNFPM bare return without wrapping for architecture validation error.
What the draft fix changed: In buildNFPM (orbit/pkg/packaging/linux_shared.go), changed the error string from "Invalid architecture: %s" to "invalid architecture: %s" to conform to Go error string conventions (lowercase, no punctuation) consistent with other errors in the file. Purely a string literal change, no behavior change.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 98 high — react 👍/👎 to teach the reviewer
| if err != nil { | ||
| return ctxerr.Wrap(ctx, err, "upsert maintained app") | ||
| } | ||
| id, _ := res.LastInsertId() |
There was a problem hiding this comment.
🦩 🟠 UpsertMaintainedApp software_titles/software UPDATE errors are wrapped, but LastInsertId error is silently discarded
In UpsertMaintainedApp (server/datastore/mysql/maintained_apps.go), changed id, _ := res.LastInsertId() to id, err := res.LastInsertId() followed by an explicit if err != nil { return ctxerr.Wrap(ctx, err, "get last insert id for maintained app") }, so a failure to retrieve the last insert id now aborts the transaction and is propagated to the caller instead of silently leaving appID as 0. res.RowsAffected() error is left discarded, since it was not part of this finding.
🤖 Prompt for AI agents
In server/datastore/mysql/maintained_apps.go around line 43, review and complete this code-review fix: UpsertMaintainedApp software_titles/software UPDATE errors are wrapped, but LastInsertId error is silently discarded.
What the draft fix changed: In `UpsertMaintainedApp` (server/datastore/mysql/maintained_apps.go), changed `id, _ := res.LastInsertId()` to `id, err := res.LastInsertId()` followed by an explicit `if err != nil { return ctxerr.Wrap(ctx, err, "get last insert id for maintained app") }`, so a failure to retrieve the last insert id now aborts the transaction and is propagated to the caller instead of silently leaving `appID` as 0. `res.RowsAffected()` error is left discarded, since it was not part of this finding.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| package tables | ||
|
|
||
| import "database/sql" | ||
| import ( | ||
| "database/sql" | ||
| "fmt" | ||
| ) | ||
|
|
||
| func init() { | ||
| MigrationClient.AddMigration(Up_20260326210603, Down_20260326210603) |
There was a problem hiding this comment.
🦩 🟠 Bare error return without wrapping loses context in FMA name-sync migration
In Up_20260326210603, the second tx.Exec error (software table update) is now wrapped with fmt.Errorf("updating software names to FMA names: %w", err) instead of being returned bare. Also wrapped the first tx.Exec error (software_titles update) with fmt.Errorf("updating software_titles names to FMA names: %w", err) for consistency, added the fmt import, and changed the final return to return nil after explicit error check.
🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20260326210603_UpdateSoftwareTitleNamesToFMANames.go around line 9, review and complete this code-review fix: Bare error return without wrapping loses context in FMA name-sync migration.
What the draft fix changed: In `Up_20260326210603`, the second `tx.Exec` error (software table update) is now wrapped with `fmt.Errorf("updating software names to FMA names: %w", err)` instead of being returned bare. Also wrapped the first `tx.Exec` error (software_titles update) with `fmt.Errorf("updating software_titles names to FMA names: %w", err)` for consistency, added the `fmt` import, and changed the final return to `return nil` after explicit error check.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 97 high — react 👍/👎 to teach the reviewer
| var os fleet.OperatingSystem | ||
| stmt := "SELECT id, name, version, arch, kernel_version, platform, display_version, installation_type, os_version_id FROM operating_systems WHERE name = ? AND version = ? AND arch = ? AND kernel_version = ? AND platform = ? AND display_version = ? AND installation_type = ?" | ||
| if err := sqlx.GetContext(ctx, tx, &os, stmt, hostOS.Name, hostOS.Version, hostOS.Arch, hostOS.KernelVersion, hostOS.Platform, hostOS.DisplayVersion, hostOS.InstallationType); err != nil { | ||
| return nil, err | ||
| return nil, ctxerr.Wrap(ctx, err, "get operating system") | ||
| } | ||
| return &os, nil | ||
| } |
There was a problem hiding this comment.
🦩 🟠 getOperatingSystemDB and listOperatingSystemsDB return raw sqlx errors without ctxerr wrapping
Wrapped the raw sqlx errors in getOperatingSystemDB and listOperatingSystemsDB (server/datastore/mysql/operating_systems.go) with ctxerr.Wrap(ctx, err, "get operating system") and ctxerr.Wrap(ctx, err, "list operating systems") respectively. Since ctxerr.Wrap preserves the underlying error chain for errors.Is/errors.Unwrap, the existing errors.Is(err, sql.ErrNoRows) check in getOrGenerateOperatingSystemDB and newOperatingSystemDB continues to work correctly against the wrapped error returned from getOperatingSystemDB.
🤖 Prompt for AI agents
In server/datastore/mysql/operating_systems.go around line 145, review and complete this code-review fix: getOperatingSystemDB and listOperatingSystemsDB return raw sqlx errors without ctxerr wrapping.
What the draft fix changed: Wrapped the raw sqlx errors in `getOperatingSystemDB` and `listOperatingSystemsDB` (server/datastore/mysql/operating_systems.go) with `ctxerr.Wrap(ctx, err, "get operating system")` and `ctxerr.Wrap(ctx, err, "list operating systems")` respectively. Since `ctxerr.Wrap` preserves the underlying error chain for `errors.Is`/`errors.Unwrap`, the existing `errors.Is(err, sql.ErrNoRows)` check in `getOrGenerateOperatingSystemDB` and `newOperatingSystemDB` continues to work correctly against the wrapped error returned from `getOperatingSystemDB`.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| @@ -44,7 +44,8 @@ func ReconcileAppleDeclarationsBatched( | |||
|
|
|||
| cursor, err := ds.GetMDMAppleDeclarationReconcileCursor(ctx) | |||
There was a problem hiding this comment.
🦩 🟠 logger.WarnContext error re-log without wrapping context in ReconcileAppleDeclarationsBatched cursor read
In ReconcileAppleDeclarationsBatched, the cursor-read error from ds.GetMDMAppleDeclarationReconcileCursor is now wrapped with fmt.Errorf("reading apple MDM declaration reconcile cursor: %w", err) before being passed to logger.WarnContext, so the context boundary wrapping required by FLEETMDM-002-2 is preserved in the log output. The function still intentionally continues with an empty cursor (existing recovery behavior unchanged), so the wrapped error is logged rather than returned; this matches the finding's specific complaint (missing %w wrapping at the log call) without altering the fallback control flow, which was outside the finding's scope.
🤖 Prompt for AI agents
In server/service/apple_mdm_declarations_batched.go around line 45, review and complete this code-review fix: logger.WarnContext error re-log without wrapping context in ReconcileAppleDeclarationsBatched cursor read.
What the draft fix changed: In ReconcileAppleDeclarationsBatched, the cursor-read error from ds.GetMDMAppleDeclarationReconcileCursor is now wrapped with fmt.Errorf("reading apple MDM declaration reconcile cursor: %w", err) before being passed to logger.WarnContext, so the context boundary wrapping required by FLEETMDM-002-2 is preserved in the log output. The function still intentionally continues with an empty cursor (existing recovery behavior unchanged), so the wrapped error is logged rather than returned; this matches the finding's specific complaint (missing %w wrapping at the log call) without altering the fallback control flow, which was outside the finding's scope.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer
| @@ -72,8 +81,8 @@ func writeAPIKeys(issuer, id, content string) (string, error) { | |||
| // The underliying tools (rcodesign and Transporter) expect to find a | |||
| // certificate key in this path. | |||
| path := filepath.Join(homedir, ".appstoreconnect", "private_keys") | |||
There was a problem hiding this comment.
🦩 🟠 writeAPIKeys error message says 'finding home dir' when the actual failing operation is MkdirAll
Changed the error message in writeAPIKeys (macos_rcodesign.go) for the secure.MkdirAll failure from "finding home dir" to "creating private keys dir", correctly describing the failing operation.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 74, review and complete this code-review fix: writeAPIKeys error message says 'finding home dir' when the actual failing operation is MkdirAll.
What the draft fix changed: Changed the error message in writeAPIKeys (macos_rcodesign.go) for the secure.MkdirAll failure from "finding home dir" to "creating private keys dir", correctly describing the failing operation.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer
| @@ -72,8 +81,8 @@ func writeAPIKeys(issuer, id, content string) (string, error) { | |||
| // The underliying tools (rcodesign and Transporter) expect to find a | |||
| // certificate key in this path. | |||
| path := filepath.Join(homedir, ".appstoreconnect", "private_keys") | |||
There was a problem hiding this comment.
🦩 🟠 secure.MkdirAll called with file-permission mode 0o600 instead of a directory mode
Changed the mode argument passed to secure.MkdirAll in writeAPIKeys from 0o600 to 0o700, giving the owner execute/traversal permission needed for a usable directory.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 74, review and complete this code-review fix: secure.MkdirAll called with file-permission mode 0o600 instead of a directory mode.
What the draft fix changed: Changed the mode argument passed to secure.MkdirAll in writeAPIKeys from 0o600 to 0o700, giving the owner execute/traversal permission needed for a usable directory.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
| @@ -30,8 +41,7 @@ func rSign(pkgPath, cert string) error { | |||
| cmd.Stdout = &outBuf | |||
| cmd.Stderr = &outBuf | |||
| if err := cmd.Run(); err != nil { | |||
There was a problem hiding this comment.
🦩 🟠 rSign swallows underlying error detail by printing to stdout instead of wrapping into returned error
In rSign, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign: %w: %s"), so the rcodesign output is available to callers/error handling.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 32, review and complete this code-review fix: rSign swallows underlying error detail by printing to stdout instead of wrapping into returned error.
What the draft fix changed: In rSign, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign: %w: %s"), so the rcodesign output is available to callers/error handling.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer
| @@ -56,8 +66,7 @@ func rNotarizeStaple(pkg, apiKeyID, apiKeyIssuer, apiKeyContent string) error { | |||
| cmd.Stdout = &outBuf | |||
| cmd.Stderr = &outBuf | |||
| if err := cmd.Run(); err != nil { | |||
There was a problem hiding this comment.
🦩 🟠 rNotarizeStaple swallows rcodesign notarize output instead of returning it in the error
In rNotarizeStaple, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign notarize: %w: %s"), preserving diagnostic output in the error itself.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 58, review and complete this code-review fix: rNotarizeStaple swallows rcodesign notarize output instead of returning it in the error.
What the draft fix changed: In rNotarizeStaple, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign notarize: %w: %s"), preserving diagnostic output in the error itself.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer
| @@ -12,12 +12,23 @@ import ( | |||
| ) | |||
|
|
|||
| func rSign(pkgPath, cert string) error { | |||
There was a problem hiding this comment.
🦩 🟠 Private key material written to a predictable path in the shared OS temp directory
In rSign, replaced the fixed-name os.TempDir()/cert.pem file write with os.CreateTemp("", "cert-*.pem") to get a uniquely named temp file, explicitly chmod'd to 0o600 before writing the cert contents, reducing the predictable-path/TOCTOU race window. This changes control flow slightly (explicit Chmod + WriteString + Close with error handling); behavior should be equivalent but the additional error paths introduced are unverified against existing tests, and true hardening would also want O_EXCL semantics guaranteed by CreateTemp (which it already provides) plus possibly restricting the temp dir itself.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 14, review and complete this code-review fix: Private key material written to a predictable path in the shared OS temp directory.
What the draft fix changed: In rSign, replaced the fixed-name os.TempDir()/cert.pem file write with os.CreateTemp("", "cert-*.pem") to get a uniquely named temp file, explicitly chmod'd to 0o600 before writing the cert contents, reducing the predictable-path/TOCTOU race window. This changes control flow slightly (explicit Chmod + WriteString + Close with error handling); behavior should be equivalent but the additional error paths introduced are unverified against existing tests, and true hardening would also want O_EXCL semantics guaranteed by CreateTemp (which it already provides) plus possibly restricting the temp dir itself.
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
| @@ -57,7 +57,7 @@ func buildNFPM(opt Options, pkger nfpm.Packager) (string, error) { | |||
| } | |||
|
|
|||
| if opt.Architecture != ArchAmd64 && opt.Architecture != ArchArm64 { | |||
There was a problem hiding this comment.
🦩 🟠 buildNFPM bare return without wrapping for architecture validation error
In buildNFPM (orbit/pkg/packaging/linux_shared.go), changed the error string from "Invalid architecture: %s" to "invalid architecture: %s" to conform to Go error string conventions (lowercase, no punctuation) consistent with other errors in the file. Purely a string literal change, no behavior change.
🤖 Prompt for AI agents
In orbit/pkg/packaging/linux_shared.go around line 59, review and complete this code-review fix: buildNFPM bare return without wrapping for architecture validation error.
What the draft fix changed: In buildNFPM (orbit/pkg/packaging/linux_shared.go), changed the error string from "Invalid architecture: %s" to "invalid architecture: %s" to conform to Go error string conventions (lowercase, no punctuation) consistent with other errors in the file. Purely a string literal change, no behavior change.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 98 high — react 👍/👎 to teach the reviewer
| if err != nil { | ||
| return ctxerr.Wrap(ctx, err, "upsert maintained app") | ||
| } | ||
| id, _ := res.LastInsertId() |
There was a problem hiding this comment.
🦩 🟠 UpsertMaintainedApp software_titles/software UPDATE errors are wrapped, but LastInsertId error is silently discarded
In UpsertMaintainedApp (server/datastore/mysql/maintained_apps.go), changed id, _ := res.LastInsertId() to id, err := res.LastInsertId() followed by an explicit if err != nil { return ctxerr.Wrap(ctx, err, "get last insert id for maintained app") }, so a failure to retrieve the last insert id now aborts the transaction and is propagated to the caller instead of silently leaving appID as 0. res.RowsAffected() error is left discarded, since it was not part of this finding.
🤖 Prompt for AI agents
In server/datastore/mysql/maintained_apps.go around line 43, review and complete this code-review fix: UpsertMaintainedApp software_titles/software UPDATE errors are wrapped, but LastInsertId error is silently discarded.
What the draft fix changed: In `UpsertMaintainedApp` (server/datastore/mysql/maintained_apps.go), changed `id, _ := res.LastInsertId()` to `id, err := res.LastInsertId()` followed by an explicit `if err != nil { return ctxerr.Wrap(ctx, err, "get last insert id for maintained app") }`, so a failure to retrieve the last insert id now aborts the transaction and is propagated to the caller instead of silently leaving `appID` as 0. `res.RowsAffected()` error is left discarded, since it was not part of this finding.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| package tables | ||
|
|
||
| import "database/sql" | ||
| import ( | ||
| "database/sql" | ||
| "fmt" | ||
| ) | ||
|
|
||
| func init() { | ||
| MigrationClient.AddMigration(Up_20260326210603, Down_20260326210603) |
There was a problem hiding this comment.
🦩 🟠 Bare error return without wrapping loses context in FMA name-sync migration
In Up_20260326210603, the second tx.Exec error (software table update) is now wrapped with fmt.Errorf("updating software names to FMA names: %w", err) instead of being returned bare. Also wrapped the first tx.Exec error (software_titles update) with fmt.Errorf("updating software_titles names to FMA names: %w", err) for consistency, added the fmt import, and changed the final return to return nil after explicit error check.
🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20260326210603_UpdateSoftwareTitleNamesToFMANames.go around line 9, review and complete this code-review fix: Bare error return without wrapping loses context in FMA name-sync migration.
What the draft fix changed: In `Up_20260326210603`, the second `tx.Exec` error (software table update) is now wrapped with `fmt.Errorf("updating software names to FMA names: %w", err)` instead of being returned bare. Also wrapped the first `tx.Exec` error (software_titles update) with `fmt.Errorf("updating software_titles names to FMA names: %w", err)` for consistency, added the `fmt` import, and changed the final return to `return nil` after explicit error check.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 97 high — react 👍/👎 to teach the reviewer
| var os fleet.OperatingSystem | ||
| stmt := "SELECT id, name, version, arch, kernel_version, platform, display_version, installation_type, os_version_id FROM operating_systems WHERE name = ? AND version = ? AND arch = ? AND kernel_version = ? AND platform = ? AND display_version = ? AND installation_type = ?" | ||
| if err := sqlx.GetContext(ctx, tx, &os, stmt, hostOS.Name, hostOS.Version, hostOS.Arch, hostOS.KernelVersion, hostOS.Platform, hostOS.DisplayVersion, hostOS.InstallationType); err != nil { | ||
| return nil, err | ||
| return nil, ctxerr.Wrap(ctx, err, "get operating system") | ||
| } | ||
| return &os, nil | ||
| } |
There was a problem hiding this comment.
🦩 🟠 getOperatingSystemDB and listOperatingSystemsDB return raw sqlx errors without ctxerr wrapping
Wrapped the raw sqlx errors in getOperatingSystemDB and listOperatingSystemsDB (server/datastore/mysql/operating_systems.go) with ctxerr.Wrap(ctx, err, "get operating system") and ctxerr.Wrap(ctx, err, "list operating systems") respectively. Since ctxerr.Wrap preserves the underlying error chain for errors.Is/errors.Unwrap, the existing errors.Is(err, sql.ErrNoRows) check in getOrGenerateOperatingSystemDB and newOperatingSystemDB continues to work correctly against the wrapped error returned from getOperatingSystemDB.
🤖 Prompt for AI agents
In server/datastore/mysql/operating_systems.go around line 145, review and complete this code-review fix: getOperatingSystemDB and listOperatingSystemsDB return raw sqlx errors without ctxerr wrapping.
What the draft fix changed: Wrapped the raw sqlx errors in `getOperatingSystemDB` and `listOperatingSystemsDB` (server/datastore/mysql/operating_systems.go) with `ctxerr.Wrap(ctx, err, "get operating system")` and `ctxerr.Wrap(ctx, err, "list operating systems")` respectively. Since `ctxerr.Wrap` preserves the underlying error chain for `errors.Is`/`errors.Unwrap`, the existing `errors.Is(err, sql.ErrNoRows)` check in `getOrGenerateOperatingSystemDB` and `newOperatingSystemDB` continues to work correctly against the wrapped error returned from `getOperatingSystemDB`.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| @@ -44,7 +44,8 @@ func ReconcileAppleDeclarationsBatched( | |||
|
|
|||
| cursor, err := ds.GetMDMAppleDeclarationReconcileCursor(ctx) | |||
There was a problem hiding this comment.
🦩 🟠 logger.WarnContext error re-log without wrapping context in ReconcileAppleDeclarationsBatched cursor read
In ReconcileAppleDeclarationsBatched, the cursor-read error from ds.GetMDMAppleDeclarationReconcileCursor is now wrapped with fmt.Errorf("reading apple MDM declaration reconcile cursor: %w", err) before being passed to logger.WarnContext, so the context boundary wrapping required by FLEETMDM-002-2 is preserved in the log output. The function still intentionally continues with an empty cursor (existing recovery behavior unchanged), so the wrapped error is logged rather than returned; this matches the finding's specific complaint (missing %w wrapping at the log call) without altering the fallback control flow, which was outside the finding's scope.
🤖 Prompt for AI agents
In server/service/apple_mdm_declarations_batched.go around line 45, review and complete this code-review fix: logger.WarnContext error re-log without wrapping context in ReconcileAppleDeclarationsBatched cursor read.
What the draft fix changed: In ReconcileAppleDeclarationsBatched, the cursor-read error from ds.GetMDMAppleDeclarationReconcileCursor is now wrapped with fmt.Errorf("reading apple MDM declaration reconcile cursor: %w", err) before being passed to logger.WarnContext, so the context boundary wrapping required by FLEETMDM-002-2 is preserved in the log output. The function still intentionally continues with an empty cursor (existing recovery behavior unchanged), so the wrapped error is logged rather than returned; this matches the finding's specific complaint (missing %w wrapping at the log call) without altering the fallback control flow, which was outside the finding's scope.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer
| @@ -72,8 +81,8 @@ func writeAPIKeys(issuer, id, content string) (string, error) { | |||
| // The underliying tools (rcodesign and Transporter) expect to find a | |||
| // certificate key in this path. | |||
| path := filepath.Join(homedir, ".appstoreconnect", "private_keys") | |||
There was a problem hiding this comment.
🦩 🟠 writeAPIKeys error message says 'finding home dir' when the actual failing operation is MkdirAll
Changed the error message in writeAPIKeys (macos_rcodesign.go) for the secure.MkdirAll failure from "finding home dir" to "creating private keys dir", correctly describing the failing operation.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 74, review and complete this code-review fix: writeAPIKeys error message says 'finding home dir' when the actual failing operation is MkdirAll.
What the draft fix changed: Changed the error message in writeAPIKeys (macos_rcodesign.go) for the secure.MkdirAll failure from "finding home dir" to "creating private keys dir", correctly describing the failing operation.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer
| @@ -72,8 +81,8 @@ func writeAPIKeys(issuer, id, content string) (string, error) { | |||
| // The underliying tools (rcodesign and Transporter) expect to find a | |||
| // certificate key in this path. | |||
| path := filepath.Join(homedir, ".appstoreconnect", "private_keys") | |||
There was a problem hiding this comment.
🦩 🟠 secure.MkdirAll called with file-permission mode 0o600 instead of a directory mode
Changed the mode argument passed to secure.MkdirAll in writeAPIKeys from 0o600 to 0o700, giving the owner execute/traversal permission needed for a usable directory.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 74, review and complete this code-review fix: secure.MkdirAll called with file-permission mode 0o600 instead of a directory mode.
What the draft fix changed: Changed the mode argument passed to secure.MkdirAll in writeAPIKeys from 0o600 to 0o700, giving the owner execute/traversal permission needed for a usable directory.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 90 high — react 👍/👎 to teach the reviewer
| @@ -30,8 +41,7 @@ func rSign(pkgPath, cert string) error { | |||
| cmd.Stdout = &outBuf | |||
| cmd.Stderr = &outBuf | |||
| if err := cmd.Run(); err != nil { | |||
There was a problem hiding this comment.
🦩 🟠 rSign swallows underlying error detail by printing to stdout instead of wrapping into returned error
In rSign, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign: %w: %s"), so the rcodesign output is available to callers/error handling.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 32, review and complete this code-review fix: rSign swallows underlying error detail by printing to stdout instead of wrapping into returned error.
What the draft fix changed: In rSign, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign: %w: %s"), so the rcodesign output is available to callers/error handling.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer
| @@ -56,8 +66,7 @@ func rNotarizeStaple(pkg, apiKeyID, apiKeyIssuer, apiKeyContent string) error { | |||
| cmd.Stdout = &outBuf | |||
| cmd.Stderr = &outBuf | |||
| if err := cmd.Run(); err != nil { | |||
There was a problem hiding this comment.
🦩 🟠 rNotarizeStaple swallows rcodesign notarize output instead of returning it in the error
In rNotarizeStaple, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign notarize: %w: %s"), preserving diagnostic output in the error itself.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 58, review and complete this code-review fix: rNotarizeStaple swallows rcodesign notarize output instead of returning it in the error.
What the draft fix changed: In rNotarizeStaple, removed the fmt.Println(outBuf.String()) call and instead embedded outBuf.String() into the returned wrapped error ("rcodesign notarize: %w: %s"), preserving diagnostic output in the error itself.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer
| @@ -12,12 +12,23 @@ import ( | |||
| ) | |||
|
|
|||
| func rSign(pkgPath, cert string) error { | |||
There was a problem hiding this comment.
🦩 🟠 Private key material written to a predictable path in the shared OS temp directory
In rSign, replaced the fixed-name os.TempDir()/cert.pem file write with os.CreateTemp("", "cert-*.pem") to get a uniquely named temp file, explicitly chmod'd to 0o600 before writing the cert contents, reducing the predictable-path/TOCTOU race window. This changes control flow slightly (explicit Chmod + WriteString + Close with error handling); behavior should be equivalent but the additional error paths introduced are unverified against existing tests, and true hardening would also want O_EXCL semantics guaranteed by CreateTemp (which it already provides) plus possibly restricting the temp dir itself.
🤖 Prompt for AI agents
In orbit/pkg/packaging/macos_rcodesign.go around line 14, review and complete this code-review fix: Private key material written to a predictable path in the shared OS temp directory.
What the draft fix changed: In rSign, replaced the fixed-name os.TempDir()/cert.pem file write with os.CreateTemp("", "cert-*.pem") to get a uniquely named temp file, explicitly chmod'd to 0o600 before writing the cert contents, reducing the predictable-path/TOCTOU race window. This changes control flow slightly (explicit Chmod + WriteString + Close with error handling); behavior should be equivalent but the additional error paths introduced are unverified against existing tests, and true hardening would also want O_EXCL semantics guaranteed by CreateTemp (which it already provides) plus possibly restricting the temp dir itself.
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
| @@ -57,7 +57,7 @@ func buildNFPM(opt Options, pkger nfpm.Packager) (string, error) { | |||
| } | |||
|
|
|||
| if opt.Architecture != ArchAmd64 && opt.Architecture != ArchArm64 { | |||
There was a problem hiding this comment.
🦩 🟠 buildNFPM bare return without wrapping for architecture validation error
In buildNFPM (orbit/pkg/packaging/linux_shared.go), changed the error string from "Invalid architecture: %s" to "invalid architecture: %s" to conform to Go error string conventions (lowercase, no punctuation) consistent with other errors in the file. Purely a string literal change, no behavior change.
🤖 Prompt for AI agents
In orbit/pkg/packaging/linux_shared.go around line 59, review and complete this code-review fix: buildNFPM bare return without wrapping for architecture validation error.
What the draft fix changed: In buildNFPM (orbit/pkg/packaging/linux_shared.go), changed the error string from "Invalid architecture: %s" to "invalid architecture: %s" to conform to Go error string conventions (lowercase, no punctuation) consistent with other errors in the file. Purely a string literal change, no behavior change.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 98 high — react 👍/👎 to teach the reviewer
| if err != nil { | ||
| return ctxerr.Wrap(ctx, err, "upsert maintained app") | ||
| } | ||
| id, _ := res.LastInsertId() |
There was a problem hiding this comment.
🦩 🟠 UpsertMaintainedApp software_titles/software UPDATE errors are wrapped, but LastInsertId error is silently discarded
In UpsertMaintainedApp (server/datastore/mysql/maintained_apps.go), changed id, _ := res.LastInsertId() to id, err := res.LastInsertId() followed by an explicit if err != nil { return ctxerr.Wrap(ctx, err, "get last insert id for maintained app") }, so a failure to retrieve the last insert id now aborts the transaction and is propagated to the caller instead of silently leaving appID as 0. res.RowsAffected() error is left discarded, since it was not part of this finding.
🤖 Prompt for AI agents
In server/datastore/mysql/maintained_apps.go around line 43, review and complete this code-review fix: UpsertMaintainedApp software_titles/software UPDATE errors are wrapped, but LastInsertId error is silently discarded.
What the draft fix changed: In `UpsertMaintainedApp` (server/datastore/mysql/maintained_apps.go), changed `id, _ := res.LastInsertId()` to `id, err := res.LastInsertId()` followed by an explicit `if err != nil { return ctxerr.Wrap(ctx, err, "get last insert id for maintained app") }`, so a failure to retrieve the last insert id now aborts the transaction and is propagated to the caller instead of silently leaving `appID` as 0. `res.RowsAffected()` error is left discarded, since it was not part of this finding.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| package tables | ||
|
|
||
| import "database/sql" | ||
| import ( | ||
| "database/sql" | ||
| "fmt" | ||
| ) | ||
|
|
||
| func init() { | ||
| MigrationClient.AddMigration(Up_20260326210603, Down_20260326210603) |
There was a problem hiding this comment.
🦩 🟠 Bare error return without wrapping loses context in FMA name-sync migration
In Up_20260326210603, the second tx.Exec error (software table update) is now wrapped with fmt.Errorf("updating software names to FMA names: %w", err) instead of being returned bare. Also wrapped the first tx.Exec error (software_titles update) with fmt.Errorf("updating software_titles names to FMA names: %w", err) for consistency, added the fmt import, and changed the final return to return nil after explicit error check.
🤖 Prompt for AI agents
In server/datastore/mysql/migrations/tables/20260326210603_UpdateSoftwareTitleNamesToFMANames.go around line 9, review and complete this code-review fix: Bare error return without wrapping loses context in FMA name-sync migration.
What the draft fix changed: In `Up_20260326210603`, the second `tx.Exec` error (software table update) is now wrapped with `fmt.Errorf("updating software names to FMA names: %w", err)` instead of being returned bare. Also wrapped the first `tx.Exec` error (software_titles update) with `fmt.Errorf("updating software_titles names to FMA names: %w", err)` for consistency, added the `fmt` import, and changed the final return to `return nil` after explicit error check.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 97 high — react 👍/👎 to teach the reviewer
| var os fleet.OperatingSystem | ||
| stmt := "SELECT id, name, version, arch, kernel_version, platform, display_version, installation_type, os_version_id FROM operating_systems WHERE name = ? AND version = ? AND arch = ? AND kernel_version = ? AND platform = ? AND display_version = ? AND installation_type = ?" | ||
| if err := sqlx.GetContext(ctx, tx, &os, stmt, hostOS.Name, hostOS.Version, hostOS.Arch, hostOS.KernelVersion, hostOS.Platform, hostOS.DisplayVersion, hostOS.InstallationType); err != nil { | ||
| return nil, err | ||
| return nil, ctxerr.Wrap(ctx, err, "get operating system") | ||
| } | ||
| return &os, nil | ||
| } |
There was a problem hiding this comment.
🦩 🟠 getOperatingSystemDB and listOperatingSystemsDB return raw sqlx errors without ctxerr wrapping
Wrapped the raw sqlx errors in getOperatingSystemDB and listOperatingSystemsDB (server/datastore/mysql/operating_systems.go) with ctxerr.Wrap(ctx, err, "get operating system") and ctxerr.Wrap(ctx, err, "list operating systems") respectively. Since ctxerr.Wrap preserves the underlying error chain for errors.Is/errors.Unwrap, the existing errors.Is(err, sql.ErrNoRows) check in getOrGenerateOperatingSystemDB and newOperatingSystemDB continues to work correctly against the wrapped error returned from getOperatingSystemDB.
🤖 Prompt for AI agents
In server/datastore/mysql/operating_systems.go around line 145, review and complete this code-review fix: getOperatingSystemDB and listOperatingSystemsDB return raw sqlx errors without ctxerr wrapping.
What the draft fix changed: Wrapped the raw sqlx errors in `getOperatingSystemDB` and `listOperatingSystemsDB` (server/datastore/mysql/operating_systems.go) with `ctxerr.Wrap(ctx, err, "get operating system")` and `ctxerr.Wrap(ctx, err, "list operating systems")` respectively. Since `ctxerr.Wrap` preserves the underlying error chain for `errors.Is`/`errors.Unwrap`, the existing `errors.Is(err, sql.ErrNoRows)` check in `getOrGenerateOperatingSystemDB` and `newOperatingSystemDB` continues to work correctly against the wrapped error returned from `getOperatingSystemDB`.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟢 92 high — react 👍/👎 to teach the reviewer
| @@ -44,7 +44,8 @@ func ReconcileAppleDeclarationsBatched( | |||
|
|
|||
| cursor, err := ds.GetMDMAppleDeclarationReconcileCursor(ctx) | |||
There was a problem hiding this comment.
🦩 🟠 logger.WarnContext error re-log without wrapping context in ReconcileAppleDeclarationsBatched cursor read
In ReconcileAppleDeclarationsBatched, the cursor-read error from ds.GetMDMAppleDeclarationReconcileCursor is now wrapped with fmt.Errorf("reading apple MDM declaration reconcile cursor: %w", err) before being passed to logger.WarnContext, so the context boundary wrapping required by FLEETMDM-002-2 is preserved in the log output. The function still intentionally continues with an empty cursor (existing recovery behavior unchanged), so the wrapped error is logged rather than returned; this matches the finding's specific complaint (missing %w wrapping at the log call) without altering the fallback control flow, which was outside the finding's scope.
🤖 Prompt for AI agents
In server/service/apple_mdm_declarations_batched.go around line 45, review and complete this code-review fix: logger.WarnContext error re-log without wrapping context in ReconcileAppleDeclarationsBatched cursor read.
What the draft fix changed: In ReconcileAppleDeclarationsBatched, the cursor-read error from ds.GetMDMAppleDeclarationReconcileCursor is now wrapped with fmt.Errorf("reading apple MDM declaration reconcile cursor: %w", err) before being passed to logger.WarnContext, so the context boundary wrapping required by FLEETMDM-002-2 is preserved in the log output. The function still intentionally continues with an empty cursor (existing recovery behavior unchanged), so the wrapped error is logged rather than returned; this matches the finding's specific complaint (missing %w wrapping at the log call) without altering the fallback control flow, which was outside the finding's scope.
Verify the change is correct and complete; do not refactor unrelated code.
fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer
Closes 62 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.
orbit/pkg/packaging/macos_rcodesign.go:74orbit/pkg/packaging/macos_rcodesign.go:74orbit/pkg/packaging/macos_rcodesign.go:32orbit/pkg/packaging/macos_rcodesign.go:58orbit/pkg/packaging/macos_rcodesign.go:14server/datastore/mysql/wstep.go:31server/datastore/mysql/wstep.go:47server/datastore/mysql/wstep.go:60server/datastore/mysql/wstep.go:52server/mdm/assets/assets.go:139server/mdm/assets/assets.go:73server/mdm/assets/assets.go:23server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go:303server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go:74server/service/conditional_access_microsoft_proxy/conditional_access_microsoft_proxy.go:192server/datastore/mysql/migrations/tables/migration.go:29server/datastore/mysql/migrations/tables/migration.go:230server/datastore/mysql/migrations/tables/migration.go:66server/mdm/android/service/reconcile_devices.go:88case !ok:aftercase ok:on a boolean switchserver/mdm/android/service/reconcile_devices.go:75server/mdm/android/service/reconcile_devices.go:33tools/mdm/apple/loadtest/loadtest.go:161tools/mdm/apple/loadtest/loadtest.go:169ee/orbit/pkg/httpsigproxy/httpsigproxy.go:226ee/orbit/pkg/httpsigproxy/httpsigproxy.go:111server/service/client_users.go:73server/service/client_users.go:92orbit/pkg/go-paniclog/paniclog_windows.go:58orbit/pkg/go-paniclog/paniclog_windows.go:64tools/mdm/migration/jamf/main.go:140tools/mdm/migration/jamf/main.go:80orbit/pkg/windows/windowsupdate/iupdate.go:128orbit/pkg/windows/windowsupdate/iupdate.go:102server/logging/kafkarest.go:81server/logging/kafkarest.go:81server/mdm/nanodep/cmd/deptokens/main.go:84orbit/cmd/desktop/desktop_linux.go:55server/mdm/apple/vpp/api.go:236orbit/pkg/table/extension.go:131server/datastore/mysql/host_identity_scep.go:43server/datastore/mysql/scheduled_queries.go:367server/platform/mysql/common.go:92tools/dibble/pkg/seed/enroll_secrets.go:42tools/bump-migration/main.go:31orbit/pkg/dataflatten/json.go:10orbit/pkg/dataflatten/jsonl.go:11orbit/pkg/dataflatten/plist.go:11server/mail/invite.go:22server/vulnerabilities/customcve/matching_rules.go:99orbit/pkg/packaging/wix/transform.go:67server/datastore/failing/common_store.go:29server/datastore/mysql/calendar_events.go:97server/datastore/mysql/queries.go:336server/service/client_hosts.go:92server/service/client_software.go:211ee/server/calendar/google_calendar_load.go:128orbit/pkg/osquery/osquery.go:184orbit/pkg/packaging/linux_shared.go:59server/datastore/mysql/maintained_apps.go:43server/datastore/mysql/migrations/tables/20260326210603_UpdateSoftwareTitleNamesToFMANames.go:9server/datastore/mysql/operating_systems.go:145server/service/apple_mdm_declarations_batched.go:45What 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:
1446a072-096e-4294-8082-c7cadffe76deMerging 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.
ClickUp task: CU-86akj32d7 FleetMDM bulk review findings sweep (12 PRs)