Skip to content

[New Integrationi] Anduril Lattice#20021

Open
tehbooom wants to merge 14 commits into
elastic:mainfrom
tehbooom:lattice
Open

[New Integrationi] Anduril Lattice#20021
tehbooom wants to merge 14 commits into
elastic:mainfrom
tehbooom:lattice

Conversation

@tehbooom

@tehbooom tehbooom commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Proposed commit message

Adds a new integration for the Anduril Lattice Common Operational Picture API. Collects entity lifecycle events (tracks, assets, geospatial zones, signals) via long-poll REST API with OAuth2 and static bearer token auth.

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

Author's Checklist

  • Verified working with Lattice Sandbox environment

How to test this PR locally

Need a developer account with Anduril to test

Screenshots

entity-dashboard-1 entity-dashboard-2 entity-dashboard-3

@tehbooom tehbooom requested a review from a team as a code owner July 7, 2026 18:54
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Elastic Docs Style Checker (Vale)

Summary: 1 warning found

⚠️ Warnings (1): Fix when the suggestion improves clarity or correctness.
File Line Rule Message
packages/anduril_lattice/data_stream/entity/fields/fields.yml 572 Elastic.Latinisms Latin terms and abbreviations are a common source of confusion. Use 'for example' instead of 'e.g'.

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.

@github-actions

This comment has been minimized.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Buildkite build 45655 failed the Check integrations anduril_lattice package step on commit ef2deab, but the PR has since advanced to b7ec98. The follow-up commit removes controlGroupJson from the Anduril Lattice saved search object, so rerun CI on the current head before changing anything else.

Remediation

  • Keep commit b7ec98a52e9a61116d1953218af7cb0ca2483198's removal of controlGroupJson from packages/anduril_lattice/kibana/search/anduril_lattice-75f003ff-aed4-4e6b-83b0-21583fcefaa3.json.
  • Rerun the Check integrations anduril_lattice Buildkite step on the current PR head.
  • If it still fails, inspect/upload the full package-check log or test-result XML; the prefetched log for this run only includes teardown and the final exit status.
Investigation details

Root Cause

The actionable failure line is missing from the available Buildkite log, but the failed build is stale relative to the current PR head:

  • Failed build 45655 ran .buildkite/scripts/test_one_package.sh packages/anduril_lattice origin/main ef2deab2958fa89cae87e24dc6eb8305f296280c.
  • The PR now includes b7ec98a52e9a61116d1953218af7cb0ca2483198 (fix: Remove controlGroupJson) after that failed commit.
  • At failed commit ef2deab, the saved search object had unsupported-looking controlGroupJson attributes at packages/anduril_lattice/kibana/search/anduril_lattice-75f003ff-aed4-4e6b-83b0-21583fcefaa3.json:13 and :55.
  • The current PR head removes both fields, and a repository-wide search of existing package saved searches found no other controlGroupJson usage under packages/**/kibana/search/*.json.

Evidence

  • Build: https://buildkite.com/elastic/integrations/builds/45655
  • Job/step: Check integrations anduril_lattice
  • Failed command: .buildkite/scripts/test_one_package.sh packages/anduril_lattice origin/main ef2deab2958fa89cae87e24dc6eb8305f296280c
  • Post-failure fix commit: b7ec98a52e9a61116d1953218af7cb0ca2483198
  • Key log excerpt from /tmp/gh-aw/buildkite-logs/integrations-check-integrations-anduril_lattice.txt:95-100:
--- [anduril_lattice] failed
^^^ +++
🚨 Error: The command exited with status 1
^^^ +++
user command error: exit status 1

Verification

  • Not run locally: the local checkout is not on the PR branch, and this package check requires the CI Elastic stack/Docker path while this environment notes Docker-in-Docker is unsupported.
  • Verified with PR commit metadata that b7ec98 was pushed after the failed ef2deab build, and confirmed the exact saved-object diff removes only the two controlGroupJson attributes.

Follow-up

If Buildkite still fails on b7ec98, the next investigation needs the full elastic-package failure output or uploaded test-result XML because the prefetched job log does not include the package validation error itself.


What is this? | From workflow: PR Buildkite Detective

Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

@andrewkroh andrewkroh added New Integration Issue or pull request for creating a new integration package. documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. labels Jul 7, 2026
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

@teresaromero teresaromero 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.

for Vale linting fixes you van use the skill on this repository for the agents to update the readmes according to the elastic Vale style

Comment thread packages/anduril_lattice/manifest.yml Outdated
Comment thread packages/anduril_lattice/_dev/build/build.yml Outdated
resource.timeout: {{http_client_timeout}}
{{/if}}
resource.url: {{url}}
state:

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.

The manifest/README claim OAuth2 tokens are auto-refreshed with a 30-minute lifetime, but the program never actually caches one: the state.?client_id check on line 29 only picks the auth mode (OAuth2 vs. static token), and the fetched auth.token is never written back into state (the state.with(...) returns on lines 56/69 only set events/cursor/want_more). So every poll re-authenticates from scratch — at the default 5s interval, ~720 token exchanges/hour instead of one per 30 minutes.

Per the Filebeat CEL input docs (https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-cel.html), plain state fields persist across poll intervals for the life of the input, so caching is safe here. packages/cyera/data_stream/datastore/agent/stream/cel.yml.hbs (https://github.com/elastic/integrations/blob/main/packages/cyera/data_stream/datastore/agent/stream/cel.yml.hbs) already does this via has(state.?next.expiry) && timestamp(state.next.expiry) > now, reusing state.next.access_token when still valid. Worth the same pattern here.

- sandbox_token
program: |-
state.with(
(state.?client_id.orValue("") != "") ?

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.

Suggested change
(state.?client_id.orValue("") != "") ?
has(state.client_id) ?

Comment on lines +34 to +45
request(
"POST",
state.url.trim_right("/") + "/api/v1/oauth/token"
).with(
{
"Header": {"Content-Type": ["application/json"]},
"Body": {
"client_id": state.client_id,
"client_secret": state.client_secret,
}.encode_json(),
}
).do_request().as(tok_resp,

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.

Suggested change
request(
"POST",
state.url.trim_right("/") + "/api/v1/oauth/token"
).with(
{
"Header": {"Content-Type": ["application/json"]},
"Body": {
"client_id": state.client_id,
"client_secret": state.client_secret,
}.encode_json(),
}
).do_request().as(tok_resp,
post_request(
state.url.trim_right("/") + "/api/v1/oauth/token",
"application/json",
{
"client_id": state.client_id,
"client_secret": state.client_secret,
}.encode_json()
).do_request().as(tok_resp,

(tok_resp.StatusCode == 200) ?
tok_resp.Body.decode_json().as(tok_body,
{
"token": string(tok_body.access_token),

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.

Suggested change
"token": string(tok_body.access_token),
"token": tok_body.access_token,

But why is this being kept twice?

)
)
:
{"token": state.?token.orValue("")}

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.

Suggested change
{"token": state.?token.orValue("")}
{?"token": state.?token}

Comment on lines +76 to +97
request(
"POST",
state.url.trim_right("/") + "/api/v1/entities/events"
).with(
{
"Header": {
"Content-Type": ["application/json"],
?"Authorization": (state.token != "") ?
optional.of(["Bearer " + state.token])
:
optional.none(),
?"Anduril-Sandbox-Authorization": (state.?sandbox_token.orValue("") != "") ?
optional.of(["Bearer " + state.sandbox_token])
:
optional.none(),
},
"Body": {
"sessionToken": state.?cursor.session_token.orValue(""),
"batchSize": int(state.batch_size),
}.encode_json(),
}
).do_request().as(resp,

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.

Suggested change
request(
"POST",
state.url.trim_right("/") + "/api/v1/entities/events"
).with(
{
"Header": {
"Content-Type": ["application/json"],
?"Authorization": (state.token != "") ?
optional.of(["Bearer " + state.token])
:
optional.none(),
?"Anduril-Sandbox-Authorization": (state.?sandbox_token.orValue("") != "") ?
optional.of(["Bearer " + state.sandbox_token])
:
optional.none(),
},
"Body": {
"sessionToken": state.?cursor.session_token.orValue(""),
"batchSize": int(state.batch_size),
}.encode_json(),
}
).do_request().as(resp,
request(
"POST",
state.url.trim_right("/") + "/api/v1/entities/events",
{
?"sessionToken": state.?cursor.session_token,
"batchSize": int(state.batch_size),
}.encode_json()
).with(
{
"Header": {
"Content-Type": ["application/json"],
?"Authorization": state.token.optMap(t, ["Bearer " + t]),
?"Anduril-Sandbox-Authorization": state.?sandbox_token.optMap(t, ["Bearer " + t]),.orValue("") != ""),
}
).do_request().as(resp,

"version": 2,
"visualizationType": "lnsXY"
},
"title": "Diposition Distribution"

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.

Suggested change
"title": "Diposition Distribution"
"title": "Disposition Distribution"

"layers": {}
}
},
"filters": [],

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 should have a filter to restrict it to the data stream.

},
"zoom": 3.08
},
"title": "[Anduril Lattice] Entity Map",

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.

Suggested change
"title": "[Anduril Lattice] Entity Map",
"title": "Entity Map",

Already in the dashboard.

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.

Add titles to the metrics panels.

Add layer-level queries to the maps so that if the map query is cleared we don't get all logs-*.

Comment thread packages/anduril_lattice/LICENSE.txt Outdated

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.

We don't need this; it will be injected.

@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

✅ All changelog entries have the correct PR link.

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

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. New Integration Issue or pull request for creating a new integration package.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants