Skip to content

[EDR Workflows][Artifact transfer 3] Import API validator#248046

Merged
gergoabraham merged 55 commits intoelastic:mainfrom
gergoabraham:artifact-transfer-3-import-api
Mar 18, 2026
Merged

[EDR Workflows][Artifact transfer 3] Import API validator#248046
gergoabraham merged 55 commits intoelastic:mainfrom
gergoabraham:artifact-transfer-3-import-api

Conversation

@gergoabraham
Copy link
Copy Markdown
Contributor

@gergoabraham gergoabraham commented Jan 7, 2026

prerequisites:

follow-up:

closes #250470

Summary

Note

Hidden behind feature flag (as part of the Endpoint exception move effort):

xpack.securitySolution.enableExperimental:
 - endpointExceptionsMovedUnderManagement

This PR allows importing all Endpoint artifacts! Lot's of changes, here's a summary written by Claude, plus some additional information:

This PR updates the Endpoint artifact import validator registered for the POST /api/exception_lists/_import API. The changes are gated behind the endpointExceptionsMovedUnderManagement feature flag.

What's changed

Import validation overhaul (getExceptionsPreImportHandler):

  • Replaces the old simple "block all non-endpoint-exception artifacts" logic with full per-artifact-type validation support
  • When the feature flag is enabled, dispatches validation to the appropriate artifact-specific validator (TrustedAppValidator, BlocklistValidator, EventFilterValidator, HostIsolationExceptionsValidator, TrustedDeviceValidator, EndpointExceptionsValidator)
  • Supports importing only one artifact list type per import call (returns 400 if multiple types are mixed)
  • Handles overwrite semantics by deleting visible items before import (respecting user permissions), then disabling the Lists API's own overwrite to avoid full-list deletion

Space-aware validation:

  • Each imported item is validated against the user's space permissions: non-global artifact management users can only import items owned by the current space; users with global artifact management privilege can import items from other spaces, provided those items are visible in the current space
  • Invalid owner space IDs are rejected (this means error); invalid policy IDs are stripped and noted in a comment on the item

On error handling:

  • if there's a general problem (like no user access), the request is rejected.
  • if there's a per-item problem, the request succeeds, but it'll contain the errors per item, which errors we can later show to the user

Data enrichment on import:

  • Adds the imported_artifact tag to all imported items
  • Adds an audit comment to each item with the original author and creation date
  • Adds the ownerSpaceId tag to items that lack one (backward compatibility for pre-space-awareness exports)

ExceptionsListPreImportServerExtension type change:

  • The extension point's data type changed from PromiseFromStreams{ data: PromiseFromStreams; overwrite: boolean }, allowing the extension to inspect and override the overwrite flag

ExceptionListClient.bulkDeleteExceptionListItems:

  • New public method for bulk-deleting exception list items (replaces the previous slow per-item sequential deletion via asyncForEach)

ExceptionItemImportError class:

  • New error class implementing BulkErrorErrorSchema, used to surface per-item validation errors in the import response (instead of aborting the entire import)

Tests:

  • Comprehensive new FTR integration test suite (artifact_import.ts) covering privilege checks, space-awareness scenarios, invalid data handling, overwrite behavior, comment/tag enrichment, and backward compatibility

Testing

To ease testing, I added some ugly details (58fcfb3) to the success toast, but this is not something that will stay.

Follow-up PR possibilities

There are some things we probably also need to add, but I'd like to keep them out of this PR. I can think of these:

  • improve UI feedback to user on errors (the toast doesn't look ideal)
  • do not allow any artifact type be imported on any artifact pages and rule exceptions page. this is now allowed, since the API endpoint is the same. (we could fix this e.g. by adding a new query parameter to the import API, or by adding a new endpoint artifact import API that calls the lists import service)

Follow-up PR is already in-progress:

Screenshots

image image image

Some error messages

image

Response:

{
    "message": "EndpointArtifactError: Importing multiple Endpoint artifact exception list types at the same time is not supported",
    "status_code": 400
}
image ☝️ probably won't be like this, it's just to visualize the response for this PR. will be improved in a follow-up pr

Response:

{
    "errors": [
        {
            "error": {
                "status_code": 403,
                "message": "EndpointArtifactError: Importing artifacts with invalid owner space IDs is not allowed. The following space ID is invalid or unaccessible by current user: nope"
            },
            "list_id": "endpoint_host_isolation_exceptions",
            "item_id": "5cc4585e-edbb-445f-a0d6-a6a67bb29d04"
        },
        {
            "error": {
                "status_code": 403,
                "message": "EndpointArtifactError: Endpoint authorization failure. Importing artifacts that are not visible in the current space is not allowed"
            },
            "list_id": "endpoint_host_isolation_exceptions",
            "item_id": "4c791b4a-5e87-4eb3-9713-1c80f6c98b80"
        }
    ],
    "success": false,
    "success_count": 1,
    "success_exception_lists": true,
    "success_count_exception_lists": 0,
    "success_exception_list_items": false,
    "success_count_exception_list_items": 1
}

Checklist

Check the PR satisfies following conditions.

Reviewers should verify this PR satisfies this list as well.

  • Any text added follows EUI's writing guidelines, uses sentence case text and includes i18n support
  • Documentation was added for features that require explanation or tutorials
  • Unit or functional tests were updated or added to match the most common scenarios
  • If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the docker list
  • This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The release_note:breaking label should be applied in these situations.
  • Flaky Test Runner was used on any tests changed
  • The PR description includes the appropriate Release Notes section, and the correct release_note:* label is applied per the guidelines
  • Review the backport guidelines and apply applicable backport:* labels.

Identify risks

Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging.

@gergoabraham gergoabraham self-assigned this Jan 7, 2026
@gergoabraham gergoabraham added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting Team:Defend Workflows “EDR Workflows” sub-team of Security Solution labels Jan 7, 2026
gergoabraham added a commit that referenced this pull request Jan 21, 2026
follow-up:
- #247976
- #248046

## Summary

This PR adds:
- Export and Import buttons for all Endpoint artifacts,
- activates Export functionality, while Import doesn't do anything so
far.

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

<img width="950" height="176" alt="image"
src="https://github.com/user-attachments/assets/1187d274-5872-4bf6-9b7c-9778daaa15f7"
/>

<img width="950" height="177" alt="image"
src="https://github.com/user-attachments/assets/a91417c9-20dd-4278-ae57-53ddae033730"
/>

etc...


https://github.com/user-attachments/assets/1e98a9a0-8952-45ff-a687-31a7d21cea60


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
qn895 pushed a commit to qn895/kibana that referenced this pull request Jan 22, 2026
…ic#247967)

follow-up:
- elastic#247976
- elastic#248046

## Summary

This PR adds:
- Export and Import buttons for all Endpoint artifacts,
- activates Export functionality, while Import doesn't do anything so
far.

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

<img width="950" height="176" alt="image"
src="https://github.com/user-attachments/assets/1187d274-5872-4bf6-9b7c-9778daaa15f7"
/>

<img width="950" height="177" alt="image"
src="https://github.com/user-attachments/assets/a91417c9-20dd-4278-ae57-53ddae033730"
/>

etc...


https://github.com/user-attachments/assets/1e98a9a0-8952-45ff-a687-31a7d21cea60


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
dennis-tismenko pushed a commit to dennis-tismenko/kibana that referenced this pull request Jan 22, 2026
…ic#247967)

follow-up:
- elastic#247976
- elastic#248046

## Summary

This PR adds:
- Export and Import buttons for all Endpoint artifacts,
- activates Export functionality, while Import doesn't do anything so
far.

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

<img width="950" height="176" alt="image"
src="https://github.com/user-attachments/assets/1187d274-5872-4bf6-9b7c-9778daaa15f7"
/>

<img width="950" height="177" alt="image"
src="https://github.com/user-attachments/assets/a91417c9-20dd-4278-ae57-53ddae033730"
/>

etc...


https://github.com/user-attachments/assets/1e98a9a0-8952-45ff-a687-31a7d21cea60


### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
@gergoabraham gergoabraham force-pushed the artifact-transfer-3-import-api branch 3 times, most recently from 40f74db to e9586f6 Compare January 23, 2026 14:31
@gergoabraham gergoabraham force-pushed the artifact-transfer-3-import-api branch from e9586f6 to 76c9b95 Compare March 2, 2026 13:00
gergoabraham added a commit that referenced this pull request Mar 3, 2026
prerequisite:
- #247967

follow-up:
- #248046

## Summary

This PR adds UI changes for being able to import artifacts:
- Import flyout on artifact pages,
- flyout stored in URL as well like other flyouts,
- import button for empty state on artifact pages,
- import button for empty state on policy detail tabs.

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

> [!important]
> This PR contains only UI changes! API changes are implemented in a
follow-up PR.
>
> No checks are changed/applied - on any artifact page you will be able
to import JSON files of shared exception lists or endpoint exceptions,
but an API error is returned if you try to import endpoint artifacts.


### Looks

<img width="898" height="948" alt="image"
src="https://github.com/user-attachments/assets/4a9fd1b4-7c36-47bd-b963-c9e5ace85f1b"
/>

### Artifact pages -Import flyout from overflow menu


https://github.com/user-attachments/assets/53d9a05d-66bf-49bb-9cea-15e95d353cf8

### Artifact pages - empty state


https://github.com/user-attachments/assets/40f4b0f4-2e24-47dd-b3cc-6c4482c3205b

### Policy details tabs - empty state


https://github.com/user-attachments/assets/13266549-8cd0-4690-85bb-c0e4fa0d03ba






### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
rbrtj pushed a commit to rbrtj/kibana that referenced this pull request Mar 5, 2026
prerequisite:
- elastic#247967

follow-up:
- elastic#248046

## Summary

This PR adds UI changes for being able to import artifacts:
- Import flyout on artifact pages,
- flyout stored in URL as well like other flyouts,
- import button for empty state on artifact pages,
- import button for empty state on policy detail tabs.

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

> [!important]
> This PR contains only UI changes! API changes are implemented in a
follow-up PR.
>
> No checks are changed/applied - on any artifact page you will be able
to import JSON files of shared exception lists or endpoint exceptions,
but an API error is returned if you try to import endpoint artifacts.


### Looks

<img width="898" height="948" alt="image"
src="https://github.com/user-attachments/assets/4a9fd1b4-7c36-47bd-b963-c9e5ace85f1b"
/>

### Artifact pages -Import flyout from overflow menu


https://github.com/user-attachments/assets/53d9a05d-66bf-49bb-9cea-15e95d353cf8

### Artifact pages - empty state


https://github.com/user-attachments/assets/40f4b0f4-2e24-47dd-b3cc-6c4482c3205b

### Policy details tabs - empty state


https://github.com/user-attachments/assets/13266549-8cd0-4690-85bb-c0e4fa0d03ba






### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
DennisKo pushed a commit to DennisKo/kibana that referenced this pull request Mar 6, 2026
prerequisite:
- elastic#247967

follow-up:
- elastic#248046

## Summary

This PR adds UI changes for being able to import artifacts:
- Import flyout on artifact pages,
- flyout stored in URL as well like other flyouts,
- import button for empty state on artifact pages,
- import button for empty state on policy detail tabs.

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

> [!important]
> This PR contains only UI changes! API changes are implemented in a
follow-up PR.
>
> No checks are changed/applied - on any artifact page you will be able
to import JSON files of shared exception lists or endpoint exceptions,
but an API error is returned if you try to import endpoint artifacts.


### Looks

<img width="898" height="948" alt="image"
src="https://github.com/user-attachments/assets/4a9fd1b4-7c36-47bd-b963-c9e5ace85f1b"
/>

### Artifact pages -Import flyout from overflow menu


https://github.com/user-attachments/assets/53d9a05d-66bf-49bb-9cea-15e95d353cf8

### Artifact pages - empty state


https://github.com/user-attachments/assets/40f4b0f4-2e24-47dd-b3cc-6c4482c3205b

### Policy details tabs - empty state


https://github.com/user-attachments/assets/13266549-8cd0-4690-85bb-c0e4fa0d03ba






### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
@gergoabraham gergoabraham force-pushed the artifact-transfer-3-import-api branch 2 times, most recently from b986868 to c770752 Compare March 7, 2026 16:43
Copy link
Copy Markdown
Contributor

@rylnd rylnd left a comment

Choose a reason for hiding this comment

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

Detection Engine changes (shared Lists code) LGTM.

const { savedObjectsClient } = this;

if (this.enableServerExtensionPoints) {
// todo: this is not ideal, items will be checked one-by-one. we'd need an `exceptionsListPreBulkDeleteItems`
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.

While this isn't worse than the code it's replacing: is there a blocker to adding a bulkGet to allow this?

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.

yeah, that's good question. I don't know about any blocker - I think this was the point where I intentionally lost momentum, and instead of going down the rabbit hole focused on getting this functionality ready

Copy link
Copy Markdown
Contributor

@paul-tavares paul-tavares left a comment

Choose a reason for hiding this comment

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

Hi @gergo - I did some code review, but did not finish it - got up to the base validator. I may not have enought context or knownledge of this feature, so some of my comments may not actually be applicable. A few things that raised concern for me:

  • when overwrite is true, we seem to delete items before even attempting to import new ones. This could lead to a bad state of the customer's env. if the actual import fails.
  • I'm not clear why we are validating space owner tags for imports as well as whether the spaces are valid in the current environment. This seems to suggest that a user will no longer be able to export exceptions from one environemnt/space and import it into another - without having to manipulate the export manually. I would have invisioned that the space owner id tag would be ignored and all imported items would be owned by the space where the import is happening

I may reach out to you tomorrow to disucss this further.

const validateCanEndpointArtifactsBeImported = (
data: PromiseFromStreams,
experimentalFeatures: ExperimentalFeatures
) => {
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.

can you add a return Type to this function

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.

request: KibanaRequest | undefined;
importedListId: string;
logger: Logger;
}) => {
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.

can you add a return Type here

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.

namespaceType: 'agnostic',
});

logger.info(
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.

Careful with .info() loggers. Maybe move this to .debug()? Same comment for the `logger.info() on line 295 below

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.

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.

strange - I'm still seeing logger.info() although you referenced a commit where you seem to have moved them to .debug() 🤔

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.

🤦
because in the next commit i changed it back to info 😅 probably when testing how to delete more than 1k artifacts

thanks, Paul : )
067fc20

Comment on lines +133 to +136
await addOwnerSpaceIdTagToItems(data, endpointAppContext, request);
addImportedCommentToItems(data);
addImportedTagToItems(data);

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 is allot of looping through the data. If the imports are capped at low numbers, then it should be ok... but perhpas consider looping through the data items less often by making the necessary adjustment from one loop instead.

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.

@gergoabraham
Copy link
Copy Markdown
Contributor Author

hey @paul-tavares, thanks a lot for your feedback!

when overwrite is true, we seem to delete items before even attempting to import new ones. This could lead to a bad state of the customer's env. if the actual import fails.

yep, that's unfortunately a valid scenario. i guess moving the deletion into a 'post-import' handler won't help as well, since we can still have the problem of successfully importing new artifacts, and then not deleting the old ones in case of any problem.

looked into the existing import, and it's also cannot be considered atomic, so i think we should be okay with this. the existing import also deletes the existing items first (called from here), and only then creates the new ones.

I'm not clear why we are validating space owner tags for imports as well as whether the spaces are valid in the current environment. This seems to suggest that a user will no longer be able to export exceptions from one environemnt/space and import it into another - without having to manipulate the export manually. I would have invisioned that the space owner id tag would be ignored and all imported items would be owned by the space where the import is happening

i see your point. validating owner space IDs was a request from product side, you can see the questions/answers in the issue linked in the development section.
afaik space IDs are based on their names, so if you have the same space names when migrating to a new environment, that should work perfectly. copying exceptions to another space, well... that use case is indeed not supported with this behavior. cc @roxana-gheorghe

@paul-tavares
Copy link
Copy Markdown
Contributor

Thanks @gergoabraham for the above response. Seems as if my concerns has already come up with discussion with PM. I will complete the code review here soon.

Copy link
Copy Markdown
Contributor

@paul-tavares paul-tavares left a comment

Choose a reason for hiding this comment

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

Ok. I completed the code review - no other significant feedback from me.

@gergoabraham
Copy link
Copy Markdown
Contributor Author

Thanks @gergoabraham for the above response. Seems as if my concerns has already come up with discussion with PM. I will complete the code review here soon.

thank you @paul-tavares for your feedback, i always appreciate it! 🙌

Copy link
Copy Markdown
Contributor

@paul-tavares paul-tavares left a comment

Choose a reason for hiding this comment

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

Thanks for the changes.

});

if (itemIdsToDelete.length > 0) {
await exceptionListClient.bulkDeleteExceptionListItems({
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.

(optional) For large amounts of data, it might be best to handle the deletes from within executeFunctionOnStream() and use an async queue to process them (ex. using QueueProcessor), rather than to collect all IDs and potentially send off a very large bulk delete.

namespaceType: 'agnostic',
});

logger.info(
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.

strange - I'm still seeing logger.info() although you referenced a commit where you seem to have moved them to .debug() 🤔

@elasticmachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Serverless Detection Engine - Security Solution Cypress Tests #7 / Detection ES|QL rules - Rule Creation ES|QL investigation fields shows custom ES|QL field in investigation fields autocomplete and saves it in rule shows custom ES|QL field in investigation fields autocomplete and saves it in rule
  • [job] [logs] Serverless Detection Engine - Security Solution Cypress Tests #7 / Detection ES|QL rules - Rule Creation ES|QL query validation allows non-aggregating ES|QL query without metadata operator (auto-injected at execution) allows non-aggregating ES|QL query without metadata operator (auto-injected at execution)
  • [job] [logs] FTR Configs #177 / discover - group 2 feature controls discover feature controls security global discover read-only privileges "before all" hook for "shows discover navlink"

Metrics [docs]

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/securitysolution-io-ts-list-types 521 522 +1
lists 98 99 +1
total +2

Async chunks

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

id before after diff
securitySolution 11.4MB 11.4MB +307.0B

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
lists 52 53 +1
Unknown metric groups

API count

id before after diff
@kbn/securitysolution-io-ts-list-types 535 536 +1
lists 227 229 +2
total +3

ESLint disabled line counts

id before after diff
lists 31 30 -1

Total ESLint disabled count

id before after diff
lists 32 31 -1

History

cc @gergoabraham

@gergoabraham gergoabraham merged commit 6c5231b into elastic:main Mar 18, 2026
18 checks passed
qn895 pushed a commit to qn895/kibana that referenced this pull request Mar 18, 2026
…8046)

prerequisites:
- elastic#247967
- elastic#247976

follow-up:
- elastic#257983

closes elastic#250470

## Summary

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

This PR allows importing all Endpoint artifacts! Lot's of changes,
here's a summary written by Claude, plus some additional information:

This PR updates the Endpoint artifact import validator registered for
the `POST /api/exception_lists/_import` API. The changes are gated
behind the `endpointExceptionsMovedUnderManagement` feature flag.

### What's changed

**Import validation overhaul (`getExceptionsPreImportHandler`):**
- Replaces the old simple "block all non-endpoint-exception artifacts"
logic with full per-artifact-type validation support
- When the feature flag is enabled, dispatches validation to the
appropriate artifact-specific validator (`TrustedAppValidator`,
`BlocklistValidator`, `EventFilterValidator`,
`HostIsolationExceptionsValidator`, `TrustedDeviceValidator`,
`EndpointExceptionsValidator`)
- Supports importing only **one** artifact list type per import call
(returns 400 if multiple types are mixed)
- Handles `overwrite` semantics by deleting visible items before import
(respecting user permissions), then disabling the Lists API's own
overwrite to avoid full-list deletion

**Space-aware validation:**
- Each imported item is validated against the user's space permissions:
non-global artifact management users can only import items owned by the
current space; users with global artifact management privilege can
import items from other spaces, provided those items are visible in the
current space
- Invalid owner space IDs are rejected _(this means error);_ invalid
policy IDs are stripped and noted in a comment on the item

**On error handling:**
- if there's a general problem (like no user access), the request is
rejected.
- if there's a per-item problem, the request succeeds, but it'll contain
the errors per item, which errors we can later show to the user

**Data enrichment on import:**
- Adds the `imported_artifact` tag to all imported items
- Adds an audit comment to each item with the original author and
creation date
- Adds the `ownerSpaceId` tag to items that lack one (backward
compatibility for pre-space-awareness exports)

**`ExceptionsListPreImportServerExtension` type change:**
- The extension point's data type changed from `PromiseFromStreams` → `{
data: PromiseFromStreams; overwrite: boolean }`, allowing the extension
to inspect and override the `overwrite` flag

**`ExceptionListClient.bulkDeleteExceptionListItems`:**
- New public method for bulk-deleting exception list items (replaces the
previous slow per-item sequential deletion via `asyncForEach`)

**`ExceptionItemImportError` class:**
- New error class implementing `BulkErrorErrorSchema`, used to surface
per-item validation errors in the import response (instead of aborting
the entire import)

**Tests:**
- Comprehensive new FTR integration test suite (`artifact_import.ts`)
covering privilege checks, space-awareness scenarios, invalid data
handling, overwrite behavior, comment/tag enrichment, and backward
compatibility

## Testing
To ease testing, I added some ugly details
(58fcfb3) to the success toast, but
this is not something that will stay.

## Follow-up PR possibilities
There are some things we probably also need to add, but I'd like to keep
them out of this PR. I can think of these:
- improve UI feedback to user on errors (the toast doesn't look ideal)
- do not allow any artifact type be imported on any artifact pages and
rule exceptions page. this is now allowed, since the API endpoint is the
same. (we could fix this e.g. by adding a new query parameter to the
import API, or by adding a new endpoint artifact import API that calls
the lists import service)

Follow-up PR is already in-progress:
- elastic#257983

## Screenshots
<img width="965" height="497" alt="image"
src="https://github.com/user-attachments/assets/9a552242-48b0-45f2-979b-eadacf73ffcc"
/>
<img width="975" height="497" alt="image"
src="https://github.com/user-attachments/assets/73d77a99-c2c6-421b-a22d-2c2aeb595b90"
/>
<img width="1227" height="747" alt="image"
src="https://github.com/user-attachments/assets/3d3b77f2-0077-441d-b4eb-5519fcda25a5"
/>



### Some error messages
<img width="973" height="500" alt="image"
src="https://github.com/user-attachments/assets/b751a6cb-e84a-44df-8d47-c676a20253ce"
/>

Response:
```json
{
    "message": "EndpointArtifactError: Importing multiple Endpoint artifact exception list types at the same time is not supported",
    "status_code": 400
}
```

<img width="1231" height="745" alt="image"
src="https://github.com/user-attachments/assets/ef4d9032-ecef-4f32-9c80-241ecdc1a978"
/>
☝️ probably won't be like this, it's just to visualize the response for
this PR. will be improved in a follow-up pr

Response:
```json
{
    "errors": [
        {
            "error": {
                "status_code": 403,
                "message": "EndpointArtifactError: Importing artifacts with invalid owner space IDs is not allowed. The following space ID is invalid or unaccessible by current user: nope"
            },
            "list_id": "endpoint_host_isolation_exceptions",
            "item_id": "5cc4585e-edbb-445f-a0d6-a6a67bb29d04"
        },
        {
            "error": {
                "status_code": 403,
                "message": "EndpointArtifactError: Endpoint authorization failure. Importing artifacts that are not visible in the current space is not allowed"
            },
            "list_id": "endpoint_host_isolation_exceptions",
            "item_id": "4c791b4a-5e87-4eb3-9713-1c80f6c98b80"
        }
    ],
    "success": false,
    "success_count": 1,
    "success_exception_lists": true,
    "success_count_exception_lists": 0,
    "success_exception_list_items": false,
    "success_count_exception_list_items": 1
}
```



### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
jeramysoucy pushed a commit to jeramysoucy/kibana that referenced this pull request Mar 26, 2026
…8046)

prerequisites:
- elastic#247967
- elastic#247976

follow-up:
- elastic#257983

closes elastic#250470

## Summary

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

This PR allows importing all Endpoint artifacts! Lot's of changes,
here's a summary written by Claude, plus some additional information:

This PR updates the Endpoint artifact import validator registered for
the `POST /api/exception_lists/_import` API. The changes are gated
behind the `endpointExceptionsMovedUnderManagement` feature flag.

### What's changed

**Import validation overhaul (`getExceptionsPreImportHandler`):**
- Replaces the old simple "block all non-endpoint-exception artifacts"
logic with full per-artifact-type validation support
- When the feature flag is enabled, dispatches validation to the
appropriate artifact-specific validator (`TrustedAppValidator`,
`BlocklistValidator`, `EventFilterValidator`,
`HostIsolationExceptionsValidator`, `TrustedDeviceValidator`,
`EndpointExceptionsValidator`)
- Supports importing only **one** artifact list type per import call
(returns 400 if multiple types are mixed)
- Handles `overwrite` semantics by deleting visible items before import
(respecting user permissions), then disabling the Lists API's own
overwrite to avoid full-list deletion

**Space-aware validation:**
- Each imported item is validated against the user's space permissions:
non-global artifact management users can only import items owned by the
current space; users with global artifact management privilege can
import items from other spaces, provided those items are visible in the
current space
- Invalid owner space IDs are rejected _(this means error);_ invalid
policy IDs are stripped and noted in a comment on the item

**On error handling:**
- if there's a general problem (like no user access), the request is
rejected.
- if there's a per-item problem, the request succeeds, but it'll contain
the errors per item, which errors we can later show to the user

**Data enrichment on import:**
- Adds the `imported_artifact` tag to all imported items
- Adds an audit comment to each item with the original author and
creation date
- Adds the `ownerSpaceId` tag to items that lack one (backward
compatibility for pre-space-awareness exports)

**`ExceptionsListPreImportServerExtension` type change:**
- The extension point's data type changed from `PromiseFromStreams` → `{
data: PromiseFromStreams; overwrite: boolean }`, allowing the extension
to inspect and override the `overwrite` flag

**`ExceptionListClient.bulkDeleteExceptionListItems`:**
- New public method for bulk-deleting exception list items (replaces the
previous slow per-item sequential deletion via `asyncForEach`)

**`ExceptionItemImportError` class:**
- New error class implementing `BulkErrorErrorSchema`, used to surface
per-item validation errors in the import response (instead of aborting
the entire import)

**Tests:**
- Comprehensive new FTR integration test suite (`artifact_import.ts`)
covering privilege checks, space-awareness scenarios, invalid data
handling, overwrite behavior, comment/tag enrichment, and backward
compatibility

## Testing
To ease testing, I added some ugly details
(58fcfb3) to the success toast, but
this is not something that will stay.

## Follow-up PR possibilities
There are some things we probably also need to add, but I'd like to keep
them out of this PR. I can think of these:
- improve UI feedback to user on errors (the toast doesn't look ideal)
- do not allow any artifact type be imported on any artifact pages and
rule exceptions page. this is now allowed, since the API endpoint is the
same. (we could fix this e.g. by adding a new query parameter to the
import API, or by adding a new endpoint artifact import API that calls
the lists import service)

Follow-up PR is already in-progress:
- elastic#257983

## Screenshots
<img width="965" height="497" alt="image"
src="https://github.com/user-attachments/assets/9a552242-48b0-45f2-979b-eadacf73ffcc"
/>
<img width="975" height="497" alt="image"
src="https://github.com/user-attachments/assets/73d77a99-c2c6-421b-a22d-2c2aeb595b90"
/>
<img width="1227" height="747" alt="image"
src="https://github.com/user-attachments/assets/3d3b77f2-0077-441d-b4eb-5519fcda25a5"
/>



### Some error messages
<img width="973" height="500" alt="image"
src="https://github.com/user-attachments/assets/b751a6cb-e84a-44df-8d47-c676a20253ce"
/>

Response:
```json
{
    "message": "EndpointArtifactError: Importing multiple Endpoint artifact exception list types at the same time is not supported",
    "status_code": 400
}
```

<img width="1231" height="745" alt="image"
src="https://github.com/user-attachments/assets/ef4d9032-ecef-4f32-9c80-241ecdc1a978"
/>
☝️ probably won't be like this, it's just to visualize the response for
this PR. will be improved in a follow-up pr

Response:
```json
{
    "errors": [
        {
            "error": {
                "status_code": 403,
                "message": "EndpointArtifactError: Importing artifacts with invalid owner space IDs is not allowed. The following space ID is invalid or unaccessible by current user: nope"
            },
            "list_id": "endpoint_host_isolation_exceptions",
            "item_id": "5cc4585e-edbb-445f-a0d6-a6a67bb29d04"
        },
        {
            "error": {
                "status_code": 403,
                "message": "EndpointArtifactError: Endpoint authorization failure. Importing artifacts that are not visible in the current space is not allowed"
            },
            "list_id": "endpoint_host_isolation_exceptions",
            "item_id": "4c791b4a-5e87-4eb3-9713-1c80f6c98b80"
        }
    ],
    "success": false,
    "success_count": 1,
    "success_exception_lists": true,
    "success_count_exception_lists": 0,
    "success_exception_list_items": false,
    "success_count_exception_list_items": 1
}
```



### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] If a plugin configuration key changed, check if it needs to be
allowlisted in the cloud and added to the [docker
list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)
- [ ] This was checked for breaking HTTP API changes, and any breaking
changes have been approved by the breaking-change committee. The
`release_note:breaking` label should be applied in these situations.
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
- [ ] Review the [backport
guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing)
and apply applicable `backport:*` labels.

### Identify risks

Does this PR introduce any risks? For example, consider risks like hard
to test bugs, performance regression, potential of data loss.

Describe the risk, its severity, and mitigation for each identified
risk. Invite stakeholders and evaluate how to proceed before merging.

- [ ] [See some risk
examples](https://github.com/elastic/kibana/blob/main/RISK_MATRIX.mdx)
- [ ] ...

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
gergoabraham added a commit that referenced this pull request Apr 2, 2026
prerequisites:
- #247967
- #247976
- #248046

## Summary

> [!note]
> Hidden behind feature flag (as part of the Endpoint exception move
effort):
> ```
> xpack.securitySolution.enableExperimental:
>  - endpointExceptionsMovedUnderManagement
> ```

### Limit which lists can be imported on which page
- Shared exceptions page doesn't allow importing Endpoint artifacts
(including Endpoint exceptions, that was allowed before)
- 📔 text: `You can only import shared exception lists here, but at least
one of the imported files contains endpoint artifacts. Import endpoint
artifacts from their dedicated pages instead.`
- Endpoint artifact pages allow only their corresponding artifact types
to be imported
    - 📔 texts:
      - `You can only import blocklist entries here.`
      - `You can only import Endpoint exceptions here.`
      - `You can only import event filters here.`
      - etc.
- Check is moved to the UI side (without more refined validation), to
avoid introducing (breaking) changes to import API

### Keep existing artifacts on import

Artifact import now APPENDS imported artifacts to existing ones, instead
of OVERWRITING the whole list
- Due to this change, all texts are updated to not use the 'list' word,
e.g. _'Import trusted application list'_ => _'Import trusted
applications'_

### Positive friction for importing Endpoint artifacts
- A confirmation modal is added to the import process (based on design)
  - 📔 texts:
    - flyout: `Import artifacts to your artifact list.`
- confirm modal: `This will add new artifacts to your list. If an
artifact you're importing already exists, the existing version will be
kept, and the import of that artifact will be skipped.`

### Display import errors in a better way, following new design
- Different toasts are shown to the user when the import API call fails,
the API call succeeds but none of the artifacts are imported, some of
the artifacts are imported or all of the artifacts are imported
    - 📔 texts:
- `Artifacts imported` / `All artifacts were imported successfully`
- `Import completed with errors` / `{importedCount} imported,
{failedCount} failed. Review the errors for details.`
- `Artifacts weren't imported` / `The artifacts couldn't be imported.
Review the errors and try again.`
- A new modal can be opened from the fail toast to show the list of all
errors
    - 📔 texts:
      - title: `Import errors`
- info: `Some items couldn't be imported. Review the errors below for
details.`

### Server error responses are updated with new texts
- 📔 texts:
- `This artifact can't be imported because you don't have permission to
manage artifacts in other spaces. Contact your administrator for
access.`
- `This artifact can't be imported because you don't have permission to
manage global artifacts. Contact your administrator for access.`
- `This artifact can't be imported because it isn't visible in the
current space. Try importing it from a matching space or a space with
access to the related policy.`
- `This artifact can't be imported because it belongs to a space you
don't have access to. Update the artifact in its original space and try
again.`

## Screenshots

### Import limitation

#### Shared lists page

<img width="1135" height="642" alt="image"
src="https://github.com/user-attachments/assets/86c2bd48-8678-4662-80fd-87d4f9aa6ed2"
/>


#### An endpoint artifact page

<img width="1113" height="755" alt="image"
src="https://github.com/user-attachments/assets/d0452196-bc92-4fc0-a035-07ac069522df"
/>


### New texts

<img width="348" height="158" alt="image"
src="https://github.com/user-attachments/assets/fcd64168-4908-423b-8bbb-3671b6763c94"
/>

<img width="288" height="153" alt="image"
src="https://github.com/user-attachments/assets/172378b7-2956-4f34-8b0d-d6891fea5084"
/>

<img width="423" height="275" alt="image"
src="https://github.com/user-attachments/assets/9c1b0f44-9cc5-4dad-9306-2219a1e35052"
/>

etc.

### Confirm modal

<img width="1380" height="925" alt="image"
src="https://github.com/user-attachments/assets/b023f965-ccad-4398-b8c9-da7f33bede68"
/>

<img width="812" height="249" alt="image"
src="https://github.com/user-attachments/assets/d5269ea4-0584-43b9-9983-b5cbbb8485b6"
/>

### Displaying the results on toasts

#### Success

<img width="356" height="120" alt="image"
src="https://github.com/user-attachments/assets/327aaad0-ecdb-4e3a-b6d7-08cf7ac2506c"
/>

#### Some items have errors

<img width="342" height="147" alt="image"
src="https://github.com/user-attachments/assets/da703d02-ef0e-42d6-8456-9766243122d0"
/>

#### All items have errors

<img width="348" height="170" alt="image"
src="https://github.com/user-attachments/assets/37942e8f-12b2-4916-b5b7-c383623855fd"
/>

#### Results modal 

<img width="1332" height="689" alt="image"
src="https://github.com/user-attachments/assets/4352c9a4-6b78-4e08-8f9a-a8ab05610cf7"
/>

<img width="1371" height="974" alt="image"
src="https://github.com/user-attachments/assets/4eb1dd78-65b1-4131-a29d-758de247b1ed"
/>

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
@gergoabraham gergoabraham deleted the artifact-transfer-3-import-api branch April 10, 2026 10:51
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 ci:build-cloud-image release_note:skip Skip the PR/issue when compiling release notes Team:Defend Workflows “EDR Workflows” sub-team of Security Solution v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failing test: EDR Workflows - Endpoint Exceptions Integration Tests - Serverless Env - Complete.unknown - "before all" hook in "{root}"

6 participants