Skip to content

[snowflake] Add Support for query_history, events, and external_access_history Data Streams - #22142

Merged
mohitjha-elastic merged 10 commits into
elastic:mainfrom
mohitjha-elastic:snowflake-batch-3
Oct 28, 2026
Merged

mohitjha-elastic merged 10 commits into
elastic:mainfrom
mohitjha-elastic:snowflake-batch-3

Conversation

@mohitjha-elastic

@mohitjha-elastic mohitjha-elastic commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Proposed commit message

snowflake: add support for query_history, events, and external_access_history data streams.

This release includes query_history, events, and external_access_history data streams.
The fields are mapped to their corresponding ECS fields where possible.
Field Schemas and Test samples were derived from live data samples and documentation[1], which
were subsequently sanitized.
Bumped the minimum kibana constraint to 9.4.0.

[1] https://docs.snowflake.com/en/sql-reference/snowflake-db

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

How to test this PR locally

To test the integration:

  • Clone integrations repo.
  • Install elastic package locally.
  • Start elastic stack using elastic-package.
  • Move to integrations/packages/snowflake directory.
  • Run the following command to run tests.

elastic-package test -v

Screenshots

image image image image image

@mohitjha-elastic mohitjha-elastic self-assigned this Oct 23, 2026
Copilot AI balanced review requested due to automatic review settings October 23, 2026 12:03
@mohitjha-elastic
mohitjha-elastic requested review from a team as code owners October 23, 2026 12:03
@mohitjha-elastic mohitjha-elastic added enhancement New feature or request Team:Security-Service Integrations Security Service Integrations team [elastic/security-service-integrations] Team:SDE-Crest Crest developers on the Security Integrations team [elastic/sit-crest-contractors] Integration:snowflake Snowflake labels Oct 23, 2026
@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

Pinging @elastic/security-service-integrations (Team:Security-Service Integrations)

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

✅ Elastic Docs Style Checker (Vale)

No issues found on modified lines!


The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved pagination and ingest issues can stall collection or silently discard distinct records and log content.

6 open issues
What changed in this PR

Extends the Snowflake integration with SQL query history, handler logs, and external network-access telemetry collected through the SQL API.

Changes:

  • Adds three data streams with collectors, ingest pipelines, field mappings, sample events, and tests.
  • Adds saved searches and a Handler Event Logs dashboard.
  • Updates setup documentation, release notes, screenshots, and the minimum Kibana version to 9.4.
File Description
packages/​snowflake/​manifest.yml Updates version, compatibility, screenshots, and collection description.
packages/​snowflake/​kibana/​search/​snowflake-c86d2fd9-8bd0-48a3-9e72-a6251556a68b.json Adds the Suspicious Query Activity search.
packages/​snowflake/​kibana/​search/​snowflake-4a191f01-6f92-49cd-b82a-aafba5b2de57.json Adds the External Data Access Events search.
packages/​snowflake/​kibana/​search/​snowflake-37d8053b-f615-4cd0-85b8-53a0def440ef.json Adds the Failed Queries search.
packages/​snowflake/​kibana/​search/​snowflake-1bcb2507-6a66-4929-940b-ca55e277ccae.json Adds the Handler Log Essential Details search.
packages/​snowflake/​kibana/​dashboard/​snowflake-6462c3e6-8189-4f28-afb4-19120fe464eb.json Adds handler-log metrics, charts, filters, and navigation.
packages/​snowflake/​data_stream/​query_history/​sample_event.json Documents a processed query event.
packages/​snowflake/​data_stream/​query_history/​manifest.yml Defines query-history collection settings.
packages/​snowflake/​data_stream/​query_history/​fields/​fields.yml Defines Snowflake-specific query fields.
packages/​snowflake/​data_stream/​query_history/​fields/​ecs.yml Declares observer and related-user fields.
packages/​snowflake/​data_stream/​query_history/​fields/​beats.yml Declares input metadata.
packages/​snowflake/​data_stream/​query_history/​fields/​base-fields.yml Defines dataset and timestamp fields.
packages/​snowflake/​data_stream/​query_history/​elasticsearch/​ingest_pipeline/​default.yml Parses query records and maps ECS fields.
packages/​snowflake/​data_stream/​query_history/​agent/​stream/​cel.yml.hbs Implements query-history polling and pagination.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​system/​test-default-config.yml Configures default collection testing.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​system/​test-continuation-config.yml Configures small-batch continuation testing.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-success-select.log-expected.json Defines expected successful-query output.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-success-select.log Supplies a successful-query fixture.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-missing-optional.log-expected.json Defines output with optional fields absent.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-missing-optional.log Supplies a minimal query fixture.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-iso8601.log-expected.json Defines ISO 8601 timestamp parsing output.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-iso8601.log Supplies an ISO 8601 query fixture.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-incident.log-expected.json Defines expected incident-query output.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-incident.log Supplies an incident-query fixture.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-grant.log-expected.json Defines grant-query categorization output.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-grant.log Supplies a privilege-grant fixture.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-fail.log-expected.json Defines expected failed-query output.
packages/​snowflake/​data_stream/​query_history/​_dev/​test/​pipeline/​test-query-history-fail.log Supplies a failed-query fixture.
packages/​snowflake/​data_stream/​external_access_history/​sample_event.json Documents a processed external-access event.
packages/​snowflake/​data_stream/​external_access_history/​manifest.yml Defines external-access collection settings.
packages/​snowflake/​data_stream/​external_access_history/​fields/​fields.yml Defines access-status and invalid-IP fields.
packages/​snowflake/​data_stream/​external_access_history/​fields/​ecs.yml Declares observer, related-entity, and cloud fields.
packages/​snowflake/​data_stream/​external_access_history/​fields/​beats.yml Declares input metadata.
packages/​snowflake/​data_stream/​external_access_history/​fields/​base-fields.yml Defines dataset and timestamp fields.
packages/​snowflake/​data_stream/​external_access_history/​elasticsearch/​ingest_pipeline/​default.yml Maps network access and enriches destination IPs.
packages/​snowflake/​data_stream/​external_access_history/​agent/​stream/​cel.yml.hbs Collects access records joined to query history.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​system/​test-default-config.yml Configures default collection testing.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​system/​test-continuation-config.yml Configures small-batch continuation testing.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-success.log-expected.json Defines successful-access output.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-success.log Supplies a successful-access fixture.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-non-ip.log-expected.json Defines invalid-IP fallback output.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-non-ip.log Supplies an invalid-IP fixture.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-missing-optional.log-expected.json Defines output with optional fields absent.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-missing-optional.log Supplies a minimal access fixture.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-deny.log-expected.json Defines denied-access output.
packages/​snowflake/​data_stream/​external_access_history/​_dev/​test/​pipeline/​test-external-access-deny.log Supplies a denied-access fixture.
packages/​snowflake/​data_stream/​events/​sample_event.json Documents a processed handler log.
packages/​snowflake/​data_stream/​events/​manifest.yml Defines event-table collection settings.
packages/​snowflake/​data_stream/​events/​fields/​fields.yml Defines Snowflake telemetry attributes.
packages/​snowflake/​data_stream/​events/​fields/​ecs.yml Declares observer and related-entity fields.
packages/​snowflake/​data_stream/​events/​fields/​beats.yml Declares input metadata.
packages/​snowflake/​data_stream/​events/​fields/​base-fields.yml Defines dataset and timestamp fields.
packages/​snowflake/​data_stream/​events/​elasticsearch/​ingest_pipeline/​default.yml Parses handler logs and drops non-log records.
packages/​snowflake/​data_stream/​events/​agent/​stream/​cel.yml.hbs Implements event-table polling and pagination.
packages/​snowflake/​data_stream/​events/​_dev/​test/​system/​test-default-config.yml Configures collection and log-only count assertions.
packages/​snowflake/​data_stream/​events/​_dev/​test/​system/​test-continuation-config.yml Configures small-batch event collection testing.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-log.log-expected.json Defines expected handler-log output.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-log.log Supplies informational and error log fixtures.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-log-iso8601.log-expected.json Defines ISO 8601 handler-log output.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-log-iso8601.log Supplies an ISO 8601 handler-log fixture.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-log-container.log-expected.json Defines container and cloud metadata output.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-log-container.log Supplies a container-log fixture.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-drop-non-log.log-expected.json Expects non-log records to be dropped.
packages/​snowflake/​data_stream/​events/​_dev/​test/​pipeline/​test-events-drop-non-log.log Supplies metric and span fixtures.
packages/​snowflake/​changelog.yml Records the new streams and dashboards.
packages/​snowflake/​_dev/​build/​docs/​README.md Documents collection, permissions, and new datasets.

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 23, 2026 12:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@qcorporation qcorporation added the documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. label Oct 23, 2026
Copilot AI balanced review requested due to automatic review settings October 26, 2026 07:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Event fingerprinting and JSON message handling can silently discard distinct logs or their content.

6 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Include source context in log document IDs

packages/​snowflake/​data_stream/​events/​elasticsearch/​ingest_pipeline/​default.yml:51

These three fields produce the same _id for distinct logs that share a timestamp and message, even when they belong to different snow.query.id values or executables. Consequently, one document is rejected as a duplicate even when both rows arrive in the same result page. Include the remaining source/record context in the fingerprint so deduplication removes replayed rows rather than unrelated handler logs.

Medium severity Preserve unrecognized JSON handler messages

packages/​snowflake/​data_stream/​events/​elasticsearch/​ingest_pipeline/​default.yml:100

A JSON-formatted handler message such as {"operation":"sync","result":"failed"} becomes a Map here, but the later message processors only handle Maps with formattedMessage or non-Map values. Cleanup then deletes the payload, losing the message content when original-event preservation is disabled. Parse into a temporary field and replace VALUE only for recognized Openflow envelopes, leaving other messages unchanged for the existing fallback.

Review effort: Balanced

@kcreddy kcreddy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mohitjha-elastic, some vera bot comments seem valid. I only verified one of them: https://github.com/elastic/integrations/pull/22142/changes#r4359434145.

Can you address them (thumbsup/down + resolve/addcomment as relevant)? I will take a look once Vera's are addressed.

Copilot AI balanced review requested due to automatic review settings October 27, 2026 09:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elastic-vault-github-plugin-prod

elastic-vault-github-plugin-prod Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

Copilot AI balanced review requested due to automatic review settings October 28, 2026 06:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The attribute merge can silently discard nested custom values when scalar and dotted keys conflict; normalize conflicting subtrees and add regression coverage for an undocumented prefix.

1 open issue
1 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 28, 2026 07:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues block the Snowflake telemetry expansion.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@mohitjha-elastic

Copy link
Copy Markdown
Contributor Author

@kcreddy All vera-bot and Copilot comments have been addressed. Please feel free to review the PR when you have some time.

Comment thread packages/snowflake/manifest.yml Resolved
Comment thread packages/snowflake/manifest.yml Resolved
return;
}
ctx.destination = ctx.destination ?: [:];
ctx.destination.domain = parts[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what this script description says, only A single hostname is mapped to destination.domain.

But, if you do ctx.destination.domain = parts[0]; it carries destination.domain unconditionally.

If you intend as per description:

if (parts.size() == 1) {
  ctx.destination = ctx.destination ?: [:];
  ctx.destination.domain = parts[0];
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destination.domain is a single-value ECS field, so the first hostname is always mapped, and every hostname still goes to related.hosts. Multi-value lists also keep the raw vendor field (the later remove only runs when the vendor value equals that single domain). I updated the script description to match that.

"version": 2,
"visualizationType": "lnsHeatmap"
},
"title": "Off-Hours Login Activity (UTC)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ESQL one doesn't have a WHERE claude which makes it Off-Hours. Is this intended?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is Intended. The heatmap is the full weekday/hour grid so off-hours cells are visible against business-hours activity. A WHERE on off-hours would leave a sparse grid and hide that contrast. The panel title is “Off-Hours Login Activity (UTC)” in that sense — it highlights unusual hours rather than filtering to them.

Copilot AI balanced review requested due to automatic review settings October 28, 2026 09:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed for unpublished findings involving pagination cursor loss during throttling and misclassification of security-sensitive user changes.

No open issues 🎉

Review effort: Balanced

@vera-review-bot

Copy link
Copy Markdown
Contributor

Review summary

Issues found across the latest commits 0387d92 — 2 low
  • 🔵 If RESOURCE_ATTRIBUTES, SCOPE, RECORD or RECORD_ATTRIBUTES fails to parse as JSON, the raw string is still renamed into an object-mapped snowflake.events.* field, so Elasticsearch rejects the document. Guard the four renames on instanceof Map (or drop the unparsed column in each on_failure). (link)
  • 🔵 snowflake.events.resource_attributes.k8s.container.name is now always removed after it is copied to container.name, but events/fields.yml (and the README field table) still declare it. Delete that leaf, keep restart_count, and rebuild the README. (link)
Issues found across earlier commits 03edd7e — 1 high

Package-level:

  • 🟠 The new events, query_history and external_access_history pipeline test directories have no test-common-config.yml. Add one per stream that sets the preserve_original_event tag.

    Add _dev/test/pipeline/test-common-config.yml to each of the three new data streams, then regenerate the expected outputs with elastic-package test pipeline --data-streams events,query_history,external_access_history --generate:

    fields:
      tags:
        - preserve_original_event
Issues found across earlier commits 077b2a4 — 1 medium, 1 low
  • 🟡 The events keyset compares the SQL value COALESCE(TO_VARCHAR(VALUE), '') with a cursor last_value copied from the API cell for the VARIANT VALUE column, and these two strings can differ. Build the tie-break key in SQL, either by folding VALUE into ROW_KEY or by returning a TO_VARCHAR(VALUE) key column. (link) (Outdated)
  • 🔵 The 'lag-window resume' TIEBREAK mock rule can never match, because the earlier 16:00:00.123002000 empty-page rule also matches the lag request. Move this rule above that one, or anchor the 123002000 rule on binding 1. (link) (Outdated)
Issues found across earlier commits e81b3b1 — 6 medium, 4 low
  • 🟡 events/fields.yml declares many fields that only SPAN, SPAN_EVENT, METRIC and EVENT rows carry, but the pipeline drops every non-LOG row, so nothing ever writes them. Remove these declarations, or stop dropping those row types. (link) (Outdated)
  • 🟡 The events _id fingerprint uses only TIMESTAMP, RECORD_TYPE and VALUE, so separate LOG rows with the same message in the same millisecond get the same _id and all but one are rejected. Add the per-row context columns to the fingerprint. (link)
  • 🟡 host.name is set to the external destination hostname, which duplicates destination.domain and misuses the ECS host field. Drop the host.name set and populate related.hosts from destination.domain. (link) (Outdated)
  • 🟡 No events fixture covers the Openflow structured-VALUE branch (formattedMessage, throwable, mdc) or the malformed-JSON VALUE fallback. Add fixtures for both. (link)
  • 🟡 Handler-defined RECORD_ATTRIBUTES keys are indexed unmapped under snowflake.events.record_attributes, which risks mapping conflicts and field-count growth. Route undocumented keys into a flattened field. (link) (Outdated)
  • 🔵 set_event_duration runs whenever TOTAL_ELAPSED_TIME is non-null, even after the convert to long has failed, so a bad value turns the document into a pipeline_error. Guard the script on a numeric type. (link) (Outdated)
  • 🔵 The mock rules for the empty page after the last LIMIT 2 page can never match, because their regexes expect the table name before the binding timestamp. Make the timestamp-first ordering the matching alternative, as the 09:00 rules do. (link) (Outdated)
  • 🔵 The lag-window cursor is parsed with the strict -0700 layout, while the package's newer streams parse with Z0700. Use Z0700 so a Z-suffixed cursor cannot stall the stream. (link) (Outdated)
  • 🔵 Non-LOG event-table rows are dropped only after the fingerprint, five JSON parses, three dot_expanders and three date parses. Move the RECORD_TYPE drop to just after parse_json. (link) (Outdated)

Package-level:

  • 🟡 test-common-config.yml is missing from the new events, query_history and external_access_history pipeline test directories. Add one to each with tags: [preserve_original_event].

    Add test-common-config.yml to each of the three new pipeline test directories, then regenerate the expected outputs:

    fields:
      tags:
        - preserve_original_event

A new commit triggers another review — at most once every 15 minutes. I skip the PR while it's approved or has merge conflicts.

🤖 AI-Generated Review | Vera Review Bot - v0.4.3 | 📚 Knowledge base: integration-skills

⚠️ Automated review — verify suggestions before applying.

@kcreddy kcreddy left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks! See the latest bot comments if applicable

Copilot AI balanced review requested due to automatic review settings October 28, 2026 10:26
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

✅ All changelog entries have the correct PR link.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human assessment is needed because pagination and watermark interactions can replay processed results during rate-limited retries or permanently skip late-arriving rows within the configured lag window.

No open issues 🎉

Review effort: Balanced

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

cc @mohitjha-elastic

@mergify

mergify Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again.

@mohitjha-elastic
mohitjha-elastic merged commit 4c549d8 into elastic:main Oct 28, 2026
17 checks passed
@mohitjha-elastic
mohitjha-elastic deleted the snowflake-batch-3 branch October 28, 2026 11:16
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

Package snowflake - 0.3.0 containing this change is available at https://epr.elastic.co/package/snowflake/0.3.0/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. enhancement New feature or request Integration:snowflake Snowflake Team:SDE-Crest Crest developers on the Security Integrations team [elastic/sit-crest-contractors] Team:Security-Service Integrations Security Service Integrations team [elastic/security-service-integrations]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants