Skip to content

[Security Solution] Register Workflows with Inbox#266256

Open
spong wants to merge 11 commits intoelastic:mainfrom
spong:inbox-plus-workflows
Open

[Security Solution] Register Workflows with Inbox#266256
spong wants to merge 11 commits intoelastic:mainfrom
spong:inbox-plus-workflows

Conversation

@spong
Copy link
Copy Markdown
Member

@spong spong commented Apr 29, 2026

Summary

Introduces Inbox ↔ Workflows as a first-class integration so that any waitForInput step in a Workflow surfaces as a schema-driven, schema-validated action in the shared Inbox plugin, with a responsive flyout for human resolution. Lays the platform rails (registry, common contracts, privilege model, space scoping, demo fixtures) so future providers can plug in with zero additional Inbox work.

Plugin introduced in #265634, and with this changeset data now comes from real workflows!

Plugin is disabled by default, so enable via:

xpack.inbox.enabled: true

And populate sample workflows exercising each schema variation with:

KIBANA_URL=http://localhost:5601 \
  KIBANA_USERNAME=elastic \
  KIBANA_PASSWORD=changeme \
  KIBANA_SPACE_ID=default \
  node --import tsx x-pack/platform/plugins/shared/inbox/scripts/demo/seed_inbox_demo.ts

(or using this branch of the example-mcp-app-security. All setup details in /inbox/scripts/demo/README.md)

Complete with support for dynamic response actions:

What's in this PR

Inbox plugin — provider platform

  • InboxActionProvider contract (x-pack/platform/plugins/shared/inbox/server/services/inbox_action_provider.ts) — the registration shape plugins implement to contribute items to the Inbox.
  • InboxActionRegistry — fan-out / merge-sort / pagination across providers, with a clamped total so a provider truncating its response can never desync the UI's pager. Logs a warning on truncation.
  • Routes
    • GET /internal/inbox/actions — list + filter (status, source_app, pagination)
    • POST /internal/inbox/actions/{source_app}/{source_id}/respond — schema-validated respond path
  • Security
    • Split API privileges inbox_read / inbox_respond so the read feature role cannot invoke the respond route (previously collapsed under a single api: [PLUGIN_ID]).
    • Dynamic space resolution via the spaces plugin — no more hardcoded 'default' leaking rows across spaces. Falls back to 'default' only when spaces is absent (single-space installs).
  • Public app hardening
    • Lazy detail-renderer loader catches chunk-load / module-init failures and falls back to the default form instead of crashing the tree.
    • TimeoutChip guards against malformed timeout_at so it can't render NaNh NaNm.
    • SchemaForm accessibility pass: label fallbacks to field name, visual * required marker, hasChildLabel={false} for EuiSwitch rows, localized select placeholder.
  • React-Query tuning (public/application.tsx): refetchOnWindowFocus: 'always' + refetchOnMount: 'always' with a 30s staleTime dedupe window so the list is always current when the tab/app regains focus, plus locked-in invalidateQueries on the respond mutation so responded items drop off the list without a manual refresh.

Workflows-management — Inbox provider

  • New WorkflowsInboxProvider (src/platform/plugins/shared/workflows_management/server/inbox/) converts paused waitForInput steps into InboxActions (to_inbox_action.ts) and registers with the Inbox plugin at setup.
  • New WorkflowExecutionQueryService#listWaitingForInputSteps to fan-out across the executions index for paused steps (filtered by spaceId + status: waiting_for_input); WorkflowsManagementService exposes it via the same-name delegating method consistent with the rest of the facade. Wire-level regression tests live in workflow_execution_query_service.test.ts (term-only query / pagination math / index_not_found_exception swallowed / log+rethrow), with a delegation test in the facade suite.

Common contracts (@kbn/inbox-common)

  • OpenAPI / Zod schemas for the list and respond routes, including status, source_app, input_schema, submission_channel, and timeout_at.
  • Helper buildRespondToActionUrl(sourceApp, sourceId) with proper URL-encoding for composite source IDs.
  • Privilege constants INBOX_API_PRIVILEGE_READ / INBOX_API_PRIVILEGE_RESPOND.

Demo fixtures

  • x-pack/platform/plugins/shared/inbox/scripts/demo/:
    • Six minimal workflow YAMLs covering the field-type matrix (string / number / boolean / single-enum / array-of-enum / required+defaults).
    • seed_inbox_demo.ts — dependency-light fetch script that imports + triggers each workflow against a running Kibana so the Inbox populates immediately.
    • README.md with run instructions and the matching MCP-app generate-inbox-data flow.

FTR wiring

  • New stateful FTR config x-pack/platform/test/inbox_api_integration/config.ts opt-in via --xpack.inbox.enabled=true.
  • inbox_flow.ts — contract-level coverage (empty-registry list, query validation, 404 on unknown source, 400 on missing input). Live-workflow lifecycle assertions are stubbed as describe.skip with TODOs pointing at the Workflows execution-engine harness work.
  • Registered in .buildkite/ftr_platform_stateful_configs.yml and .github/CODEOWNERS.

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.


PR developed with Cursor + Claude Opus 4.7 Super Duper xHigh Thinking++

@spong spong requested a review from andrew-goldstein April 29, 2026 05:33
@spong spong self-assigned this Apr 29, 2026
@spong spong requested review from a team as code owners April 29, 2026 05:33
@spong spong added the release_note:skip Skip the PR/issue when compiling release notes label Apr 29, 2026
@spong spong requested review from a team as code owners April 29, 2026 05:33
@spong spong added backport:skip This PR does not require backporting Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v9.5.0 Feature:Inbox This is the label for the Inbox Project labels Apr 29, 2026
@botelastic botelastic Bot added the Team:One Workflow Team label for One Workflow (Workflow automation) label Apr 29, 2026
@infra-vault-gh-plugin-prod
Copy link
Copy Markdown

Pinging @elastic/security-solution (Team: SecuritySolution)

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented Apr 29, 2026

Catch flakiness early (recommended): run the flaky test runner against this PR before merging.

This PR adds a new FTR test suite (inbox_api_integration) with active HTTP-level contract tests that exercise async server interactions.

Trigger a run with the Flaky Test Runner UI or post this comment on the PR:

/flaky ftrConfig:x-pack/platform/test/inbox_api_integration/config.ts:30

Share feedback in the #appex-qa channel.

Posted via Macroscope — Flaky Test Runner nudge

Comment thread x-pack/platform/plugins/shared/inbox/public/pages/inbox_actions/index.tsx Outdated
Copy link
Copy Markdown
Member

@delanni delanni left a comment

Choose a reason for hiding this comment

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

ftr config set change 👍

@talboren talboren requested a review from h88 April 29, 2026 11:27
@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner

✅ Build triggered - kibana-flaky-test-suite-runner#11990

  • x-pack/platform/test/inbox_api_integration/config.ts x30

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner Stats

🟠 Some tests failed. - kibana-flaky-test-suite-runner#11990

[❌] x-pack/platform/test/inbox_api_integration/config.ts: 0/30 tests passed.

see run history

@spong
Copy link
Copy Markdown
Member Author

spong commented Apr 29, 2026

/flaky ftrConfig:x-pack/platform/test/inbox_api_integration/config.ts:30

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner

✅ Build triggered - kibana-flaky-test-suite-runner#11994

  • x-pack/platform/test/inbox_api_integration/config.ts x30

@kibanamachine
Copy link
Copy Markdown
Contributor

Flaky Test Runner Stats

🎉 All tests passed! - kibana-flaky-test-suite-runner#11994

[✅] x-pack/platform/test/inbox_api_integration/config.ts: 30/30 tests passed.

see run history

logger.debug(
`Workflows inbox provider resuming execution ${parsed.executionId} (workflow ${parsed.workflowId})`
);
await api.resumeWorkflowExecution(parsed.executionId, ctx.spaceId, input, ctx.request);
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.

Consider providing stepId to avoid a potential race conditional of two approvals for the same inbox item being received at nearly the same time

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ooooh, good catch! Ty! 🙏

Looks like there's more we can do around OCC updates within workflows themself, but will keep this initial fix to the Inbox interface.

/**
* Surface the response was submitted through (inbox, kibana_execution_view, agent_builder, slack, api)
*/
channel: z.string().nullable().optional(),
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Better as response_client maybe? Not to confuse with workflow distribution channels?

security: {
authz: { requiredPrivileges: [INBOX_API_PRIVILEGE_RESPOND] },
},
summary: 'Respond to an inbox action',
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i18n

Copy link
Copy Markdown
Contributor

@andrew-goldstein andrew-goldstein left a comment

Choose a reason for hiding this comment

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

Thanks @spong!
LGTM 🚀

Comment on lines +26 to +41
// The step runtime's abort signal is how monitors (workflow-level timeout,
// cancellation) tell a step "you have already been settled — do not touch
// state". Without this guard a waitForInput that is resumed after the
// workflow has timed out would enter `tryEnterWaitUntil` with an in-memory
// status of FAILED (set by the monitor's failStep call), treat itself as
// "not already waiting", and re-write status back to WAITING_FOR_INPUT —
// leaving a zombie step that `listWaitingForInputSteps` keeps surfacing in
// the Inbox forever.
if (this.stepExecutionRuntime.abortController.signal.aborted) {
this.workflowLogger.logDebug(
`Step '${this.node.stepId}' run aborted before wait-entry; skipping`,
{ event: { action: 'hitl:aborted' } }
);
return;
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@h88, this is one of the two (non-inbox-conditional) functional changes to workflows in this PR.

This was surfaced as having stale items stuck in the Inbox views, and the fix makes sense to me, but please do confirm if this is an okay approach here. Corresponding tests are included as well.

All other workflow changes in this PR are conditional on the Inbox plugin being enabled, for which it is currently off-by-default.

Comment on lines +1218 to +1231
// Freshness guard: a waitForInput step whose parent workflow already
// terminated (timeout, cancel, external failure) can leave the execution
// doc with `status: waiting_for_input` but `finishedAt` set — writing
// resumeInput and scheduling a resume task in that state is a no-op that
// silently swallows the analyst's response. Reject explicitly so the
// caller sees a 409 and the Inbox provider can surface a real error.
if (workflowExecution.finishedAt) {
throw new WorkflowExecutionInvalidStatusError(
executionId,
`${workflowExecution.status} (already finished at ${workflowExecution.finishedAt})`,
ExecutionStatus.WAITING_FOR_INPUT
);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@h88, this is the only other (non-inbox-conditional) functional change to workflows in this PR.

Perhaps this isn't necessary with the other previous fix for updating event.action on abort, so any confirmation here would be appreciated!

@kibanamachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #152 / task_manager migrations 8.5.0 migrates active tasks to set enabled to true

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
inbox 20 26 +6

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/inbox-common 17 31 +14
inbox 7 28 +21
total +35

Any counts in public APIs

Total count of every any typed public API. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats any for more detailed information.

id before after diff
inbox 0 1 +1

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
inbox 4.9KB 13.7KB +8.7KB

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
inbox 0 1 +1

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
inbox 4.7KB 5.1KB +367.0B
Unknown metric groups

API count

id before after diff
@kbn/inbox-common 17 33 +16
inbox 7 42 +35
total +51

ESLint disabled line counts

id before after diff
inbox 0 2 +2

Total ESLint disabled count

id before after diff
inbox 0 2 +2

History

cc @spong

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

Labels

backport:skip This PR does not require backporting Feature:Inbox This is the label for the Inbox Project release_note:skip Skip the PR/issue when compiling release notes Team:One Workflow Team label for One Workflow (Workflow automation) Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants