From 2e58aabeeee86b76922ca4779461ce50428faba0 Mon Sep 17 00:00:00 2001 From: Ian Littman Date: Mon, 23 Jun 2025 21:09:55 -0500 Subject: [PATCH] Avoid unnecessary prepared statements in "select config from team" uncached queries (#30206) For #30199. This is one of a few approaches to mitigate the issue the customer is seeing. This is SQLi-safe because we're dealing with an unsigned int parameter, sprintf'd %d. Existing tests fully cover this path. # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements) - [ ] Manual QA for all new/changed functionality --- changes/30199-stmt-tweak | 1 + server/datastore/mysql/teams.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 changes/30199-stmt-tweak diff --git a/changes/30199-stmt-tweak b/changes/30199-stmt-tweak new file mode 100644 index 0000000000..c0b289f0fa --- /dev/null +++ b/changes/30199-stmt-tweak @@ -0,0 +1 @@ +* Improved performance when pulling team settings on osquery config and distributed read endpoints diff --git a/server/datastore/mysql/teams.go b/server/datastore/mysql/teams.go index 568efeaf70..70a2af1568 100644 --- a/server/datastore/mysql/teams.go +++ b/server/datastore/mysql/teams.go @@ -394,9 +394,9 @@ func amountTeamsDB(ctx context.Context, db sqlx.QueryerContext) (int, error) { // TeamAgentOptions loads the agents options of a team. func (ds *Datastore) TeamAgentOptions(ctx context.Context, tid uint) (*json.RawMessage, error) { - sql := `SELECT config->'$.agent_options' FROM teams WHERE id = ?` + stmt := fmt.Sprintf(`SELECT config->'$.agent_options' FROM teams WHERE id = %d`, tid) // safe because uint var agentOptions *json.RawMessage - if err := sqlx.GetContext(ctx, ds.reader(ctx), &agentOptions, sql, tid); err != nil { + if err := sqlx.GetContext(ctx, ds.reader(ctx), &agentOptions, stmt); err != nil { return nil, ctxerr.Wrap(ctx, err, "select team") } return agentOptions, nil @@ -408,9 +408,9 @@ func (ds *Datastore) TeamFeatures(ctx context.Context, tid uint) (*fleet.Feature } func teamFeaturesDB(ctx context.Context, q sqlx.QueryerContext, tid uint) (*fleet.Features, error) { - sql := `SELECT config->'$.features' as features FROM teams WHERE id = ?` + stmt := fmt.Sprintf(`SELECT config->'$.features' as features FROM teams WHERE id = %d`, tid) // safe due to uint var raw *json.RawMessage - if err := sqlx.GetContext(ctx, q, &raw, sql, tid); err != nil { + if err := sqlx.GetContext(ctx, q, &raw, stmt); err != nil { return nil, ctxerr.Wrap(ctx, err, "get team config features") }