Repository navigation
Add hot-path indexes and attribute osquery log batches to the authenticated node - #1072
Merged
Merged
Conversation
This was referenced Oct 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add hot-path indexes and attribute osquery log batches to the authenticated node
Indexes
Adds 13 secondary indexes, each backing a query verified to run on every poll or check-in:
osquery_nodesenvironment;hostname;localnamenode_queriesquery_id, statusdistributed_queriesenvironment_id, type, created_atosquery_status_data/osquery_result_datauuid, created_atosquery_query_dataname, created_ataudit_logscreated_atcarved_filesenvironment_id, query_nametagged_nodesnode_id;admin_tag_idThese are created by a new
dbutil.EnsureIndexeshelper rather than GORM struct tags. On MySQL, tagging an existing untagged string column flips its type fromlongtexttovarchar(191), andAutoMigratethen ALTERs the column on every install. That rebuilds the table, and fails or truncates on values longer than 191 characters.How the helper builds them:
CREATE INDEX CONCURRENTLY, so writes are never blocked. An invalid index left by an interrupted build is dropped and rebuilt, unless another session is still building it.TEXTon the live schema; a prefix on a shortvarcharis an error.last_seen,ip_addressandbytes_receivedare deliberately left unindexed. Every check-in rewrites them, and keeping them out of indexes preserves Postgres HOT updates. A guard test enforces this.Security: log batches trusted the sender-written
hostIdentifierosctrl-tls authenticates each log POST by
node_key, but then attributed the batch to thehostIdentifierinside it, which the sender controls. Any enrolled node could:bytes_receivedProcessLogsnow takes the authenticated node and uses it for:UpdateMetadata(nodeID, …)by primary keyAlertMatcher.MatchResultLogs/MatchStatusLogsnow take the sender's UUIDExternal sinks still receive the raw batch, whose entries contain the sender-written
hostIdentifier. Consumers should key on the exporter-supplied identity.Also fixed
Alert detail for status logs was chosen via Go map iteration. The node page's "errors reported by this node" preset therefore reported an empty detail ~25% of the time, and its test was flaky (8/30 failures). Fields are now matched in a fixed order (message → filename → version); 0/200 failures.
Validation
go build ./...,go vet ./...clean; all packages passgo test ./....golangci-lintreports only a pre-existing goimports issue inpkg/queries/events_test.go.osquery_nodesOSCTRL_TEST_POSTGRES_DSN/OSCTRL_TEST_MYSQL_DSN; run with:Notes for reviewers
uuidindexes on the status/result log tables are now redundant with the new(uuid, created_at)ones. They're left in place because dropping the struct tag would trigger the MySQL column-type ALTER described above.