[Security Solution] Register Workflows with Inbox#266256
[Security Solution] Register Workflows with Inbox#266256spong wants to merge 11 commits intoelastic:mainfrom
Conversation
|
Pinging @elastic/security-solution (Team: SecuritySolution) |
|
Catch flakiness early (recommended): run the flaky test runner against this PR before merging. This PR adds a new FTR test suite ( Trigger a run with the Flaky Test Runner UI or post this comment on the PR: Share feedback in the #appex-qa channel. Posted via Macroscope — Flaky Test Runner nudge |
Flaky Test Runner✅ Build triggered - kibana-flaky-test-suite-runner#11990
|
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. |
|
/flaky ftrConfig:x-pack/platform/test/inbox_api_integration/config.ts:30 |
Flaky Test Runner✅ Build triggered - kibana-flaky-test-suite-runner#11994
|
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. |
| logger.debug( | ||
| `Workflows inbox provider resuming execution ${parsed.executionId} (workflow ${parsed.workflowId})` | ||
| ); | ||
| await api.resumeWorkflowExecution(parsed.executionId, ctx.spaceId, input, ctx.request); |
There was a problem hiding this comment.
Consider providing stepId to avoid a potential race conditional of two approvals for the same inbox item being received at nearly the same time
There was a problem hiding this comment.
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(), |
There was a problem hiding this comment.
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', |
andrew-goldstein
left a comment
There was a problem hiding this comment.
Thanks @spong!
LGTM 🚀
| // 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; | ||
| } | ||
|
|
There was a problem hiding this comment.
@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.
| // 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 | ||
| ); | ||
| } | ||
|
|
There was a problem hiding this comment.
@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!
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Module Count
Public APIs missing comments
Any counts in public APIs
Async chunks
Public APIs missing exports
Page load bundle
Unknown metric groupsAPI count
ESLint disabled line counts
Total ESLint disabled count
History
cc @spong |
Summary
Introduces Inbox ↔ Workflows as a first-class integration so that any
waitForInputstep 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:
And populate sample workflows exercising each schema variation with:
(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
InboxActionProvidercontract (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 clampedtotalso a provider truncating its response can never desync the UI's pager. Logs a warning on truncation.GET /internal/inbox/actions— list + filter (status, source_app, pagination)POST /internal/inbox/actions/{source_app}/{source_id}/respond— schema-validated respond pathinbox_read/inbox_respondso thereadfeature role cannot invoke the respond route (previously collapsed under a singleapi: [PLUGIN_ID]).spacesplugin — no more hardcoded'default'leaking rows across spaces. Falls back to'default'only whenspacesis absent (single-space installs).TimeoutChipguards against malformedtimeout_atso it can't renderNaNh NaNm.SchemaFormaccessibility pass: label fallbacks to field name, visual*required marker,hasChildLabel={false}forEuiSwitchrows, localized select placeholder.public/application.tsx):refetchOnWindowFocus: 'always'+refetchOnMount: 'always'with a 30sstaleTimededupe window so the list is always current when the tab/app regains focus, plus locked-ininvalidateQuerieson the respond mutation so responded items drop off the list without a manual refresh.Workflows-management — Inbox provider
WorkflowsInboxProvider(src/platform/plugins/shared/workflows_management/server/inbox/) converts pausedwaitForInputsteps intoInboxActions (to_inbox_action.ts) and registers with the Inbox plugin at setup.WorkflowExecutionQueryService#listWaitingForInputStepsto fan-out across the executions index for paused steps (filtered byspaceId+status: waiting_for_input);WorkflowsManagementServiceexposes it via the same-name delegating method consistent with the rest of the facade. Wire-level regression tests live inworkflow_execution_query_service.test.ts(term-only query / pagination math /index_not_found_exceptionswallowed / log+rethrow), with a delegation test in the facade suite.Common contracts (
@kbn/inbox-common)status,source_app,input_schema,submission_channel, andtimeout_at.buildRespondToActionUrl(sourceApp, sourceId)with proper URL-encoding for composite source IDs.INBOX_API_PRIVILEGE_READ/INBOX_API_PRIVILEGE_RESPOND.Demo fixtures
x-pack/platform/plugins/shared/inbox/scripts/demo/:seed_inbox_demo.ts— dependency-lightfetchscript that imports + triggers each workflow against a running Kibana so the Inbox populates immediately.README.mdwith run instructions and the matching MCP-appgenerate-inbox-dataflow.FTR wiring
x-pack/platform/test/inbox_api_integration/config.tsopt-in via--xpack.inbox.enabled=true.inbox_flow.ts— contract-level coverage (empty-registry list, query validation, 404 on unknown source, 400 on missinginput). Live-workflow lifecycle assertions are stubbed asdescribe.skipwith TODOs pointing at the Workflows execution-engine harness work..buildkite/ftr_platform_stateful_configs.ymland.github/CODEOWNERS.Checklist
Check the PR satisfies following conditions.
Reviewers should verify this PR satisfies this list as well.
release_note:*label is applied per the guidelinesbackport:*labels.PR developed with Cursor + Claude Opus 4.7 Super Duper xHigh Thinking++