Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions frontend/utilities/auth_token/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Cookie from "js-cookie";

const DEFAULT_EXPIRATION_DAYS = 5;

// >>> OPENFRAME(auth-token-http-fallback): allow non-secure cookie fallback for non-TLS deployments β€” openframe/docs/auth.md
// The `__Host-` cookie name prefix and the `Secure` attribute both require the

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.

🦩 πŸ”΄ Fork-specific fallback logic in upstream auth_token utility lacks OPENFRAME sentinel comments

Wrapped all fork-specific HTTPS-detection fallback logic in frontend/utilities/auth_token/index.ts with // >>> OPENFRAME(auth-token-http-fallback): ... β€” openframe/docs/auth.md / // <<< OPENFRAME(auth-token-http-fallback) sentinel comment pairs: around the isSecure/getTokenName function definitions, and around the Cookie.set call in save, the Cookie.get call in get, and the Cookie.remove call in remove, since each of these call sites depends on the fork-specific getTokenName/isSecure behavior.

πŸ€– Prompt for AI agents
In frontend/utilities/auth_token/index.ts around line 9, review and complete this code-review fix: Fork-specific fallback logic in upstream auth_token utility lacks OPENFRAME sentinel comments.
What the draft fix changed: Wrapped all fork-specific HTTPS-detection fallback logic in `frontend/utilities/auth_token/index.ts` with `// >>> OPENFRAME(auth-token-http-fallback): ... β€” openframe/docs/auth.md` / `// <<< OPENFRAME(auth-token-http-fallback)` sentinel comment pairs: around the `isSecure`/`getTokenName` function definitions, and around the `Cookie.set` call in `save`, the `Cookie.get` call in `get`, and the `Cookie.remove` call in `remove`, since each of these call sites depends on the fork-specific `getTokenName`/`isSecure` behavior.
Verify the change is correct and complete; do not refactor unrelated code.

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

// cookie to be set from a secure (HTTPS) context. When Fleet is served over
// plain HTTP (e.g. a Docker deployment without TLS), the browser silently
Expand All @@ -18,26 +19,33 @@ const isSecure = (): boolean => window.location.protocol === "https:";
// `__Host-` prefixed names are only valid on secure cookies, so the cookie name
// must match the context it was stored in for get/remove to find it.
const getTokenName = (): string => (isSecure() ? "__Host-token" : "token");
// <<< OPENFRAME(auth-token-http-fallback)

const save = (token: string, expiresAt?: Date): void => {
// >>> OPENFRAME(auth-token-http-fallback): allow non-secure cookie fallback for non-TLS deployments β€” openframe/docs/auth.md
Cookie.set(getTokenName(), token, {
secure: isSecure(),
sameSite: "lax",
expires: expiresAt ?? DEFAULT_EXPIRATION_DAYS,
});
// <<< OPENFRAME(auth-token-http-fallback)
};

const get = (): string | null => {
// >>> OPENFRAME(auth-token-http-fallback): allow non-secure cookie fallback for non-TLS deployments β€” openframe/docs/auth.md
return Cookie.get(getTokenName()) || null;
// <<< OPENFRAME(auth-token-http-fallback)
};

const remove = (): void => {
// NOTE: the secure and sameSite from the cookie must be provided
// to correctly remove. That is why we include the options here as well.
// >>> OPENFRAME(auth-token-http-fallback): allow non-secure cookie fallback for non-TLS deployments β€” openframe/docs/auth.md
Cookie.remove(getTokenName(), {
secure: isSecure(),
sameSite: "lax",
});
// <<< OPENFRAME(auth-token-http-fallback)
};

export default {
Expand Down
4 changes: 4 additions & 0 deletions server/contexts/viewer/viewer.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func (v Viewer) CanPerformPasswordReset() bool {
return false
}

// >>> OPENFRAME(viewer-telemetry): add diagnostic/telemetry context and system viewer β€” openframe/docs/....md

// GetDiagnosticContext implements ctxerr.ErrorContextProvider

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.

🦩 πŸ”΄ New NewSystemContext fork addition to viewer.go missing OPENFRAME sentinel comments

Wrapped the fork-only additions (GetDiagnosticContext, GetTelemetryContext, maskEmail, systemUserName, systemUser, NewSystemContext) in // >>> OPENFRAME(viewer-telemetry): add diagnostic/telemetry context and system viewer β€” openframe/docs/....md and // <<< OPENFRAME(viewer-telemetry) sentinel comments, placed immediately after the last unmodified upstream method (CanPerformPasswordReset) and at the end of the file, per FLEETMDM-001. The doc reference path in the sentinel is a placeholder (openframe/docs/....md) as given in the suggested fix and should be updated to the actual doc path by a human reviewer.

πŸ€– Prompt for AI agents
In server/contexts/viewer/viewer.go around line 108, review and complete this code-review fix: New NewSystemContext fork addition to viewer.go missing OPENFRAME sentinel comments.
What the draft fix changed: Wrapped the fork-only additions (GetDiagnosticContext, GetTelemetryContext, maskEmail, systemUserName, systemUser, NewSystemContext) in `// >>> OPENFRAME(viewer-telemetry): add diagnostic/telemetry context and system viewer β€” openframe/docs/....md` and `// <<< OPENFRAME(viewer-telemetry)` sentinel comments, placed immediately after the last unmodified upstream method (`CanPerformPasswordReset`) and at the end of the file, per FLEETMDM-001. The doc reference path in the sentinel is a placeholder (`openframe/docs/....md`) as given in the suggested fix and should be updated to the actual doc path by a human reviewer.
Verify the change is correct and complete; do not refactor unrelated code.

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

func (v *Viewer) GetDiagnosticContext() map[string]any {
vdata := map[string]any{
Expand Down Expand Up @@ -156,3 +158,5 @@ var systemUser = &fleet.User{
func NewSystemContext(ctx context.Context) context.Context {
return NewContext(ctx, Viewer{User: systemUser})
}

// <<< OPENFRAME(viewer-telemetry)
12 changes: 12 additions & 0 deletions server/datastore/mysqlredis/hosts.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,14 @@ func (d *Datastore) NewHost(ctx context.Context, host *fleet.Host) (*fleet.Host,
logging.WithErr(ctx, err)
}
}
// >>> OPENFRAME(host-cache-invalidation): invalidate node_key cache on host creation β€” openframe/docs/host-cache.md
// A newly inserted host has no positive cache entry, but a stale negative
// cache entry for the new node_key could linger (up to hostCacheNegativeTTL)
// if the node_key had been probed moments before enrollment. Clearing it
// here ensures the next LoadHostByNodeKey populates the positive cache
// instead of returning a false NotFound.
d.invalidateAfterHostEnroll(ctx, h, "enroll")
// <<< OPENFRAME(host-cache-invalidation)
return h, 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.

🦩 πŸ”΄ New fork file mysqlredis/hosts.go lacks OPENFRAME sentinel comments around fork-specific cache invalidation logic

Wrapped each fork-specific cache-invalidation call in // >>> OPENFRAME(host-cache-invalidation): ... β€” openframe/docs/host-cache.md / // <<< OPENFRAME(host-cache-invalidation) sentinel comment pairs in NewHost, EnrollOsquery, DeleteHost, DeleteHosts, CleanupExpiredHosts, and CleanupIncomingHosts, immediately around the d.invalidateAfterHostEnroll(...), d.hostCacheDeleteByID(...), and d.invalidateHostIDs(...) calls (existing explanatory comments preserved inside the sentinel block). The doc path openframe/docs/host-cache.md is a placeholder slug/doc reference since the actual doc filename wasn't specified in the finding β€” a reviewer should confirm/update it to match the real doc location if one exists.

πŸ€– Prompt for AI agents
In server/datastore/mysqlredis/hosts.go around line 143, review and complete this code-review fix: New fork file mysqlredis/hosts.go lacks OPENFRAME sentinel comments around fork-specific cache invalidation logic.
What the draft fix changed: Wrapped each fork-specific cache-invalidation call in `// >>> OPENFRAME(host-cache-invalidation): ... β€” openframe/docs/host-cache.md` / `// <<< OPENFRAME(host-cache-invalidation)` sentinel comment pairs in `NewHost`, `EnrollOsquery`, `DeleteHost`, `DeleteHosts`, `CleanupExpiredHosts`, and `CleanupIncomingHosts`, immediately around the `d.invalidateAfterHostEnroll(...)`, `d.hostCacheDeleteByID(...)`, and `d.invalidateHostIDs(...)` calls (existing explanatory comments preserved inside the sentinel block). The doc path `openframe/docs/host-cache.md` is a placeholder slug/doc reference since the actual doc filename wasn't specified in the finding β€” a reviewer should confirm/update it to match the real doc location if one exists.
Verify the change is correct and complete; do not refactor unrelated code.

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

}

Expand All @@ -153,9 +155,11 @@ func (d *Datastore) EnrollOsquery(ctx context.Context, opts ...fleet.DatastoreEn
logging.WithErr(ctx, err)
}
}
// >>> OPENFRAME(host-cache-invalidation): invalidate stale cache on re-enrollment β€” openframe/docs/host-cache.md
// EnrollOsquery can update an existing row's node_key + team_id on
// re-enrollment, so the cached snapshot is stale after the call.
d.invalidateAfterHostEnroll(ctx, h, "enroll")
// <<< OPENFRAME(host-cache-invalidation)
return h, nil
}

Expand All @@ -169,9 +173,11 @@ func (d *Datastore) DeleteHost(ctx context.Context, hid uint) error {
logging.WithErr(ctx, err)
}
}
// >>> OPENFRAME(host-cache-invalidation): purge cache entry on host deletion β€” openframe/docs/host-cache.md
// Deleted row must not serve from cache: a stale hit would let the host
// authenticate after its deletion.
d.hostCacheDeleteByID(ctx, hid, "delete")
// <<< OPENFRAME(host-cache-invalidation)
return nil
}

Expand All @@ -185,8 +191,10 @@ func (d *Datastore) DeleteHosts(ctx context.Context, ids []uint) error {
logging.WithErr(ctx, err)
}
}
// >>> OPENFRAME(host-cache-invalidation): purge cache entries on batch host deletion β€” openframe/docs/host-cache.md
// Batched pipelined invalidation β€” see invalidateHostIDs for why.
d.invalidateHostIDs(ctx, ids, "delete")
// <<< OPENFRAME(host-cache-invalidation)
return nil
}

Expand All @@ -204,7 +212,9 @@ func (d *Datastore) CleanupExpiredHosts(ctx context.Context) ([]fleet.DeletedHos
logging.WithErr(ctx, err)
}
}
// >>> OPENFRAME(host-cache-invalidation): purge cache entries for expired hosts β€” openframe/docs/host-cache.md
d.invalidateHostIDs(ctx, ids, "delete")
// <<< OPENFRAME(host-cache-invalidation)
return details, nil
}

Expand All @@ -218,7 +228,9 @@ func (d *Datastore) CleanupIncomingHosts(ctx context.Context, now time.Time) ([]
logging.WithErr(ctx, err)
}
}
// >>> OPENFRAME(host-cache-invalidation): purge cache entries for cleaned up incoming hosts β€” openframe/docs/host-cache.md
d.invalidateHostIDs(ctx, ids, "delete")
// <<< OPENFRAME(host-cache-invalidation)
return ids, nil
}

Expand Down
3 changes: 3 additions & 0 deletions server/mdm/nanomdm/storage/mysql/mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (s *MySQLStorage) StoreAuthenticate(r *mdm.Request, msg *mdm.Authenticate)
if r.Certificate != nil {
pemCert = cryptoutil.PEMCertificate(r.Certificate.Raw)
}
// >>> OPENFRAME(nanomdm-bootstrap-token-renewal): preserve bootstrap token across SCEP renewal β€” openframe/docs/nanomdm.md
// When a device undergoes SCEP certificate renewal, it sends a new
// Authenticate message. We must preserve the existing bootstrap token
// during renewal; clearing it causes commands that depend on it (e.g.
Comment on lines 142 to 148

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.

🦩 πŸ”΄ Fork-specific comment referencing openframe issue lacks required OPENFRAME sentinel wrapper

In StoreAuthenticate, wrapped the fork-specific comment and the s.db.ExecContext(...) call that preserves the bootstrap token across SCEP renewal with // >>> OPENFRAME(nanomdm-bootstrap-token-renewal): ... β€” openframe/docs/nanomdm.md before the comment and // <<< OPENFRAME(nanomdm-bootstrap-token-renewal) after the closing ) of the ExecContext call, matching the suggested fix exactly. No other lines were changed.

πŸ€– Prompt for AI agents
In server/mdm/nanomdm/storage/mysql/mysql.go around line 158, review and complete this code-review fix: Fork-specific comment referencing openframe issue lacks required OPENFRAME sentinel wrapper.
What the draft fix changed: In `StoreAuthenticate`, wrapped the fork-specific comment and the `s.db.ExecContext(...)` call that preserves the bootstrap token across SCEP renewal with `// >>> OPENFRAME(nanomdm-bootstrap-token-renewal): ... β€” openframe/docs/nanomdm.md` before the comment and `// <<< OPENFRAME(nanomdm-bootstrap-token-renewal)` after the closing `)` of the ExecContext call, matching the suggested fix exactly. No other lines were changed.
Verify the change is correct and complete; do not refactor unrelated code.

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

Expand Down Expand Up @@ -170,6 +171,7 @@ UPDATE
authenticate_at = CURRENT_TIMESTAMP;`,
r.ID, pemCert, nullEmptyString(msg.SerialNumber), msg.Raw, r.ID, r.ID,
)
// <<< OPENFRAME(nanomdm-bootstrap-token-renewal)

return err
}
Expand Down Expand Up @@ -378,3 +380,4 @@ func (s *MySQLStorage) SetRecoveryLockFailed(ctx context.Context, hostUUID strin
s.logger.ErrorContext(ctx, "MySQLStorage.SetRecoveryLockFailed not implemented")
return nil
}

5 changes: 5 additions & 0 deletions server/mock/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,13 @@ func (m *Store) GetCurrentTime(ctx context.Context) (time.Time, error) {
func (m *Store) Drop() error { return nil }
func (m *Store) MigrateTables(ctx context.Context) error { return nil }
func (m *Store) MigrateData(ctx context.Context) error { return nil }

// >>> OPENFRAME(mock-migrate-openframe): add MigrateOpenframe mock stub for OpenFrame migration hook β€” openframe/docs/datastore.md
func (m *Store) MigrateOpenframe(ctx context.Context) error { return nil }

// <<< OPENFRAME(mock-migrate-openframe)
func (m *Store) MigrationStatus(ctx context.Context) (*fleet.MigrationStatus, error) {
return &fleet.MigrationStatus{}, nil
}
func (m *Store) Name() string { return "mock" }

Comment on lines 38 to +50

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.

🦩 πŸ”΄ MigrateOpenframe addition to upstream server/mock/datastore.go lacks required OPENFRAME sentinel comments

In server/mock/datastore.go, wrapped the MigrateOpenframe method (near the MigrateTables/MigrateData/MigrationStatus group) with // >>> OPENFRAME(mock-migrate-openframe): ... and // <<< OPENFRAME(mock-migrate-openframe) sentinel comments per FLEETMDM-001, using the suggested slug and description so future upstream syncs can locate and preserve this fork-specific addition.

πŸ€– Prompt for AI agents
In server/mock/datastore.go around line 24, review and complete this code-review fix: MigrateOpenframe addition to upstream server/mock/datastore.go lacks required OPENFRAME sentinel comments.
What the draft fix changed: In `server/mock/datastore.go`, wrapped the `MigrateOpenframe` method (near the `MigrateTables`/`MigrateData`/`MigrationStatus` group) with `// >>> OPENFRAME(mock-migrate-openframe): ...` and `// <<< OPENFRAME(mock-migrate-openframe)` sentinel comments per FLEETMDM-001, using the suggested slug and description so future upstream syncs can locate and preserve this fork-specific addition.
Verify the change is correct and complete; do not refactor unrelated code.

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

Comment on lines 38 to +50

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.

🦩 πŸ”΅ server/mock/datastore.go MigrateOpenframe method inconsistently indented/formatted, likely a fork-specific addition without sentinel wrapping

Same location (MigrateOpenframe in server/mock/datastore.go): the sentinel wrapping added for finding 1 also addresses this duplicate finding about missing sentinels/ad-hoc formatting. I did not further realign the method with the other one-liners (e.g. adjusting whitespace to match Drop/MigrateTables column alignment) since that would be a cosmetic reformat beyond the sentinel requirement; if strict visual alignment is also desired, that is a separate minimal follow-up.

πŸ€– Prompt for AI agents
In server/mock/datastore.go around line 24, review and complete this code-review fix: server/mock/datastore.go MigrateOpenframe method inconsistently indented/formatted, likely a fork-specific addition without sentinel wrapping.
What the draft fix changed: Same location (`MigrateOpenframe` in `server/mock/datastore.go`): the sentinel wrapping added for finding 1 also addresses this duplicate finding about missing sentinels/ad-hoc formatting. I did not further realign the method with the other one-liners (e.g. adjusting whitespace to match `Drop`/`MigrateTables` column alignment) since that would be a cosmetic reformat beyond the sentinel requirement; if strict visual alignment is also desired, that is a separate minimal follow-up.
Verify the change is correct and complete; do not refactor unrelated code.

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

2 changes: 2 additions & 0 deletions server/service/async/async_label.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func (t *Task) RecordLabelQueryExecutions(ctx context.Context, host *fleet.Host,
}

func (t *Task) collectLabelQueryExecutions(ctx context.Context, ds fleet.Datastore, pool fleet.RedisPool, stats *collectorExecStats) error {
// >>> OPENFRAME(async-otel): add OTEL span for label collection task β€” openframe/docs/observability.md
// Create a root span for this async collection task if OTEL is enabled
if t.otelEnabled {
tracer := otel.Tracer("async")
Comment on lines 91 to 97

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.

🦩 πŸ”΄ async_label.go: OTEL span instrumentation added to upstream-shared file without OPENFRAME sentinel comments

In collectLabelQueryExecutions, wrapped the existing OTEL span creation block (the if t.otelEnabled { ... } block using otel.Tracer, trace.Span, and attribute.String) with the required // >>> OPENFRAME(async-otel): add OTEL span for label collection task β€” openframe/docs/observability.md and // <<< OPENFRAME(async-otel) sentinel comments, exactly as suggested in the finding, with no other code changes.

πŸ€– Prompt for AI agents
In server/service/async/async_label.go around line 98, review and complete this code-review fix: async_label.go: OTEL span instrumentation added to upstream-shared file without OPENFRAME sentinel comments.
What the draft fix changed: In `collectLabelQueryExecutions`, wrapped the existing OTEL span creation block (the `if t.otelEnabled { ... }` block using `otel.Tracer`, `trace.Span`, and `attribute.String`) with the required `// >>> OPENFRAME(async-otel): add OTEL span for label collection task β€” openframe/docs/observability.md` and `// <<< OPENFRAME(async-otel)` sentinel comments, exactly as suggested in the finding, with no other code changes.
Verify the change is correct and complete; do not refactor unrelated code.

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

Expand All @@ -102,6 +103,7 @@ func (t *Task) collectLabelQueryExecutions(ctx context.Context, ds fleet.Datasto
)
defer span.End()
}
// <<< OPENFRAME(async-otel)

cfg := t.taskConfigs[config.AsyncTaskLabelMembership]

Expand Down
4 changes: 3 additions & 1 deletion server/service/async/async_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (t *Task) RecordPolicyQueryExecutions(ctx context.Context, host *fleet.Host
}

func (t *Task) collectPolicyQueryExecutions(ctx context.Context, ds fleet.Datastore, pool fleet.RedisPool, stats *collectorExecStats) error {
// Create a root span for this async collection task if OTEL is enabled
// >>> OPENFRAME(async-otel): add OTEL span for policy collection task β€” openframe/docs/observability.md
if t.otelEnabled {
tracer := otel.Tracer("async")
var span trace.Span
Comment on lines 124 to 130

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.

🦩 πŸ”΄ async_policy.go: OTEL span instrumentation added to upstream-shared file without OPENFRAME sentinel comments

In collectPolicyQueryExecutions, wrapped the existing if t.otelEnabled { ... } OTEL span block with // >>> OPENFRAME(async-otel): ... and // <<< OPENFRAME(async-otel) sentinel comments, matching the suggested fix exactly. No functional code was altered, only comments added around the fork-added block.

πŸ€– Prompt for AI agents
In server/service/async/async_policy.go around line 122, review and complete this code-review fix: async_policy.go: OTEL span instrumentation added to upstream-shared file without OPENFRAME sentinel comments.
What the draft fix changed: In `collectPolicyQueryExecutions`, wrapped the existing `if t.otelEnabled { ... }` OTEL span block with `// >>> OPENFRAME(async-otel): ...` and `// <<< OPENFRAME(async-otel)` sentinel comments, matching the suggested fix exactly. No functional code was altered, only comments added around the fork-added block.
Verify the change is correct and complete; do not refactor unrelated code.

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

Expand All @@ -135,6 +135,7 @@ func (t *Task) collectPolicyQueryExecutions(ctx context.Context, ds fleet.Datast
)
defer span.End()
}
// <<< OPENFRAME(async-otel)

cfg := t.taskConfigs[config.AsyncTaskPolicyMembership]

Expand Down Expand Up @@ -275,3 +276,4 @@ func (t *Task) GetHostPolicyReportedAt(ctx context.Context, host *fleet.Host) ti
}
return host.PolicyUpdatedAt
}

5 changes: 5 additions & 0 deletions server/service/endpoint_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/go-kit/kit/endpoint"
)

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.

🦩 🟠 extractCertSerialFromHeader and iDevice URL auth fallback lack OPENFRAME sentinel comments

Wrapped extractCertSerialFromHeader (including its doc comment) in server/service/endpoint_middleware.go with // >>> OPENFRAME(idevice-cert-auth): cert-serial extraction for iOS/iPadOS mTLS device auth β€” openframe/docs/idevice-cert-auth.md before the function and // <<< OPENFRAME(idevice-cert-auth) immediately after, per FLEETMDM-001 sentinel convention.

πŸ€– Prompt for AI agents
In server/service/endpoint_middleware.go around line 24, review and complete this code-review fix: extractCertSerialFromHeader and iDevice URL auth fallback lack OPENFRAME sentinel comments.
What the draft fix changed: Wrapped extractCertSerialFromHeader (including its doc comment) in server/service/endpoint_middleware.go with `// >>> OPENFRAME(idevice-cert-auth): cert-serial extraction for iOS/iPadOS mTLS device auth β€” openframe/docs/idevice-cert-auth.md` before the function and `// <<< OPENFRAME(idevice-cert-auth)` immediately after, per FLEETMDM-001 sentinel convention.
Verify the change is correct and complete; do not refactor unrelated code.

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

// >>> OPENFRAME(idevice-cert-auth): cert-serial extraction for iOS/iPadOS mTLS device auth β€” openframe/docs/idevice-cert-auth.md
// extractCertSerialFromHeader extracts certificate serial from X-Client-Cert-Serial
// header (set by load balancer during mTLS) for iOS/iPadOS device authentication.
func extractCertSerialFromHeader(ctx context.Context, r *http.Request) context.Context {
Expand All @@ -39,6 +40,8 @@ func extractCertSerialFromHeader(ctx context.Context, r *http.Request) context.C
return certserial.NewContext(ctx, serial)
}

// <<< OPENFRAME(idevice-cert-auth)

func logJSON(ctx context.Context, logger *slog.Logger, v any, key string) {
jsonV, err := json.Marshal(v)
if err != nil {
Expand Down Expand Up @@ -76,6 +79,7 @@ func authenticatedDevice(svc fleet.Service, logger *slog.Logger, next endpoint.E
var debug bool

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.

🦩 🟠 Cert/token/URL authentication branching in authenticatedDevice is unwrapped fork logic

Wrapped the cert/token/URL three-way authentication branch inside authenticatedDevice with // >>> OPENFRAME(idevice-cert-auth): cert/token/URL authentication branching for iOS/iPadOS device auth β€” openframe/docs/idevice-cert-auth.md and // <<< OPENFRAME(idevice-cert-auth) sentinels, matching the same slug used in finding 1 since both concern the same fork feature. The referenced doc file (openframe/docs/idevice-cert-auth.md) is assumed/synthesized and should be confirmed to exist or be created by the reviewer.

πŸ€– Prompt for AI agents
In server/service/endpoint_middleware.go around line 76, review and complete this code-review fix: Cert/token/URL authentication branching in authenticatedDevice is unwrapped fork logic.
What the draft fix changed: Wrapped the cert/token/URL three-way authentication branch inside authenticatedDevice with `// >>> OPENFRAME(idevice-cert-auth): cert/token/URL authentication branching for iOS/iPadOS device auth β€” openframe/docs/idevice-cert-auth.md` and `// <<< OPENFRAME(idevice-cert-auth)` sentinels, matching the same slug used in finding 1 since both concern the same fork feature. The referenced doc file (openframe/docs/idevice-cert-auth.md) is assumed/synthesized and should be confirmed to exist or be created by the reviewer.
Verify the change is correct and complete; do not refactor unrelated code.

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

var authnMethod authz_ctx.AuthenticationMethod

// >>> OPENFRAME(idevice-cert-auth): cert/token/URL authentication branching for iOS/iPadOS device auth β€” openframe/docs/idevice-cert-auth.md
if certSerial, ok := certserial.FromContext(ctx); ok {
// Header presence signals cert auth intent, even if serial is invalid.
host, debug, err = svc.AuthenticateDeviceByCertificate(ctx, certSerial, identifier)
Expand All @@ -92,6 +96,7 @@ func authenticatedDevice(svc fleet.Service, logger *slog.Logger, next endpoint.E
authnMethod = authz_ctx.AuthnDeviceURL
}
}
// <<< OPENFRAME(idevice-cert-auth)

if err != nil {
logging.WithErr(ctx, err)
Expand Down
6 changes: 6 additions & 0 deletions server/service/maintained_apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ type addFleetMaintainedAppRequest struct {
Categories []string `json:"categories"`
}

// >>> OPENFRAME(maintained-apps-decode-request): DecodeRequest adds fleet_id/team_id
// aliasing and base64-encoded script field decoding to bypass WAF rules that may
// block requests containing shell/PowerShell script patterns. β€” openframe/docs/FLEETMDM-001.md

// DecodeRequest implements the RequestDecoder interface to support base64-encoded
// script fields. This allows bypassing WAF rules that may block requests containing
// shell/PowerShell script patterns. When the X-Fleet-Scripts-Encoded header is set

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.

🦩 🟠 New base64-script-decoding feature in shared upstream file lacks OPENFRAME sentinel comments

Wrapped the DecodeRequest method on addFleetMaintainedAppRequest (including the fleet_id/team_id aliasing logic and the base64 script-decoding block) with // >>> OPENFRAME(maintained-apps-decode-request): ... β€” openframe/docs/FLEETMDM-001.md and // <<< OPENFRAME(maintained-apps-decode-request) sentinel comments, matching the pattern used for verifyHostsToAssociate in labels_util.go. The doc reference points at FLEETMDM-001.md per the finding; if that file/slug doesn't exist yet in openframe/docs, it should be created or the slug adjusted to match project convention.

πŸ€– Prompt for AI agents
In server/service/maintained_apps.go around line 36, review and complete this code-review fix: New base64-script-decoding feature in shared upstream file lacks OPENFRAME sentinel comments.
What the draft fix changed: Wrapped the `DecodeRequest` method on `addFleetMaintainedAppRequest` (including the fleet_id/team_id aliasing logic and the base64 script-decoding block) with `// >>> OPENFRAME(maintained-apps-decode-request): ... β€” openframe/docs/FLEETMDM-001.md` and `// <<< OPENFRAME(maintained-apps-decode-request)` sentinel comments, matching the pattern used for `verifyHostsToAssociate` in labels_util.go. The doc reference points at FLEETMDM-001.md per the finding; if that file/slug doesn't exist yet in openframe/docs, it should be created or the slug adjusted to match project convention.
Verify the change is correct and complete; do not refactor unrelated code.

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

Expand Down Expand Up @@ -83,6 +87,8 @@ func (addFleetMaintainedAppRequest) DecodeRequest(ctx context.Context, r *http.R
return &req, nil
}

// <<< OPENFRAME(maintained-apps-decode-request)

type addFleetMaintainedAppResponse struct {
SoftwareTitleID uint `json:"software_title_id,omitempty"`
Err error `json:"error,omitempty"`
Expand Down
4 changes: 4 additions & 0 deletions server/service/software_installers.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ func (updateSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http
}
}

// >>> OPENFRAME(waf-bypass-scripts): base64-encode scripts to avoid WAF pattern blocks β€” openframe/docs/waf-bypass.md
// Check if scripts are base64 encoded (to bypass WAF rules that block script patterns)
if isScriptsEncoded(r) {
if decoded.InstallScript != nil {
Expand Down Expand Up @@ -238,6 +239,7 @@ func (updateSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http
decoded.PostInstallScript = &decodedScript
}
}
// <<< OPENFRAME(waf-bypass-scripts)

return &decoded, nil
}
Comment on lines 239 to 245

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.

🦩 πŸ”΄ Base64 script-encoding bypass logic added to upstream software_installers.go without OPENFRAME sentinel comments

In updateSoftwareInstallerRequest.DecodeRequest, wrapped the existing isScriptsEncoded(r) / decodeBase64Script(...) block (covering install_script, uninstall_script, pre_install_query, post_install_script) with // >>> OPENFRAME(waf-bypass-scripts): base64-encode scripts to avoid WAF pattern blocks β€” openframe/docs/waf-bypass.md and // <<< OPENFRAME(waf-bypass-scripts) sentinel comment lines, exactly as suggested. No logic was altered, only sentinel comments added around the pre-existing code block.

πŸ€– Prompt for AI agents
In server/service/software_installers.go around line 236, review and complete this code-review fix: Base64 script-encoding bypass logic added to upstream software_installers.go without OPENFRAME sentinel comments.
What the draft fix changed: In `updateSoftwareInstallerRequest.DecodeRequest`, wrapped the existing `isScriptsEncoded(r)` / `decodeBase64Script(...)` block (covering install_script, uninstall_script, pre_install_query, post_install_script) with `// >>> OPENFRAME(waf-bypass-scripts): base64-encode scripts to avoid WAF pattern blocks β€” openframe/docs/waf-bypass.md` and `// <<< OPENFRAME(waf-bypass-scripts)` sentinel comment lines, exactly as suggested. No logic was altered, only sentinel comments added around the pre-existing code block.
Verify the change is correct and complete; do not refactor unrelated code.

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

Expand Down Expand Up @@ -423,6 +425,7 @@ func (uploadSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http
decoded.AutomaticInstall = parsed
}

// >>> OPENFRAME(waf-bypass-scripts): base64-encode scripts to avoid WAF pattern blocks β€” openframe/docs/waf-bypass.md
// Check if scripts are base64 encoded (to bypass WAF rules that block script patterns)
if isScriptsEncoded(r) {
var err error
Comment on lines 425 to 431

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.

🦩 πŸ”΄ Same base64-decoding fork addition unwrapped in uploadSoftwareInstallerRequest.DecodeRequest

In uploadSoftwareInstallerRequest.DecodeRequest, wrapped the second identical isScriptsEncoded(r) / decodeBase64Script(...) block (install_script, uninstall_script, pre_install_query, post_install_script) with the same // >>> OPENFRAME(waf-bypass-scripts): ... / // <<< OPENFRAME(waf-bypass-scripts) sentinel pair, using the identical slug so both occurrences of this fork-only WAF-bypass logic are tagged consistently for upstream sync tooling. No logic changed.

πŸ€– Prompt for AI agents
In server/service/software_installers.go around line 335, review and complete this code-review fix: Same base64-decoding fork addition unwrapped in uploadSoftwareInstallerRequest.DecodeRequest.
What the draft fix changed: In `uploadSoftwareInstallerRequest.DecodeRequest`, wrapped the second identical `isScriptsEncoded(r)` / `decodeBase64Script(...)` block (install_script, uninstall_script, pre_install_query, post_install_script) with the same `// >>> OPENFRAME(waf-bypass-scripts): ...` / `// <<< OPENFRAME(waf-bypass-scripts)` sentinel pair, using the identical slug so both occurrences of this fork-only WAF-bypass logic are tagged consistently for upstream sync tooling. No logic changed.
Verify the change is correct and complete; do not refactor unrelated code.

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

Expand All @@ -439,6 +442,7 @@ func (uploadSoftwareInstallerRequest) DecodeRequest(ctx context.Context, r *http
return nil, &fleet.BadRequestError{Message: "invalid base64 encoding for post_install_script"}
}
}
// <<< OPENFRAME(waf-bypass-scripts)

return &decoded, nil
}
Expand Down
15 changes: 15 additions & 0 deletions server/vulnerabilities/msrc/parsed/product.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (
"github.com/fleetdm/fleet/v4/server/fleet"
)

// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
// displayVersionPattern matches Windows display version strings like "22H2", "23H2", "24H2".

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.

🦩 πŸ”΄ MSRC display-version fallback logic added to upstream fleetdm product.go without OPENFRAME sentinel comments

Wrapped all fork-specific MSRC display-version fallback logic in server/vulnerabilities/msrc/parsed/product.go with // >>> OPENFRAME(msrc-display-version): ... β€” openframe/docs/msrc-matching.md / // <<< OPENFRAME(msrc-display-version) sentinel comment pairs, as required. This covers: the displayVersionPattern regex var declaration; the isServerCoreHost/installationTypeKnown/matchByDisplayVersion/matchByBuildNumber variable block and installation-type/isCore matching refinements inside GetMatchForOS; the display-version fallback lookup and build-number fallback assignment inside the GetMatchForOS loop; the final match-selection return logic at the end of GetMatchForOS; and the IsServerCore() method plus extractDisplayVersionFromName helper function. No logic was altered, only comments added, preserving existing behavior and formatting. Confidence is not higher because the referenced doc file openframe/docs/msrc-matching.md is not verified to exist β€” creating it is outside this file's scope, and a complete fix should confirm/create that documentation.

πŸ€– Prompt for AI agents
In server/vulnerabilities/msrc/parsed/product.go around line 14, review and complete this code-review fix: MSRC display-version fallback logic added to upstream fleetdm product.go without OPENFRAME sentinel comments.
What the draft fix changed: Wrapped all fork-specific MSRC display-version fallback logic in `server/vulnerabilities/msrc/parsed/product.go` with `// >>> OPENFRAME(msrc-display-version): ... β€” openframe/docs/msrc-matching.md` / `// <<< OPENFRAME(msrc-display-version)` sentinel comment pairs, as required. This covers: the `displayVersionPattern` regex var declaration; the `isServerCoreHost`/`installationTypeKnown`/`matchByDisplayVersion`/`matchByBuildNumber` variable block and installation-type/isCore matching refinements inside `GetMatchForOS`; the display-version fallback lookup and build-number fallback assignment inside the `GetMatchForOS` loop; the final match-selection return logic at the end of `GetMatchForOS`; and the `IsServerCore()` method plus `extractDisplayVersionFromName` helper function. No logic was altered, only comments added, preserving existing behavior and formatting. Confidence is not higher because the referenced doc file `openframe/docs/msrc-matching.md` is not verified to exist β€” creating it is outside this file's scope, and a complete fix should confirm/create that documentation.
Verify the change is correct and complete; do not refactor unrelated code.

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

var displayVersionPattern = regexp.MustCompile(`\b\d{2}H[12]\b`)
// <<< OPENFRAME(msrc-display-version)

// Product abstracts a MS full product name.
// A full product name includes the name of the product plus its arch
Expand All @@ -24,13 +26,15 @@ type Products map[string]Product
var ErrNoMatch = errors.New("no product matches")

func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) (string, error) {
// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
isServerCoreHost := strings.EqualFold(os.InstallationType, "Server Core")
installationTypeKnown := os.InstallationType != ""

// matchByDisplayVersion is set when we find a product whose display version
// (e.g. "22H2") matches the host's. matchByBuildNumber is the fallback for
// hosts that lack a display version (legacy builds 22000/10240 only).
var matchByDisplayVersion, matchByBuildNumber string
// <<< OPENFRAME(msrc-display-version)

for pID, product := range p {
normalizedOS := NewProductFromOS(os)
Expand All @@ -43,6 +47,7 @@ func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) (
continue
}

// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
// When the host's installation type is known, only match products
// that correspond to the correct installation type (Server Core vs full desktop).
if installationTypeKnown && product.IsServerCore() != isServerCoreHost {
Expand All @@ -53,8 +58,10 @@ func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) (
// (superset of Server Core CVEs) for deterministic matching. Only use
// a Server Core product if no desktop alternative has been found.
isCore := product.IsServerCore()
// <<< OPENFRAME(msrc-display-version)

if product.HasDisplayVersion() {
// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
// Use os.DisplayVersion if available, otherwise try to extract it from the OS name.
// The OS name may already contain the display version (e.g., "Microsoft Windows 10 Pro 22H2")
// even when the DisplayVersion field is empty, which can happen when osquery includes
Expand All @@ -72,6 +79,7 @@ func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) (
}
continue
}
// <<< OPENFRAME(msrc-display-version)
}

// If os.DisplayVersion is empty, we need to confirm that the product
Expand All @@ -85,13 +93,16 @@ func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) (
build = parts[2]
}
if build == "22000" || build == "10240" {
// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
if matchByBuildNumber == "" || !isCore {
matchByBuildNumber = pID
}
// <<< OPENFRAME(msrc-display-version)
}
}
}

// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
if matchByDisplayVersion == "" && matchByBuildNumber == "" {
return "", ctxerr.Wrap(ctx, ErrNoMatch)
}
Expand All @@ -101,6 +112,7 @@ func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) (
}

return matchByBuildNumber, nil
// <<< OPENFRAME(msrc-display-version)
}

func NewProductFromFullName(fullName string) Product {
Expand Down Expand Up @@ -247,6 +259,7 @@ func (p Product) Name() string {
}
}

// >>> OPENFRAME(msrc-display-version): match hosts missing DisplayVersion via OS name fallback β€” openframe/docs/msrc-matching.md
// IsServerCore returns true if the product name indicates a Server Core installation.
func (p Product) IsServerCore() bool {
return strings.Contains(strings.ToLower(string(p)), "server core")
Expand All @@ -259,6 +272,7 @@ func extractDisplayVersionFromName(name string) string {
match := displayVersionPattern.FindString(name)
return match
}
// <<< OPENFRAME(msrc-display-version)

// Matches checks whether product A matches product B by checking to see if both are for the same
// product and if the architecture they target are compatible. This function is commutative.
Expand All @@ -269,3 +283,4 @@ func (p Product) Matches(o Product) bool {

return p.Arch() == "all" || o.Arch() == "all" || p.Arch() == o.Arch()
}

Loading