[Security Solution] Move threat intelligence to security solution (#214369)

# Summary

This PR merges Threat Intelligence plugin with security solution, in
order to remove duplicated and unnecessary code introduced as a bridge
between the TI plugin and Security Solution + to simpify maintenance. No
new functionality is implemented here, other than changing imports and
some dependendies to use security solution code directly, without weird
bridges or hacks / indirections.

## Testing

Navigate to threat intelligence plugin / indicators and try clicking
around. It is hard to list every feature we have there
but in general it should work without errors.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Luke Gmys 2025-06-03 16:51:57 +02:00 committed by GitHub
parent 6033441a2f
commit af0b369627
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
279 changed files with 3138 additions and 2636 deletions

1
.github/CODEOWNERS vendored
View file

@ -1066,7 +1066,6 @@ x-pack/solutions/security/plugins/security_solution @elastic/security-solution
x-pack/solutions/security/plugins/security_solution_ess @elastic/security-solution
x-pack/solutions/security/plugins/security_solution_serverless @elastic/security-solution
x-pack/solutions/security/plugins/session_view @elastic/kibana-cloud-security-posture
x-pack/solutions/security/plugins/threat_intelligence @elastic/security-threat-hunting-investigations
x-pack/test
x-pack/test_serverless
x-pack/test/alerting_api_integration/common/plugins/aad @elastic/response-ops

View file

@ -225,7 +225,6 @@ mapped_pages:
| [taskManager](https://github.com/elastic/kibana/blob/main/x-pack/platform/plugins/shared/task_manager/README.md) | The task manager is a generic system for running background tasks. |
| [taskManagerDependencies](https://github.com/elastic/kibana/blob/main/x-pack/platform/plugins/private/task_manager_dependencies/README.md) | This plugin is used as a temporary sidecar plugin to enable the task manager plugin access to the encrypted saved objects client as there is a circular dependency if the task manager were to require the encrypted saved objects plugin directly. |
| [telemetryCollectionXpack](https://github.com/elastic/kibana/blob/main/x-pack/platform/plugins/private/telemetry_collection_xpack/README.md) | Gathers all usage collection, retrieving them from both: OSS and X-Pack plugins. |
| [threatIntelligence](https://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/threat_intelligence/README.md) | Elastic Threat Intelligence makes it easy to analyze and investigate potential security threats by aggregating data from multiple sources in one place. Youll be able to view data from all activated threat intelligence feeds and take action. |
| [timelines](https://github.com/elastic/kibana/blob/main/x-pack/platform/plugins/shared/timelines/README.md) | Timelines is a plugin that provides a grid component with accompanying server side apis to help users identify events of interest and perform root cause analysis within Kibana. |
| [transform](https://github.com/elastic/kibana/blob/main/x-pack/platform/plugins/private/transform/README.md) | This plugin provides access to the transforms features provided by Elasticsearch. It follows Kibana's standard plugin architecture, originally the plugin boilerplate code was taken from the snapshot/restore plugin. |
| [translations](translations-plugin.md) | Contains Elastic-supported translations. Owned by the Localizations team. For adding localizations and instrument a ui to support translated content, see https://github.com/elastic/kibana/tree/main/src/platform/packages/shared/kbn-i18n |

View file

@ -981,7 +981,6 @@
"@kbn/testing-embedded-lens-plugin": "link:x-pack/examples/testing_embedded_lens",
"@kbn/third-party-lens-navigation-prompt-plugin": "link:x-pack/examples/third_party_lens_navigation_prompt",
"@kbn/third-party-vis-lens-example-plugin": "link:x-pack/examples/third_party_vis_lens_example",
"@kbn/threat-intelligence-plugin": "link:x-pack/solutions/security/plugins/threat_intelligence",
"@kbn/timelines-plugin": "link:x-pack/platform/plugins/shared/timelines",
"@kbn/timelion-grammar": "link:src/platform/packages/private/kbn-timelion-grammar",
"@kbn/timerange": "link:src/platform/packages/shared/kbn-timerange",

View file

@ -164,7 +164,6 @@ pageLoadAssetSize:
synthetics: 55971
telemetry: 51957
telemetryManagementSection: 38586
threatIntelligence: 44299
timelines: 327300
transform: 41007
triggersActionsUi: 135613

View file

@ -61,7 +61,6 @@ export const storybookAliases = {
// security_solution_packages: 'x-pack/solutions/security/packages/storybook/config',
serverless: 'src/platform/packages/shared/serverless/storybook/config',
shared_ux: 'src/platform/packages/private/shared-ux/storybook/config',
threat_intelligence: 'x-pack/solutions/security/plugins/threat_intelligence/.storybook',
triggers_actions_ui: 'x-pack/platform/plugins/shared/triggers_actions_ui/.storybook',
ui_actions_enhanced: 'src/platform/plugins/shared/ui_actions_enhanced/.storybook',
unified_search: 'src/platform/plugins/shared/unified_search/.storybook',

View file

@ -2008,8 +2008,6 @@
"@kbn/third-party-lens-navigation-prompt-plugin/*": ["x-pack/examples/third_party_lens_navigation_prompt/*"],
"@kbn/third-party-vis-lens-example-plugin": ["x-pack/examples/third_party_vis_lens_example"],
"@kbn/third-party-vis-lens-example-plugin/*": ["x-pack/examples/third_party_vis_lens_example/*"],
"@kbn/threat-intelligence-plugin": ["x-pack/solutions/security/plugins/threat_intelligence"],
"@kbn/threat-intelligence-plugin/*": ["x-pack/solutions/security/plugins/threat_intelligence/*"],
"@kbn/timelines-plugin": ["x-pack/platform/plugins/shared/timelines"],
"@kbn/timelines-plugin/*": ["x-pack/platform/plugins/shared/timelines/*"],
"@kbn/timelion-grammar": ["src/platform/packages/private/kbn-timelion-grammar"],

View file

@ -46123,68 +46123,68 @@
"xpack.synthetics.windowValueExpression.numberOfChecksPopoverTitleLabel": "Nombre de vérifications",
"xpack.synthetics.windowValueExpression.numberOfLocPopoverTitleLabel": "Nombre d'emplacements",
"xpack.synthetics.windowValueExpression.percentLabel": "{numberOfLocations} {numberOfLocations, plural, one {emplacement} other {emplacements}}",
"xpack.threatIntelligence.addToBlockList": "Ajouter une entrée dans la liste noire",
"xpack.threatIntelligence.addToExistingCase": "Ajouter à un cas existant",
"xpack.threatIntelligence.addToNewCase": "Ajouter au nouveau cas",
"xpack.threatIntelligence.blocklist.flyoutTitle": "Ajouter une liste noire",
"xpack.threatIntelligence.cases.eventDescription": "ajouté un indicateur de compromis",
"xpack.threatIntelligence.cases.indicatorFeedName": "Nom du fil :",
"xpack.threatIntelligence.cases.indicatorName": "Nom de l'indicateur :",
"xpack.threatIntelligence.cases.indicatorType": "Type d'indicateur :",
"xpack.threatIntelligence.common.emptyPage.body1": "Elastic Threat Intelligence facilite l'analyse et l'investigation des menaces potentielles pour la sécurité en regroupant les données de plusieurs sources en un seul endroit.",
"xpack.threatIntelligence.common.emptyPage.body2": "Vous pourrez consulter les données de tous les flux Threat Intelligence activés et prendre des mesures à partir de cette page.",
"xpack.threatIntelligence.common.emptyPage.body3": "Pour vous lancer avec Elastic Threat Intelligence, activez une ou plusieurs intégrations Threat Intelligence depuis la page Intégrations ou bien ingérez des données avec Filebeat. Pour plus d'informations, consultez la ressource {docsLink}.",
"xpack.threatIntelligence.common.emptyPage.buttonText": "Ajouter des intégrations",
"xpack.threatIntelligence.common.emptyPage.docsLinkText": "Sécurité de la documentation",
"xpack.threatIntelligence.common.emptyPage.imgAlt": "Activer les intégrations Threat Intelligence",
"xpack.threatIntelligence.common.emptyPage.title": "Prise en main dElastic Threat Intelligence",
"xpack.threatIntelligence.empty.description": "Essayer de rechercher sur une période plus longue ou de modifier votre recherche",
"xpack.threatIntelligence.empty.title": "Aucun résultat ne correspond à vos critères de recherche.",
"xpack.threatIntelligence.field.@timestamp": "@timestamp",
"xpack.threatIntelligence.field.threat.feed.name": "Fil",
"xpack.threatIntelligence.field.threat.indicator.confidence": "Confiance",
"xpack.threatIntelligence.field.threat.indicator.first_seen": "Vu en premier",
"xpack.threatIntelligence.field.threat.indicator.last_seen": "Vu en dernier",
"xpack.threatIntelligence.field.threat.indicator.marking.tlp": "Marquage TLP",
"xpack.threatIntelligence.field.threat.indicator.name": "Indicateur",
"xpack.threatIntelligence.field.threat.indicator.type": "Type dindicateur",
"xpack.threatIntelligence.indicator.barChart.popover": "Plus d'actions",
"xpack.threatIntelligence.indicator.barchartSection.title": "Tendance",
"xpack.threatIntelligence.indicator.fieldSelector.label": "Empiler par",
"xpack.threatIntelligence.indicator.fieldsTable.fieldColumnLabel": "Champ",
"xpack.threatIntelligence.indicator.fieldsTable.valueColumnLabel": "Valeur",
"xpack.threatIntelligence.indicator.flyout.jsonTabLabel": "JSON",
"xpack.threatIntelligence.indicator.flyout.overviewTabLabel": "Aperçu",
"xpack.threatIntelligence.indicator.flyout.panelSubTitle": "Vu en premier :",
"xpack.threatIntelligence.indicator.flyout.panelTitleWithOverviewTab": "Détails de l'indicateur",
"xpack.threatIntelligence.indicator.flyout.tableTabLabel": "Tableau",
"xpack.threatIntelligence.indicator.flyoutOverviewTable.highlightedFields": "Champs en surbrillance",
"xpack.threatIntelligence.indicator.flyoutOverviewTable.viewAllFieldsInTable": "Afficher tous les champs dans le tableau",
"xpack.threatIntelligence.indicator.flyoutTable.errorMessageBody": "Une erreur s'est produite lors de l'affichage des champs et des valeurs des indicateurs.",
"xpack.threatIntelligence.indicator.flyoutTable.errorMessageTitle": "Impossible d'afficher les informations des indicateurs",
"xpack.threatIntelligence.indicator.table.actionColumnLabel": "Actions",
"xpack.threatIntelligence.indicator.table.moreActions": "Plus d'actions",
"xpack.threatIntelligence.indicator.table.viewDetailsButton": "Afficher les détails",
"xpack.threatIntelligence.indicatorNameFieldDescription": "Nom d'affichage de l'indicateur généré pendant le temps d'exécution",
"xpack.threatIntelligence.indicators.flyout.take-action.button": "Entreprendre une action",
"xpack.threatIntelligence.indicators.table.copyToClipboardLabel": "Copier dans le presse-papiers",
"xpack.threatIntelligence.inspectorFlyoutTitle": "Requêtes de recherche des indicateurs",
"xpack.threatIntelligence.inspectTitle": "Inspecter",
"xpack.threatIntelligence.investigateInTimelineButton": "Investiguer dans la chronologie",
"xpack.threatIntelligence.more-actions.popover": "Plus d'actions",
"xpack.threatIntelligence.navigation.indicatorsNavItemDescription": "Elastic Threat Intelligence vous aide à voir si vous êtes exposé ou avez été exposé à des menaces connues actuelles ou passées.",
"xpack.threatIntelligence.navigation.indicatorsNavItemKeywords": "Indicateurs",
"xpack.threatIntelligence.navigation.indicatorsNavItemLabel": "Indicateurs",
"xpack.threatIntelligence.navigation.intelligenceNavItemLabel": "Intelligence",
"xpack.threatIntelligence.paywall.body": "Démarrez un essai gratuit ou mettez à niveau votre licence vers Enterprise pour utiliser la Threat Intelligence.",
"xpack.threatIntelligence.paywall.title": "Toujours plus avec Security !",
"xpack.threatIntelligence.paywall.trial": "Démarrer un essai gratuit",
"xpack.threatIntelligence.paywall.upgrade": "Mettre à niveau",
"xpack.threatIntelligence.queryBar.filterOut": "Exclure",
"xpack.threatIntelligence.timeline.addToTimeline": "Ajouter à la chronologie",
"xpack.threatIntelligence.timeline.investigateInTimelineButtonIcon": "Investiguer dans la chronologie",
"xpack.threatIntelligence.updateStatus.updated": "Mis à jour",
"xpack.threatIntelligence.updateStatus.updating": "Mise à jour...",
"xpack.securitySolution.threatIntelligence.addToBlockList": "Ajouter une entrée dans la liste noire",
"xpack.securitySolution.threatIntelligence.addToExistingCase": "Ajouter à un cas existant",
"xpack.securitySolution.threatIntelligence.addToNewCase": "Ajouter au nouveau cas",
"xpack.securitySolution.threatIntelligence.blocklist.flyoutTitle": "Ajouter une liste noire",
"xpack.securitySolution.threatIntelligence.cases.eventDescription": "ajouté un indicateur de compromis",
"xpack.securitySolution.threatIntelligence.cases.indicatorFeedName": "Nom du fil :",
"xpack.securitySolution.threatIntelligence.cases.indicatorName": "Nom de l'indicateur :",
"xpack.securitySolution.threatIntelligence.cases.indicatorType": "Type d'indicateur :",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body1": "Elastic Threat Intelligence facilite l'analyse et l'investigation des menaces potentielles pour la sécurité en regroupant les données de plusieurs sources en un seul endroit.",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body2": "Vous pourrez consulter les données de tous les flux Threat Intelligence activés et prendre des mesures à partir de cette page.",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body3": "Pour vous lancer avec Elastic Threat Intelligence, activez une ou plusieurs intégrations Threat Intelligence depuis la page Intégrations ou bien ingérez des données avec Filebeat. Pour plus d'informations, consultez la ressource {docsLink}.",
"xpack.securitySolution.threatIntelligence.common.emptyPage.buttonText": "Ajouter des intégrations",
"xpack.securitySolution.threatIntelligence.common.emptyPage.docsLinkText": "Sécurité de la documentation",
"xpack.securitySolution.threatIntelligence.common.emptyPage.imgAlt": "Activer les intégrations Threat Intelligence",
"xpack.securitySolution.threatIntelligence.common.emptyPage.title": "Prise en main dElastic Threat Intelligence",
"xpack.securitySolution.threatIntelligence.empty.description": "Essayer de rechercher sur une période plus longue ou de modifier votre recherche",
"xpack.securitySolution.threatIntelligence.empty.title": "Aucun résultat ne correspond à vos critères de recherche.",
"xpack.securitySolution.threatIntelligence.field.@timestamp": "@timestamp",
"xpack.securitySolution.threatIntelligence.field.threat.feed.name": "Fil",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.confidence": "Confiance",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.first_seen": "Vu en premier",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.last_seen": "Vu en dernier",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.marking.tlp": "Marquage TLP",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.name": "Indicateur",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.type": "Type dindicateur",
"xpack.securitySolution.threatIntelligence.indicator.barChart.popover": "Plus d'actions",
"xpack.securitySolution.threatIntelligence.indicator.barchartSection.title": "Tendance",
"xpack.securitySolution.threatIntelligence.indicator.fieldSelector.label": "Empiler par",
"xpack.securitySolution.threatIntelligence.indicator.fieldsTable.fieldColumnLabel": "Champ",
"xpack.securitySolution.threatIntelligence.indicator.fieldsTable.valueColumnLabel": "Valeur",
"xpack.securitySolution.threatIntelligence.indicator.flyout.jsonTabLabel": "JSON",
"xpack.securitySolution.threatIntelligence.indicator.flyout.overviewTabLabel": "Aperçu",
"xpack.securitySolution.threatIntelligence.indicator.flyout.panelSubTitle": "Vu en premier :",
"xpack.securitySolution.threatIntelligence.indicator.flyout.panelTitleWithOverviewTab": "Détails de l'indicateur",
"xpack.securitySolution.threatIntelligence.indicator.flyout.tableTabLabel": "Tableau",
"xpack.securitySolution.threatIntelligence.indicator.flyoutOverviewTable.highlightedFields": "Champs en surbrillance",
"xpack.securitySolution.threatIntelligence.indicator.flyoutOverviewTable.viewAllFieldsInTable": "Afficher tous les champs dans le tableau",
"xpack.securitySolution.threatIntelligence.indicator.flyoutTable.errorMessageBody": "Une erreur s'est produite lors de l'affichage des champs et des valeurs des indicateurs.",
"xpack.securitySolution.threatIntelligence.indicator.flyoutTable.errorMessageTitle": "Impossible d'afficher les informations des indicateurs",
"xpack.securitySolution.threatIntelligence.indicator.table.actionColumnLabel": "Actions",
"xpack.securitySolution.threatIntelligence.indicator.table.moreActions": "Plus d'actions",
"xpack.securitySolution.threatIntelligence.indicator.table.viewDetailsButton": "Afficher les détails",
"xpack.securitySolution.threatIntelligence.indicatorNameFieldDescription": "Nom d'affichage de l'indicateur généré pendant le temps d'exécution",
"xpack.securitySolution.threatIntelligence.indicators.flyout.take-action.button": "Entreprendre une action",
"xpack.securitySolution.threatIntelligence.indicators.table.copyToClipboardLabel": "Copier dans le presse-papiers",
"xpack.securitySolution.threatIntelligence.inspectorFlyoutTitle": "Requêtes de recherche des indicateurs",
"xpack.securitySolution.threatIntelligence.inspectTitle": "Inspecter",
"xpack.securitySolution.threatIntelligence.investigateInTimelineButton": "Investiguer dans la chronologie",
"xpack.securitySolution.threatIntelligence.more-actions.popover": "Plus d'actions",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemDescription": "Elastic Threat Intelligence vous aide à voir si vous êtes exposé ou avez été exposé à des menaces connues actuelles ou passées.",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemKeywords": "Indicateurs",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemLabel": "Indicateurs",
"xpack.securitySolution.threatIntelligence.navigation.intelligenceNavItemLabel": "Intelligence",
"xpack.securitySolution.threatIntelligence.paywall.body": "Démarrez un essai gratuit ou mettez à niveau votre licence vers Enterprise pour utiliser la Threat Intelligence.",
"xpack.securitySolution.threatIntelligence.paywall.title": "Toujours plus avec Security !",
"xpack.securitySolution.threatIntelligence.paywall.trial": "Démarrer un essai gratuit",
"xpack.securitySolution.threatIntelligence.paywall.upgrade": "Mettre à niveau",
"xpack.securitySolution.threatIntelligence.queryBar.filterOut": "Exclure",
"xpack.securitySolution.threatIntelligence.timeline.addToTimeline": "Ajouter à la chronologie",
"xpack.securitySolution.threatIntelligence.timeline.investigateInTimelineButtonIcon": "Investiguer dans la chronologie",
"xpack.securitySolution.threatIntelligence.updateStatus.updated": "Mis à jour",
"xpack.securitySolution.threatIntelligence.updateStatus.updating": "Mise à jour...",
"xpack.timelines.clipboard.copied": "Copié",
"xpack.timelines.clipboard.copy": "Copier",
"xpack.timelines.clipboard.copy.successToastTitle": "Champ {field} copié dans le presse-papiers",

View file

@ -46079,68 +46079,68 @@
"xpack.synthetics.windowValueExpression.numberOfChecksPopoverTitleLabel": "チェックの数",
"xpack.synthetics.windowValueExpression.numberOfLocPopoverTitleLabel": "場所数",
"xpack.synthetics.windowValueExpression.percentLabel": "{numberOfLocations} {numberOfLocations, plural, other {個の場所}}",
"xpack.threatIntelligence.addToBlockList": "ブロックリストエントリの追加",
"xpack.threatIntelligence.addToExistingCase": "既存のケースに追加",
"xpack.threatIntelligence.addToNewCase": "新しいケースに追加",
"xpack.threatIntelligence.blocklist.flyoutTitle": "ブロックリストの追加",
"xpack.threatIntelligence.cases.eventDescription": "侵害のインジケーターを追加しました",
"xpack.threatIntelligence.cases.indicatorFeedName": "フィード名",
"xpack.threatIntelligence.cases.indicatorName": "インジケーター名:",
"xpack.threatIntelligence.cases.indicatorType": "インジケータータイプ:",
"xpack.threatIntelligence.common.emptyPage.body1": "Elastic Threat Intelligenceでは、複数のソースのデータを一元的に集約することで、潜在的なセキュリティ脅威を簡単に分析、調査できます。",
"xpack.threatIntelligence.common.emptyPage.body2": "すべてのアクティブな脅威インテリジェンスフィードのデータを表示し、このページからアクションを実行できます。",
"xpack.threatIntelligence.common.emptyPage.body3": "Elastic Threat Intelligenceを開始するには、統合ページから1つ以上の脅威インテリジェンス統合を有効にするか、Filebeatを使用してデータを取り込みます。詳細については、{docsLink}をご覧ください。",
"xpack.threatIntelligence.common.emptyPage.buttonText": "統合の追加",
"xpack.threatIntelligence.common.emptyPage.docsLinkText": "セキュリティアプリドキュメント",
"xpack.threatIntelligence.common.emptyPage.imgAlt": "脅威インテリジェンス統合を有効にする",
"xpack.threatIntelligence.common.emptyPage.title": "Elastic Threat Intelligenceの基本操作",
"xpack.threatIntelligence.empty.description": "期間を長くして検索するか、検索を変更してください",
"xpack.threatIntelligence.empty.title": "検索条件と一致する結果がありません。",
"xpack.threatIntelligence.field.@timestamp": "@timestamp",
"xpack.threatIntelligence.field.threat.feed.name": "フィード",
"xpack.threatIntelligence.field.threat.indicator.confidence": "信頼度",
"xpack.threatIntelligence.field.threat.indicator.first_seen": "初回の認識",
"xpack.threatIntelligence.field.threat.indicator.last_seen": "前回の認識",
"xpack.threatIntelligence.field.threat.indicator.marking.tlp": "TLPマーキング",
"xpack.threatIntelligence.field.threat.indicator.name": "インジケーター",
"xpack.threatIntelligence.field.threat.indicator.type": "インジケータータイプ",
"xpack.threatIntelligence.indicator.barChart.popover": "さらにアクションを表示",
"xpack.threatIntelligence.indicator.barchartSection.title": "傾向",
"xpack.threatIntelligence.indicator.fieldSelector.label": "積み上げ",
"xpack.threatIntelligence.indicator.fieldsTable.fieldColumnLabel": "フィールド",
"xpack.threatIntelligence.indicator.fieldsTable.valueColumnLabel": "値",
"xpack.threatIntelligence.indicator.flyout.jsonTabLabel": "JSON",
"xpack.threatIntelligence.indicator.flyout.overviewTabLabel": "概要",
"xpack.threatIntelligence.indicator.flyout.panelSubTitle": "初回の表示:",
"xpack.threatIntelligence.indicator.flyout.panelTitleWithOverviewTab": "インジケーターの詳細",
"xpack.threatIntelligence.indicator.flyout.tableTabLabel": "表",
"xpack.threatIntelligence.indicator.flyoutOverviewTable.highlightedFields": "ハイライトされたフィールド",
"xpack.threatIntelligence.indicator.flyoutOverviewTable.viewAllFieldsInTable": "テーブルのすべてのフィールドを表示",
"xpack.threatIntelligence.indicator.flyoutTable.errorMessageBody": "インジケーターフィールドと値の表示エラーが発生しました。",
"xpack.threatIntelligence.indicator.flyoutTable.errorMessageTitle": "インジケーター情報を表示できませn",
"xpack.threatIntelligence.indicator.table.actionColumnLabel": "アクション",
"xpack.threatIntelligence.indicator.table.moreActions": "さらにアクションを表示",
"xpack.threatIntelligence.indicator.table.viewDetailsButton": "詳細を表示",
"xpack.threatIntelligence.indicatorNameFieldDescription": "実行時に生成されたインジケーター表示名",
"xpack.threatIntelligence.indicators.flyout.take-action.button": "アクションを実行",
"xpack.threatIntelligence.indicators.table.copyToClipboardLabel": "クリップボードにコピー",
"xpack.threatIntelligence.inspectorFlyoutTitle": "インジケーター検索リクエスト",
"xpack.threatIntelligence.inspectTitle": "検査",
"xpack.threatIntelligence.investigateInTimelineButton": "タイムラインで調査",
"xpack.threatIntelligence.more-actions.popover": "さらにアクションを表示",
"xpack.threatIntelligence.navigation.indicatorsNavItemDescription": "Elastic threat intelligenceでは、最新の脅威または過去の確認済みの脅威にさらされ、脆弱であるかどうかを確認できます。",
"xpack.threatIntelligence.navigation.indicatorsNavItemKeywords": "インジケーター",
"xpack.threatIntelligence.navigation.indicatorsNavItemLabel": "インジケーター",
"xpack.threatIntelligence.navigation.intelligenceNavItemLabel": "インテリジェンス",
"xpack.threatIntelligence.paywall.body": "脅威インテリジェンスを使用するには、無料トライアルを開始するか、ライセンスをEnterpriseにアップグレードしてください。",
"xpack.threatIntelligence.paywall.title": "Securityではさまざまなことが可能です",
"xpack.threatIntelligence.paywall.trial": "無料トライアルをはじめる",
"xpack.threatIntelligence.paywall.upgrade": "アップグレード",
"xpack.threatIntelligence.queryBar.filterOut": "除外",
"xpack.threatIntelligence.timeline.addToTimeline": "タイムラインに追加",
"xpack.threatIntelligence.timeline.investigateInTimelineButtonIcon": "タイムラインで調査",
"xpack.threatIntelligence.updateStatus.updated": "更新しました",
"xpack.threatIntelligence.updateStatus.updating": "更新中...",
"xpack.securitySolution.threatIntelligence.addToBlockList": "ブロックリストエントリの追加",
"xpack.securitySolution.threatIntelligence.addToExistingCase": "既存のケースに追加",
"xpack.securitySolution.threatIntelligence.addToNewCase": "新しいケースに追加",
"xpack.securitySolution.threatIntelligence.blocklist.flyoutTitle": "ブロックリストの追加",
"xpack.securitySolution.threatIntelligence.cases.eventDescription": "侵害のインジケーターを追加しました",
"xpack.securitySolution.threatIntelligence.cases.indicatorFeedName": "フィード名",
"xpack.securitySolution.threatIntelligence.cases.indicatorName": "インジケーター名:",
"xpack.securitySolution.threatIntelligence.cases.indicatorType": "インジケータータイプ:",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body1": "Elastic Threat Intelligenceでは、複数のソースのデータを一元的に集約することで、潜在的なセキュリティ脅威を簡単に分析、調査できます。",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body2": "すべてのアクティブな脅威インテリジェンスフィードのデータを表示し、このページからアクションを実行できます。",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body3": "Elastic Threat Intelligenceを開始するには、統合ページから1つ以上の脅威インテリジェンス統合を有効にするか、Filebeatを使用してデータを取り込みます。詳細については、{docsLink}をご覧ください。",
"xpack.securitySolution.threatIntelligence.common.emptyPage.buttonText": "統合の追加",
"xpack.securitySolution.threatIntelligence.common.emptyPage.docsLinkText": "セキュリティアプリドキュメント",
"xpack.securitySolution.threatIntelligence.common.emptyPage.imgAlt": "脅威インテリジェンス統合を有効にする",
"xpack.securitySolution.threatIntelligence.common.emptyPage.title": "Elastic Threat Intelligenceの基本操作",
"xpack.securitySolution.threatIntelligence.empty.description": "期間を長くして検索するか、検索を変更してください",
"xpack.securitySolution.threatIntelligence.empty.title": "検索条件と一致する結果がありません。",
"xpack.securitySolution.threatIntelligence.field.@timestamp": "@timestamp",
"xpack.securitySolution.threatIntelligence.field.threat.feed.name": "フィード",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.confidence": "信頼度",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.first_seen": "初回の認識",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.last_seen": "前回の認識",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.marking.tlp": "TLPマーキング",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.name": "インジケーター",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.type": "インジケータータイプ",
"xpack.securitySolution.threatIntelligence.indicator.barChart.popover": "さらにアクションを表示",
"xpack.securitySolution.threatIntelligence.indicator.barchartSection.title": "傾向",
"xpack.securitySolution.threatIntelligence.indicator.fieldSelector.label": "積み上げ",
"xpack.securitySolution.threatIntelligence.indicator.fieldsTable.fieldColumnLabel": "フィールド",
"xpack.securitySolution.threatIntelligence.indicator.fieldsTable.valueColumnLabel": "値",
"xpack.securitySolution.threatIntelligence.indicator.flyout.jsonTabLabel": "JSON",
"xpack.securitySolution.threatIntelligence.indicator.flyout.overviewTabLabel": "概要",
"xpack.securitySolution.threatIntelligence.indicator.flyout.panelSubTitle": "初回の表示:",
"xpack.securitySolution.threatIntelligence.indicator.flyout.panelTitleWithOverviewTab": "インジケーターの詳細",
"xpack.securitySolution.threatIntelligence.indicator.flyout.tableTabLabel": "表",
"xpack.securitySolution.threatIntelligence.indicator.flyoutOverviewTable.highlightedFields": "ハイライトされたフィールド",
"xpack.securitySolution.threatIntelligence.indicator.flyoutOverviewTable.viewAllFieldsInTable": "テーブルのすべてのフィールドを表示",
"xpack.securitySolution.threatIntelligence.indicator.flyoutTable.errorMessageBody": "インジケーターフィールドと値の表示エラーが発生しました。",
"xpack.securitySolution.threatIntelligence.indicator.flyoutTable.errorMessageTitle": "インジケーター情報を表示できませn",
"xpack.securitySolution.threatIntelligence.indicator.table.actionColumnLabel": "アクション",
"xpack.securitySolution.threatIntelligence.indicator.table.moreActions": "さらにアクションを表示",
"xpack.securitySolution.threatIntelligence.indicator.table.viewDetailsButton": "詳細を表示",
"xpack.securitySolution.threatIntelligence.indicatorNameFieldDescription": "実行時に生成されたインジケーター表示名",
"xpack.securitySolution.threatIntelligence.indicators.flyout.take-action.button": "アクションを実行",
"xpack.securitySolution.threatIntelligence.indicators.table.copyToClipboardLabel": "クリップボードにコピー",
"xpack.securitySolution.threatIntelligence.inspectorFlyoutTitle": "インジケーター検索リクエスト",
"xpack.securitySolution.threatIntelligence.inspectTitle": "検査",
"xpack.securitySolution.threatIntelligence.investigateInTimelineButton": "タイムラインで調査",
"xpack.securitySolution.threatIntelligence.more-actions.popover": "さらにアクションを表示",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemDescription": "Elastic threat intelligenceでは、最新の脅威または過去の確認済みの脅威にさらされ、脆弱であるかどうかを確認できます。",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemKeywords": "インジケーター",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemLabel": "インジケーター",
"xpack.securitySolution.threatIntelligence.navigation.intelligenceNavItemLabel": "インテリジェンス",
"xpack.securitySolution.threatIntelligence.paywall.body": "脅威インテリジェンスを使用するには、無料トライアルを開始するか、ライセンスをEnterpriseにアップグレードしてください。",
"xpack.securitySolution.threatIntelligence.paywall.title": "Securityではさまざまなことが可能です",
"xpack.securitySolution.threatIntelligence.paywall.trial": "無料トライアルをはじめる",
"xpack.securitySolution.threatIntelligence.paywall.upgrade": "アップグレード",
"xpack.securitySolution.threatIntelligence.queryBar.filterOut": "除外",
"xpack.securitySolution.threatIntelligence.timeline.addToTimeline": "タイムラインに追加",
"xpack.securitySolution.threatIntelligence.timeline.investigateInTimelineButtonIcon": "タイムラインで調査",
"xpack.securitySolution.threatIntelligence.updateStatus.updated": "更新しました",
"xpack.securitySolution.threatIntelligence.updateStatus.updating": "更新中...",
"xpack.timelines.clipboard.copied": "コピー完了",
"xpack.timelines.clipboard.copy": "コピー",
"xpack.timelines.clipboard.copy.successToastTitle": "フィールド{field}をクリップボードにコピーしました",

View file

@ -46165,68 +46165,68 @@
"xpack.synthetics.windowValueExpression.numberOfChecksPopoverTitleLabel": "检查数目",
"xpack.synthetics.windowValueExpression.numberOfLocPopoverTitleLabel": "位置数",
"xpack.synthetics.windowValueExpression.percentLabel": "{numberOfLocations} 个{numberOfLocations, plural, other {位置}}",
"xpack.threatIntelligence.addToBlockList": "添加阻止列表条目",
"xpack.threatIntelligence.addToExistingCase": "添加到现有案例",
"xpack.threatIntelligence.addToNewCase": "添加到新案例",
"xpack.threatIntelligence.blocklist.flyoutTitle": "添加阻止列表",
"xpack.threatIntelligence.cases.eventDescription": "已添加受损指标",
"xpack.threatIntelligence.cases.indicatorFeedName": "源名称:",
"xpack.threatIntelligence.cases.indicatorName": "指标名称:",
"xpack.threatIntelligence.cases.indicatorType": "指标类型:",
"xpack.threatIntelligence.common.emptyPage.body1": "利用 Elastic 威胁情报,可以通过将多个来源的数据聚合到一个位置,轻松分析和调查潜在的安全威胁。",
"xpack.threatIntelligence.common.emptyPage.body2": "您将可以查看来自所有已激活威胁情报馈送的数据,并从此页面执行操作。",
"xpack.threatIntelligence.common.emptyPage.body3": "要开始使用 Elastic 威胁情报,请从“集成”页面启用一个或多个威胁情报集成,或使用 Filebeat 采集数据。有关更多信息,请查看 {docsLink}。",
"xpack.threatIntelligence.common.emptyPage.buttonText": "添加集成",
"xpack.threatIntelligence.common.emptyPage.docsLinkText": "Security 应用文档",
"xpack.threatIntelligence.common.emptyPage.imgAlt": "启用威胁情报集成",
"xpack.threatIntelligence.common.emptyPage.title": "Elastic 威胁情报入门",
"xpack.threatIntelligence.empty.description": "尝试搜索更长的时间段或修改您的搜索",
"xpack.threatIntelligence.empty.title": "没有任何结果匹配您的搜索条件",
"xpack.threatIntelligence.field.@timestamp": "@timestamp",
"xpack.threatIntelligence.field.threat.feed.name": "馈送",
"xpack.threatIntelligence.field.threat.indicator.confidence": "置信度",
"xpack.threatIntelligence.field.threat.indicator.first_seen": "首次看到时间",
"xpack.threatIntelligence.field.threat.indicator.last_seen": "最后看到时间",
"xpack.threatIntelligence.field.threat.indicator.marking.tlp": "TLP 标记",
"xpack.threatIntelligence.field.threat.indicator.name": "指标",
"xpack.threatIntelligence.field.threat.indicator.type": "指标类型",
"xpack.threatIntelligence.indicator.barChart.popover": "更多操作",
"xpack.threatIntelligence.indicator.barchartSection.title": "趋势",
"xpack.threatIntelligence.indicator.fieldSelector.label": "堆叠依据",
"xpack.threatIntelligence.indicator.fieldsTable.fieldColumnLabel": "字段",
"xpack.threatIntelligence.indicator.fieldsTable.valueColumnLabel": "值",
"xpack.threatIntelligence.indicator.flyout.jsonTabLabel": "JSON",
"xpack.threatIntelligence.indicator.flyout.overviewTabLabel": "概览",
"xpack.threatIntelligence.indicator.flyout.panelSubTitle": "首次看到时间:",
"xpack.threatIntelligence.indicator.flyout.panelTitleWithOverviewTab": "指标详情",
"xpack.threatIntelligence.indicator.flyout.tableTabLabel": "表",
"xpack.threatIntelligence.indicator.flyoutOverviewTable.highlightedFields": "突出显示的字段",
"xpack.threatIntelligence.indicator.flyoutOverviewTable.viewAllFieldsInTable": "查看表中的所有字段",
"xpack.threatIntelligence.indicator.flyoutTable.errorMessageBody": "显示指标字段和值时出现错误。",
"xpack.threatIntelligence.indicator.flyoutTable.errorMessageTitle": "无法显示指标信息",
"xpack.threatIntelligence.indicator.table.actionColumnLabel": "操作",
"xpack.threatIntelligence.indicator.table.moreActions": "更多操作",
"xpack.threatIntelligence.indicator.table.viewDetailsButton": "查看详情",
"xpack.threatIntelligence.indicatorNameFieldDescription": "在运行时中生成的指标显示名称",
"xpack.threatIntelligence.indicators.flyout.take-action.button": "采取操作",
"xpack.threatIntelligence.indicators.table.copyToClipboardLabel": "复制到剪贴板",
"xpack.threatIntelligence.inspectorFlyoutTitle": "指标搜索请求",
"xpack.threatIntelligence.inspectTitle": "检查",
"xpack.threatIntelligence.investigateInTimelineButton": "在时间线中调查",
"xpack.threatIntelligence.more-actions.popover": "更多操作",
"xpack.threatIntelligence.navigation.indicatorsNavItemDescription": "Elastic 威胁情报有助于您了解您是否易于受到或已面临当前或历史上的已知威胁。",
"xpack.threatIntelligence.navigation.indicatorsNavItemKeywords": "指标",
"xpack.threatIntelligence.navigation.indicatorsNavItemLabel": "指标",
"xpack.threatIntelligence.navigation.intelligenceNavItemLabel": "情报",
"xpack.threatIntelligence.paywall.body": "开始免费试用或将许可证升级到企业版以使用威胁情报。",
"xpack.threatIntelligence.paywall.title": "Security 让您事半功倍!",
"xpack.threatIntelligence.paywall.trial": "开始免费试用",
"xpack.threatIntelligence.paywall.upgrade": "升级",
"xpack.threatIntelligence.queryBar.filterOut": "筛除",
"xpack.threatIntelligence.timeline.addToTimeline": "添加到时间线",
"xpack.threatIntelligence.timeline.investigateInTimelineButtonIcon": "在时间线中调查",
"xpack.threatIntelligence.updateStatus.updated": "已更新",
"xpack.threatIntelligence.updateStatus.updating": "正在更新......",
"xpack.securitySolution.threatIntelligence.addToBlockList": "添加阻止列表条目",
"xpack.securitySolution.threatIntelligence.addToExistingCase": "添加到现有案例",
"xpack.securitySolution.threatIntelligence.addToNewCase": "添加到新案例",
"xpack.securitySolution.threatIntelligence.blocklist.flyoutTitle": "添加阻止列表",
"xpack.securitySolution.threatIntelligence.cases.eventDescription": "已添加受损指标",
"xpack.securitySolution.threatIntelligence.cases.indicatorFeedName": "源名称:",
"xpack.securitySolution.threatIntelligence.cases.indicatorName": "指标名称:",
"xpack.securitySolution.threatIntelligence.cases.indicatorType": "指标类型:",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body1": "利用 Elastic 威胁情报,可以通过将多个来源的数据聚合到一个位置,轻松分析和调查潜在的安全威胁。",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body2": "您将可以查看来自所有已激活威胁情报馈送的数据,并从此页面执行操作。",
"xpack.securitySolution.threatIntelligence.common.emptyPage.body3": "要开始使用 Elastic 威胁情报,请从“集成”页面启用一个或多个威胁情报集成,或使用 Filebeat 采集数据。有关更多信息,请查看 {docsLink}。",
"xpack.securitySolution.threatIntelligence.common.emptyPage.buttonText": "添加集成",
"xpack.securitySolution.threatIntelligence.common.emptyPage.docsLinkText": "Security 应用文档",
"xpack.securitySolution.threatIntelligence.common.emptyPage.imgAlt": "启用威胁情报集成",
"xpack.securitySolution.threatIntelligence.common.emptyPage.title": "Elastic 威胁情报入门",
"xpack.securitySolution.threatIntelligence.empty.description": "尝试搜索更长的时间段或修改您的搜索",
"xpack.securitySolution.threatIntelligence.empty.title": "没有任何结果匹配您的搜索条件",
"xpack.securitySolution.threatIntelligence.field.@timestamp": "@timestamp",
"xpack.securitySolution.threatIntelligence.field.threat.feed.name": "馈送",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.confidence": "置信度",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.first_seen": "首次看到时间",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.last_seen": "最后看到时间",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.marking.tlp": "TLP 标记",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.name": "指标",
"xpack.securitySolution.threatIntelligence.field.threat.indicator.type": "指标类型",
"xpack.securitySolution.threatIntelligence.indicator.barChart.popover": "更多操作",
"xpack.securitySolution.threatIntelligence.indicator.barchartSection.title": "趋势",
"xpack.securitySolution.threatIntelligence.indicator.fieldSelector.label": "堆叠依据",
"xpack.securitySolution.threatIntelligence.indicator.fieldsTable.fieldColumnLabel": "字段",
"xpack.securitySolution.threatIntelligence.indicator.fieldsTable.valueColumnLabel": "值",
"xpack.securitySolution.threatIntelligence.indicator.flyout.jsonTabLabel": "JSON",
"xpack.securitySolution.threatIntelligence.indicator.flyout.overviewTabLabel": "概览",
"xpack.securitySolution.threatIntelligence.indicator.flyout.panelSubTitle": "首次看到时间:",
"xpack.securitySolution.threatIntelligence.indicator.flyout.panelTitleWithOverviewTab": "指标详情",
"xpack.securitySolution.threatIntelligence.indicator.flyout.tableTabLabel": "表",
"xpack.securitySolution.threatIntelligence.indicator.flyoutOverviewTable.highlightedFields": "突出显示的字段",
"xpack.securitySolution.threatIntelligence.indicator.flyoutOverviewTable.viewAllFieldsInTable": "查看表中的所有字段",
"xpack.securitySolution.threatIntelligence.indicator.flyoutTable.errorMessageBody": "显示指标字段和值时出现错误。",
"xpack.securitySolution.threatIntelligence.indicator.flyoutTable.errorMessageTitle": "无法显示指标信息",
"xpack.securitySolution.threatIntelligence.indicator.table.actionColumnLabel": "操作",
"xpack.securitySolution.threatIntelligence.indicator.table.moreActions": "更多操作",
"xpack.securitySolution.threatIntelligence.indicator.table.viewDetailsButton": "查看详情",
"xpack.securitySolution.threatIntelligence.indicatorNameFieldDescription": "在运行时中生成的指标显示名称",
"xpack.securitySolution.threatIntelligence.indicators.flyout.take-action.button": "采取操作",
"xpack.securitySolution.threatIntelligence.indicators.table.copyToClipboardLabel": "复制到剪贴板",
"xpack.securitySolution.threatIntelligence.inspectorFlyoutTitle": "指标搜索请求",
"xpack.securitySolution.threatIntelligence.inspectTitle": "检查",
"xpack.securitySolution.threatIntelligence.investigateInTimelineButton": "在时间线中调查",
"xpack.securitySolution.threatIntelligence.more-actions.popover": "更多操作",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemDescription": "Elastic 威胁情报有助于您了解您是否易于受到或已面临当前或历史上的已知威胁。",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemKeywords": "指标",
"xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemLabel": "指标",
"xpack.securitySolution.threatIntelligence.navigation.intelligenceNavItemLabel": "情报",
"xpack.securitySolution.threatIntelligence.paywall.body": "开始免费试用或将许可证升级到企业版以使用威胁情报。",
"xpack.securitySolution.threatIntelligence.paywall.title": "Security 让您事半功倍!",
"xpack.securitySolution.threatIntelligence.paywall.trial": "开始免费试用",
"xpack.securitySolution.threatIntelligence.paywall.upgrade": "升级",
"xpack.securitySolution.threatIntelligence.queryBar.filterOut": "筛除",
"xpack.securitySolution.threatIntelligence.timeline.addToTimeline": "添加到时间线",
"xpack.securitySolution.threatIntelligence.timeline.investigateInTimelineButtonIcon": "在时间线中调查",
"xpack.securitySolution.threatIntelligence.updateStatus.updated": "已更新",
"xpack.securitySolution.threatIntelligence.updateStatus.updating": "正在更新......",
"xpack.timelines.clipboard.copied": "已复制",
"xpack.timelines.clipboard.copy": "复制",
"xpack.timelines.clipboard.copy.successToastTitle": "已将字段 {field} 复制到剪贴板",

View file

@ -13,8 +13,8 @@ export const BARCHART_AGGREGATION_NAME = 'barchartAggregation';
* Used inside custom search strategy
*/
export enum FactoryQueryType {
IndicatorGrid = 'indicatorGrid',
Barchart = 'barchart',
IndicatorGrid = 'threatIntelligenceIndicatorGrid',
Barchart = 'threatIntelligenceBarchart',
}
export const CASE_ATTACHMENT_TYPE_ID = 'indicator';

View file

@ -39,7 +39,6 @@
"sessionView",
"spaces",
"taskManager",
"threatIntelligence",
"timelines",
"triggersActionsUi",
"uiActions",

View file

@ -26,6 +26,7 @@ import type {
} from '@kbn/discover-shared-plugin/public/services/discover_features';
import { ProductFeatureSecurityKey } from '@kbn/security-solution-features/keys';
import { ProductFeatureAssistantKey } from '@kbn/security-solution-features/src/product_features_keys';
import type { ExternalReferenceAttachmentType } from '@kbn/cases-plugin/public/client/attachment_framework/types';
import { getLazyCloudSecurityPosturePliAuthBlockExtension } from './cloud_security_posture/lazy_cloud_security_posture_pli_auth_block_extension';
import { getLazyEndpointAgentTamperProtectionExtension } from './management/pages/policy/view/ingest_manager_integration/lazy_endpoint_agent_tamper_protection_extension';
import type {
@ -66,6 +67,7 @@ import { PluginContract } from './plugin_contract';
import { PluginServices } from './plugin_services';
import { getExternalReferenceAttachmentEndpointRegular } from './cases/attachments/external_reference';
import { hasAccessToSecuritySolution } from './helpers_access';
import { generateAttachmentType } from './threat_intelligence/modules/cases/utils/attachments';
export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, StartPlugins> {
private config: SecuritySolutionUiConfigType;
@ -232,6 +234,9 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
getExternalReferenceAttachmentEndpointRegular()
);
const externalAttachmentType: ExternalReferenceAttachmentType = generateAttachmentType();
cases?.attachmentFramework?.registerExternalReference(externalAttachmentType);
this.registerDiscoverSharedFeatures(core, plugins);
return this.contract.getSetupContract();

View file

@ -2,10 +2,6 @@
Elastic Threat Intelligence makes it easy to analyze and investigate potential security threats by aggregating data from multiple sources in one place. Youll be able to view data from all activated threat intelligence feeds and take action.
### Where to find the UI for this plugin?
The Threat Intelligence UI is displayed in Kibana Security, under the Explore section.
## Development setup
### Kibana development in general
@ -63,29 +59,3 @@ node scripts/generate_indicators.js
```
see the file in order to adjust the amount of indicators generated. The default is one million.
## E2E
### Running locally
Cypress tests are integrated with the Security Solution ones. Please refer to https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_cypress/cypress/README.md for more information
## FAQ
### How is the Threat Intelligence code loaded in Kibana?
The Threat Intelligence plugin is loaded lazily within the [security_solution](https://github.com/elastic/kibana/tree/main/x-pack/solutions/security/plugins/security_solution) plugin,
from `x-pack/solutions/security/plugins/security_solution/public/threat_intelligence` owned by the Threat Hunting Investigations Team.
## QA and demo for implemented features
One way to QA and demo the feature merged into `main` branch is to run the latest `main` locally.
Another option is to deploy a Staging instance. For Staging environment snapshots are being build every night with the latest state of the `main` branch. More documentation can be found [here](https://cloud.elastic.dev/environments/Staging/#automatic-termination-of-staging-deployments)
## Contributing
See [CONTRIBUTING.md](https://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/threat_intelligence/CONTRIBUTING.md) for information on contributing.
## Issues
Please report any issues in [this GitHub project](https://github.com/orgs/elastic/projects/758/).

View file

@ -7,7 +7,7 @@
import React from 'react';
import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public';
import { CoreStart } from '@kbn/core/public';
import type { CoreStart } from '@kbn/core/public';
import { mockUiSettingsService } from '../mocks/mock_kibana_ui_settings_service';
import { DateFormatter } from './date_formatter';

View file

@ -6,7 +6,7 @@
*/
import moment from 'moment';
import React, { VFC } from 'react';
import React, { type FC } from 'react';
import { EMPTY_VALUE } from '../constants/common';
import { dateFormatter } from '../utils/dates';
import { useDateFormat, useTimeZone } from '../hooks/use_kibana_ui_settings';
@ -18,7 +18,7 @@ export interface DateFormatterProps {
dateFormat?: string;
}
export const DateFormatter: VFC<DateFormatterProps> = ({ date, dateFormat }) => {
export const DateFormatter: FC<DateFormatterProps> = ({ date, dateFormat }) => {
const userTimeZone = useTimeZone();
const userFormat = useDateFormat();

View file

@ -32,14 +32,14 @@ export const EmptyState: React.FC<{ height?: keyof typeof heights }> = ({ height
<EuiTitle>
<h3>
<FormattedMessage
id="xpack.threatIntelligence.empty.title"
id="xpack.securitySolution.threatIntelligence.empty.title"
defaultMessage="No results match your search criteria"
/>
</h3>
</EuiTitle>
<p>
<FormattedMessage
id="xpack.threatIntelligence.empty.description"
id="xpack.securitySolution.threatIntelligence.empty.description"
defaultMessage="Try searching over a longer period of time or modifying your search"
/>
</p>

View file

@ -18,11 +18,11 @@ export default {
export const Default: StoryFn = () => {
const title = 'Title with border below';
const children = <EuiText>Content with border above</EuiText>;
const children = <EuiText>{'Content with border above'}</EuiText>;
return (
<StoryProvidersComponent>
<DefaultPageLayout pageTitle={title} children={children} />
<DefaultPageLayout pageTitle={title}>{children}</DefaultPageLayout>
</StoryProvidersComponent>
);
};
@ -30,11 +30,13 @@ export const Default: StoryFn = () => {
export const NoBorder: StoryFn = () => {
const title = 'Title without border';
const border = false;
const children = <EuiText>Content without border</EuiText>;
const children = <EuiText>{'Content without border'}</EuiText>;
return (
<StoryProvidersComponent>
<DefaultPageLayout pageTitle={title} border={border} children={children} />
<DefaultPageLayout pageTitle={title} border={border}>
{children}
</DefaultPageLayout>
</StoryProvidersComponent>
);
};

View file

@ -6,7 +6,8 @@
*/
import { EuiPageHeader, EuiPageHeaderSection, EuiSpacer, EuiText } from '@elastic/eui';
import React, { FC, PropsWithChildren, ReactNode } from 'react';
import type { FC, PropsWithChildren, ReactNode } from 'react';
import React from 'react';
import { SecuritySolutionPageWrapper } from '../containers/security_solution_page_wrapper';
import { TITLE_TEST_ID } from './test_ids';

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import React, { VFC } from 'react';
import type { FC } from 'react';
import React from 'react';
import {
EuiButton,
EuiButtonEmpty,
@ -15,9 +16,9 @@ import {
EuiIcon,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useKibana } from '../hooks/use_kibana';
import { useKibana } from '../../common/lib/kibana';
export const Paywall: VFC = () => {
export const Paywall: FC = () => {
const {
services: { application },
} = useKibana();
@ -29,7 +30,7 @@ export const Paywall: VFC = () => {
title={
<h2>
<FormattedMessage
id="xpack.threatIntelligence.paywall.title"
id="xpack.securitySolution.threatIntelligence.paywall.title"
defaultMessage="Do more with Security!"
/>
</h2>
@ -37,7 +38,7 @@ export const Paywall: VFC = () => {
body={
<p>
<FormattedMessage
id="xpack.threatIntelligence.paywall.body"
id="xpack.securitySolution.threatIntelligence.paywall.body"
defaultMessage="Start a free trial or upgrade your license to Enterprise to use threat intelligence."
/>
</p>
@ -48,7 +49,7 @@ export const Paywall: VFC = () => {
<div>
<EuiButton color="primary" fill href="https://www.elastic.co/subscriptions">
<FormattedMessage
id="xpack.threatIntelligence.paywall.upgrade"
id="xpack.securitySolution.threatIntelligence.paywall.upgrade"
defaultMessage="Upgrade"
/>
</EuiButton>
@ -64,7 +65,7 @@ export const Paywall: VFC = () => {
}
>
<FormattedMessage
id="xpack.threatIntelligence.paywall.trial"
id="xpack.securitySolution.threatIntelligence.paywall.trial"
defaultMessage="Start a free trial"
/>
</EuiButtonEmpty>

View file

@ -0,0 +1,22 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
export const UPDATING = i18n.translate(
'xpack.securitySolution.threatIntelligence.updateStatus.updating',
{
defaultMessage: 'Updating...',
}
);
export const UPDATED = i18n.translate(
'xpack.securitySolution.threatIntelligence.updateStatus.updated',
{
defaultMessage: 'Updated',
}
);

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { TIPage, TIPageProperties } from '../types';
import type { TIPage, TIPageProperties } from '../types';
import { DESCRIPTION, INDICATORS, INTELLIGENCE } from './translations';
/**

View file

@ -8,21 +8,21 @@
import { i18n } from '@kbn/i18n';
export const INDICATORS = i18n.translate(
'xpack.threatIntelligence.navigation.indicatorsNavItemLabel',
'xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemLabel',
{
defaultMessage: 'Indicators',
}
);
export const INTELLIGENCE = i18n.translate(
'xpack.threatIntelligence.navigation.intelligenceNavItemLabel',
'xpack.securitySolution.threatIntelligence.navigation.intelligenceNavItemLabel',
{
defaultMessage: 'Intelligence',
}
);
export const DESCRIPTION = i18n.translate(
'xpack.threatIntelligence.navigation.indicatorsNavItemDescription',
'xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemDescription',
{
defaultMessage:
'Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats.',
@ -30,7 +30,7 @@ export const DESCRIPTION = i18n.translate(
);
export const KEYWORDS = i18n.translate(
'xpack.threatIntelligence.navigation.indicatorsNavItemKeywords',
'xpack.securitySolution.threatIntelligence.navigation.indicatorsNavItemKeywords',
{
defaultMessage: 'Indicators',
}

View file

@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { type ReactNode } from 'react';
import { EMPTY_PAGE_SECURITY_TEMPLATE } from '../../mocks/test_providers';
export const SecuritySolutionPluginTemplateWrapper = (props: {
children?: ReactNode;
emptyPageBody: ReactNode;
isEmptyState: boolean;
}) => (
<div data-test-subj={EMPTY_PAGE_SECURITY_TEMPLATE}>
{props.isEmptyState ? props.emptyPageBody : props.children}
</div>
);

View file

@ -8,27 +8,24 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { EMPTY_PAGE_SECURITY_TEMPLATE, TestProvidersComponent } from '../mocks/test_providers';
import { SecuritySolutionPluginContext } from '../types';
import { SecuritySolutionContext } from './security_solution_context';
import { EnterpriseGuard } from './enterprise_guard';
import { useSecurityContext } from '../hooks/use_security_context';
jest.mock('./security_solution_plugin_template_wrapper');
jest.mock('../hooks/use_security_context');
describe('<EnterpriseGuard />', () => {
describe('when on enterprise plan', () => {
beforeEach(() => {
jest.mocked(useSecurityContext().licenseService.isEnterprise).mockReturnValue(true);
});
it('should render specified children', () => {
render(
<TestProvidersComponent>
<SecuritySolutionContext.Provider
value={
{
licenseService: { isEnterprise: jest.fn().mockReturnValue(true) },
} as unknown as SecuritySolutionPluginContext
}
>
<EnterpriseGuard>
<div>enterprise only content</div>
</EnterpriseGuard>
</SecuritySolutionContext.Provider>
</TestProvidersComponent>
<EnterpriseGuard>
<div>{'enterprise only content'}</div>
</EnterpriseGuard>,
{ wrapper: TestProvidersComponent }
);
expect(screen.queryByText('enterprise only content')).toBeInTheDocument();
@ -38,21 +35,16 @@ describe('<EnterpriseGuard />', () => {
});
describe('when not on enterprise plan', () => {
it('should render specified children', () => {
beforeEach(() => {
jest.mocked(useSecurityContext().licenseService.isEnterprise).mockReturnValue(false);
});
it('should render the paywall', () => {
render(
<TestProvidersComponent>
<SecuritySolutionContext.Provider
value={
{
licenseService: { isEnterprise: jest.fn().mockReturnValue(false) },
} as unknown as SecuritySolutionPluginContext
}
>
<EnterpriseGuard>
<div>enterprise only content</div>
</EnterpriseGuard>
</SecuritySolutionContext.Provider>
</TestProvidersComponent>
<EnterpriseGuard>
<div>{'enterprise only content'}</div>
</EnterpriseGuard>,
{ wrapper: TestProvidersComponent }
);
expect(screen.queryByText('enterprise only content')).not.toBeInTheDocument();

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import React, { memo, PropsWithChildren } from 'react';
import type { PropsWithChildren } from 'react';
import React, { memo } from 'react';
import { Paywall } from '../components/paywall';
import { useSecurityContext } from '../hooks/use_security_context';
@ -20,3 +21,5 @@ export const EnterpriseGuard = memo<PropsWithChildren<unknown>>(({ children }) =
return <SecuritySolutionPluginTemplateWrapper isEmptyState emptyPageBody={<Paywall />} />;
});
EnterpriseGuard.displayName = 'EnterpriseGuard';

View file

@ -5,8 +5,9 @@
* 2.0.
*/
import React, { createContext, FC, PropsWithChildren, useMemo } from 'react';
import { useSourcererDataView } from '../modules/indicators/hooks/use_sourcerer_data_view';
import type { FC, PropsWithChildren } from 'react';
import React, { createContext, useMemo } from 'react';
import { useTIDataView } from '../modules/indicators/hooks/use_ti_data_view';
export type FieldTypesContextValue = Record<string, string | undefined>;
@ -18,7 +19,7 @@ export const FieldTypesContext = createContext<FieldTypesContextValue | undefine
export const FieldTypesProvider: FC<PropsWithChildren<unknown>> = ({ children }) => {
const {
sourcererDataView: { fields = {} },
} = useSourcererDataView();
} = useTIDataView();
// field name to field type map to allow the cell_renderer to format dates
const fieldTypes: FieldTypesContextValue = useMemo(

View file

@ -5,13 +5,14 @@
* 2.0.
*/
import React, { memo, useMemo, VFC } from 'react';
import type { FC } from 'react';
import React, { memo, useMemo } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { CasesPermissions } from '@kbn/cases-plugin/common';
import type { CasesPermissions } from '@kbn/cases-plugin/common';
import { IndicatorsPage } from '../modules/indicators/pages/indicators';
import { IntegrationsGuard } from './integrations_guard';
import { SecuritySolutionPluginTemplateWrapper } from './security_solution_plugin_template_wrapper';
import { useKibana } from '../hooks/use_kibana';
import { useKibana } from '../../common/lib/kibana';
export const APP_ID = 'securitySolution';
@ -19,7 +20,7 @@ const queryClient = new QueryClient();
const casesContextOwner = [APP_ID];
export const IndicatorsPageWrapper: VFC = () => {
export const IndicatorsPageWrapper: FC = () => {
const { cases } = useKibana().services;
const CasesContext = useMemo(() => cases.ui.getCasesContext(), [cases.ui]);
const permissions: CasesPermissions = useMemo(() => cases.helpers.canUseCases(), [cases.helpers]);

View file

@ -6,7 +6,8 @@
*/
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import React, { createContext, FC, PropsWithChildren, useMemo } from 'react';
import type { FC, PropsWithChildren } from 'react';
import React, { createContext, useMemo } from 'react';
export interface InspectorContextValue {
requests: RequestAdapter;

View file

@ -5,12 +5,13 @@
* 2.0.
*/
import { UseQueryResult } from '@tanstack/react-query';
import type { UseQueryResult } from '@tanstack/react-query';
import { render } from '@testing-library/react';
import React from 'react';
import { IntegrationsGuard } from './integrations_guard';
import { EMPTY_PAGE_SECURITY_TEMPLATE, TestProvidersComponent } from '../mocks/test_providers';
import { Integration, useIntegrations } from '../hooks/use_integrations';
import type { Integration } from '../hooks/use_integrations';
import { useIntegrations } from '../hooks/use_integrations';
import { useIntegrationsPageLink } from '../hooks/use_integrations_page_link';
import { useTIDocumentationLink } from '../hooks/use_documentation_link';
import { useIndicatorsTotalCount } from '../modules/indicators/hooks/use_total_count';
@ -22,6 +23,7 @@ jest.mock('../modules/indicators/hooks/use_total_count');
jest.mock('../hooks/use_integrations_page_link');
jest.mock('../hooks/use_documentation_link');
jest.mock('../hooks/use_integrations');
jest.mock('./security_solution_plugin_template_wrapper');
describe('IntegrationsGuard', () => {
it('should render loading when indicator count and integrations are being loaded', async () => {
@ -42,9 +44,12 @@ describe('IntegrationsGuard', () => {
data: [],
} as unknown as UseQueryResult<Integration[]>);
const { getByTestId } = render(<IntegrationsGuard>should be restricted</IntegrationsGuard>, {
wrapper: TestProvidersComponent,
});
const { getByTestId } = render(
<IntegrationsGuard>{'should be restricted'}</IntegrationsGuard>,
{
wrapper: TestProvidersComponent,
}
);
expect(getByTestId(LOADING_LOGO_TEST_ID)).toBeInTheDocument();
expect(getByTestId(EMPTY_PAGE_SECURITY_TEMPLATE)).toBeInTheDocument();
@ -68,9 +73,12 @@ describe('IntegrationsGuard', () => {
data: [],
} as unknown as UseQueryResult<Integration[]>);
const { getByTestId } = render(<IntegrationsGuard>should be restricted</IntegrationsGuard>, {
wrapper: TestProvidersComponent,
});
const { getByTestId } = render(
<IntegrationsGuard>{'should be restricted'}</IntegrationsGuard>,
{
wrapper: TestProvidersComponent,
}
);
expect(getByTestId(LOADING_LOGO_TEST_ID)).toBeInTheDocument();
expect(getByTestId(EMPTY_PAGE_SECURITY_TEMPLATE)).toBeInTheDocument();
@ -95,9 +103,12 @@ describe('IntegrationsGuard', () => {
data: [],
} as unknown as UseQueryResult<Integration[]>);
const { getByTestId } = render(<IntegrationsGuard>should be restricted</IntegrationsGuard>, {
wrapper: TestProvidersComponent,
});
const { getByTestId } = render(
<IntegrationsGuard>{'should be restricted'}</IntegrationsGuard>,
{
wrapper: TestProvidersComponent,
}
);
expect(getByTestId(LOADING_LOGO_TEST_ID)).toBeInTheDocument();
expect(getByTestId(EMPTY_PAGE_SECURITY_TEMPLATE)).toBeInTheDocument();
@ -121,9 +132,12 @@ describe('IntegrationsGuard', () => {
data: [],
} as unknown as UseQueryResult<Integration[]>);
const { getByTestId } = render(<IntegrationsGuard>should be restricted</IntegrationsGuard>, {
wrapper: TestProvidersComponent,
});
const { getByTestId } = render(
<IntegrationsGuard>{'should be restricted'}</IntegrationsGuard>,
{
wrapper: TestProvidersComponent,
}
);
expect(getByTestId(EMPTY_PROMPT_TEST_ID)).toBeInTheDocument();
expect(getByTestId(EMPTY_PAGE_SECURITY_TEMPLATE)).toBeInTheDocument();
});
@ -140,7 +154,7 @@ describe('IntegrationsGuard', () => {
data: [],
} as unknown as UseQueryResult<Integration[]>);
const { asFragment } = render(<IntegrationsGuard>should be restricted</IntegrationsGuard>, {
const { asFragment } = render(<IntegrationsGuard>{'should be restricted'}</IntegrationsGuard>, {
wrapper: TestProvidersComponent,
});
expect(asFragment()).toMatchInlineSnapshot(`
@ -168,7 +182,7 @@ describe('IntegrationsGuard', () => {
],
} as unknown as UseQueryResult<Integration[]>);
const { asFragment } = render(<IntegrationsGuard>should be restricted</IntegrationsGuard>, {
const { asFragment } = render(<IntegrationsGuard>{'should be restricted'}</IntegrationsGuard>, {
wrapper: TestProvidersComponent,
});
expect(asFragment()).toMatchInlineSnapshot(`

View file

@ -6,7 +6,8 @@
*/
import { EuiLoadingLogo, EuiPageTemplate } from '@elastic/eui';
import React, { memo, PropsWithChildren } from 'react';
import type { PropsWithChildren } from 'react';
import React, { memo } from 'react';
import { LOADING_LOGO_TEST_ID } from './test_ids';
import { useIntegrations } from '../hooks/use_integrations';
import { EmptyPage } from '../modules/empty_page/empty_page';
@ -44,3 +45,5 @@ export const IntegrationsGuard = memo<PropsWithChildren<unknown>>(({ children })
const showIndicatorsPage = indicatorsTotalCount > 0 || (installedTIIntegrations || []).length > 0;
return showIndicatorsPage ? <>{children}</> : <EmptyPage />;
});
IntegrationsGuard.displayName = 'IntegrationsGuard';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { FC, PropsWithChildren } from 'react';
import React, { type FC, type PropsWithChildren } from 'react';
import { useSecurityContext } from '../hooks/use_security_context';
/**

View file

@ -5,8 +5,6 @@
* 2.0.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../../../',
roots: ['<rootDir>/x-pack/solutions/security/plugins/threat_intelligence'],
};
import { SecuritySolutionTemplateWrapper } from '../../app/home/template_wrapper';
export const SecuritySolutionPluginTemplateWrapper = SecuritySolutionTemplateWrapper;

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
const returnValue = {
licenseService: { isEnterprise: jest.fn().mockReturnValue(false) },
sourcererDataView: { id: 'security-solution-default' },
};
export const useSecurityContext = () => returnValue;

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
export const INSPECTOR_FLYOUT_TITLE = i18n.translate(
'xpack.threatIntelligence.inspectorFlyoutTitle',
'xpack.securitySolution.threatIntelligence.inspectorFlyoutTitle',
{
defaultMessage: 'Indicators search requests',
}

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import { DocLinks } from '@kbn/doc-links';
import { useKibana } from './use_kibana';
import type { DocLinks } from '@kbn/doc-links';
import { useKibana } from '../../common/lib/kibana';
const useKibanaDocumentationLinks = (): DocLinks => useKibana().services.docLinks.links;

View file

@ -6,8 +6,8 @@
*/
import { useCallback, useContext, useEffect, useState } from 'react';
import { InspectorSession } from '@kbn/inspector-plugin/public';
import { useKibana } from './use_kibana';
import type { InspectorSession } from '@kbn/inspector-plugin/public';
import { useKibana } from '../../common/lib/kibana';
import { InspectorContext } from '../containers/inspector';
import { INSPECTOR_FLYOUT_TITLE } from './translations';

View file

@ -5,19 +5,21 @@
* 2.0.
*/
import type { FC, PropsWithChildren } from 'react';
import React from 'react';
import { waitFor, renderHook } from '@testing-library/react';
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
import { INSTALLATION_STATUS, THREAT_INTELLIGENCE_CATEGORY } from '../utils/filter_integrations';
const createWrapper = () => {
const createWrapper = (): FC<PropsWithChildren<{}>> => {
const queryClient = new QueryClient();
return ({ children }: { children: any }) => (
// eslint-disable-next-line react/display-name
return ({ children }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
const renderUseQuery = (result: { items: any[] }) =>
const renderUseQuery = (result: { items: unknown[] }) =>
renderHook(() => useQuery(['integrations'], () => result), {
wrapper: createWrapper(),
});

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import { QueryFunctionContext, useQuery, useQueryClient } from '@tanstack/react-query';
import { type QueryFunctionContext, useQuery, useQueryClient } from '@tanstack/react-query';
import { useCallback, useEffect, useRef } from 'react';
import { filterIntegrations } from '../utils/filter_integrations';
import { useKibana } from './use_kibana';
import { useKibana } from '../../common/lib/kibana';
type IntegrationInstallStatus = 'installed' | 'installing' | 'install_failed';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { useKibana } from './use_kibana';
import { useKibana } from '../../common/lib/kibana';
const useKibanaBasePath = (): string => useKibana().services.http.basePath.get();

View file

@ -0,0 +1,174 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useCallback } from 'react';
import moment from 'moment';
import type { DataProvider } from '@kbn/timelines-plugin/common';
import { generateDataProvider } from '../modules/timeline/utils/data_provider';
import {
fieldAndValueValid,
getIndicatorFieldAndValue,
} from '../modules/indicators/utils/field_value';
import { unwrapValue } from '../modules/indicators/utils/unwrap_value';
import {
type Indicator,
IndicatorFieldEventEnrichmentMap,
RawIndicatorFieldId,
} from '../../../common/threat_intelligence/types/indicator';
import { timelineDefaults } from '../../timelines/store/defaults';
import { APP_UI_ID } from '../../../common/constants';
import { TimelineId } from '../../../common/types/timeline';
import { TimelineTypeEnum } from '../../../common/api/timeline';
import { useStartTransaction } from '../../common/lib/apm/use_start_transaction';
import { useCreateTimeline } from '../../timelines/hooks/use_create_timeline';
import type { CreateTimelineProps } from '../../detections/components/alerts_table/types';
import { useUpdateTimeline } from '../../timelines/components/open_timeline/use_update_timeline';
interface UseInvestigateInTimelineActionProps {
/**
* Created when the user clicks on the Investigate in Timeline button.
* DataProvider contain the field(s) and value(s) displayed in the timeline.
*/
dataProviders: DataProvider[];
/**
* Start date used in the createTimeline method.
*/
from: string;
/**
* End date used in the createTimeline method.
*/
to: string;
}
/**
* This code is closely duplicated from here: https://github.com/elastic/kibana/blob/main/x-pack/solutions/security/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/use_investigate_in_timeline.tsx,
* the main changes being:
* - no exceptions are handled at the moment
* - we use dataProviders, from and to directly instead of consuming ecsData
*/
const useInvestigateInTimelineInternal = ({
dataProviders,
from,
to,
}: UseInvestigateInTimelineActionProps) => {
const { startTransaction } = useStartTransaction();
const clearActiveTimeline = useCreateTimeline({
timelineId: TimelineId.active,
timelineType: TimelineTypeEnum.default,
});
const updateTimeline = useUpdateTimeline();
const createTimeline = useCallback(
async ({ from: fromTimeline, timeline, to: toTimeline, ruleNote }: CreateTimelineProps) => {
await clearActiveTimeline();
updateTimeline({
duplicate: true,
from: fromTimeline,
id: TimelineId.active,
notes: [],
timeline: {
...timeline,
indexNames: timeline.indexNames ?? [],
show: true,
},
to: toTimeline,
ruleNote,
});
},
[updateTimeline, clearActiveTimeline]
);
const investigateInTimelineClick = useCallback(async () => {
startTransaction({ name: `${APP_UI_ID} threat indicator investigateInTimeline` });
createTimeline({
from,
notes: null,
timeline: {
...timelineDefaults,
dataProviders,
id: TimelineId.active,
indexNames: [],
dateRange: {
start: from,
end: to,
},
eventType: 'all',
filters: [],
kqlQuery: {
filterQuery: {
kuery: {
kind: 'kuery',
expression: '',
},
serializedQuery: '',
},
},
},
to,
ruleNote: '',
});
}, [startTransaction, createTimeline, dataProviders, from, to]);
return investigateInTimelineClick;
};
export interface UseInvestigateInTimelineParam {
/**
* Indicator used to retrieve the field and value then passed to the Investigate in Timeline logic
*/
indicator: Indicator;
}
export interface UseInvestigateInTimelineValue {
/**
* Investigate in Timeline function to run on click event.
*/
investigateInTimelineFn: () => Promise<void> | undefined;
}
/**
* Custom hook that gets an {@link Indicator}, retrieves the field (from the RawIndicatorFieldId.Name)
* and value, then creates DataProviders used to do the Investigate in Timeline logic
* (see /kibana/x-pack/solutions/security/plugins/security_solution/public/threat_intelligence/use_investigate_in_timeline.ts)
*/
export const useInvestigateInTimeline = ({
indicator,
}: UseInvestigateInTimelineParam): UseInvestigateInTimelineValue => {
const { key, value } = getIndicatorFieldAndValue(indicator, RawIndicatorFieldId.Name);
const sourceEventField = IndicatorFieldEventEnrichmentMap[key] ?? [];
const dataProviders: DataProvider[] = [...sourceEventField, key].map((e: string) =>
generateDataProvider(e, value as string)
);
const indicatorTimestamp: string = unwrapValue(
indicator,
RawIndicatorFieldId.TimeStamp
) as string;
const from = moment(indicatorTimestamp).subtract(7, 'd').toISOString();
const to = moment(indicatorTimestamp).add(7, 'd').toISOString();
const investigateInTimelineFn = useInvestigateInTimelineInternal({
dataProviders,
from,
to,
});
if (!to || !from) {
return {} as unknown as UseInvestigateInTimelineValue;
}
if (!fieldAndValueValid(key, value) || !sourceEventField) {
return {} as unknown as UseInvestigateInTimelineValue;
}
return { investigateInTimelineFn };
};

View file

@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useMemo } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import type { SecuritySolutionPluginContext } from '../types';
import { useKibana } from '../../common/lib/kibana';
import { useUserPrivileges } from '../../common/components/user_privileges';
import { useSetUrlParams } from '../../management/components/artifact_list_page/hooks/use_set_url_params';
import { BlockListForm } from '../../management/pages/blocklist/view/components/blocklist_form';
import { BlocklistsApiClient } from '../../management/pages/blocklist/services';
import { inputsSelectors } from '../../common/store';
import { licenseService } from '../../common/hooks/use_license';
import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper';
import { useGlobalTime } from '../../common/containers/use_global_time';
import { deleteOneQuery, setQuery } from '../../common/store/inputs/actions';
import { InputsModelId } from '../../common/store/inputs/constants';
import { ArtifactFlyout } from '../../management/components/artifact_list_page/components/artifact_flyout';
import { extractTimelineCapabilities } from '../../common/utils/timeline_capabilities';
export const useSecurityContext = (): SecuritySolutionPluginContext => {
const {
http,
application: { capabilities },
} = useKibana().services;
const { read: hasAccessToTimeline } = extractTimelineCapabilities(capabilities);
const dispatch = useDispatch();
const canWriteBlocklist = useUserPrivileges().endpointPrivileges.canWriteBlocklist;
return useMemo(() => {
return {
getPageWrapper: () => SecuritySolutionPageWrapper,
licenseService,
hasAccessToTimeline,
blockList: {
canWriteBlocklist,
exceptionListApiClient: BlocklistsApiClient.getInstance(http),
useSetUrlParams,
// @ts-ignore
getFlyoutComponent: () => ArtifactFlyout,
// @ts-ignore
getFormComponent: () => BlockListForm,
} as unknown as SecuritySolutionPluginContext['blockList'],
useQuery: () => useSelector(inputsSelectors.globalQuerySelector()),
useFilters: () => useSelector(inputsSelectors.globalFiltersQuerySelector()),
useGlobalTime,
registerQuery: (query) =>
dispatch(
setQuery({
inputId: InputsModelId.global,
id: query.id,
refetch: query.refetch,
inspect: null,
loading: query.loading,
})
),
deregisterQuery: (query) =>
dispatch(
deleteOneQuery({
inputId: InputsModelId.global,
id: query.id,
})
),
};
}, [hasAccessToTimeline, canWriteBlocklist, http, dispatch]);
};

View file

@ -5,15 +5,14 @@
* 2.0.
*/
import type { SecuritySubPlugin } from '../app/types';
import { routes } from './routes';
export class ThreatIntelligence {
public setup() {}
public start(): SecuritySubPlugin {
public start() {
return {
routes,
};
}
public stop() {}
}

View file

@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
module.exports = {
preset: '@kbn/test',
rootDir: '../../../../../../..',
roots: [
'<rootDir>/x-pack/solutions/security/plugins/security_solution/public/threat_intelligence',
],
coverageDirectory:
'<rootDir>/target/kibana-coverage/jest/x-pack/solutions/security/plugins/security_solution/public/threat_intelligence',
coverageReporters: ['text', 'html'],
collectCoverageFrom: [
'<rootDir>/x-pack/solutions/security/plugins/security_solution/public/threat_intelligence/**/*.{ts,tsx}',
],
moduleNameMapper: require('../../server/__mocks__/module_name_map'),
};

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import { getSecuritySolutionLink } from '@kbn/threat-intelligence-plugin/public';
import type { SecurityPageName } from '../../common/constants';
import { SECURITY_FEATURE_ID } from '../../common/constants';
import type { LinkItem } from '../common/links';
import { getSecuritySolutionLink } from './utils/security_solution_links';
/**
* Adds the Threat Intelligence entry to Kibana global sidenav as well as the Security sidenav.

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { FieldTypesContextValue } from '../containers/field_types_provider';
import type { FieldTypesContextValue } from '../containers/field_types_provider';
/**
* Mock to map an indicator field to its type.

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import { FilterManager } from '@kbn/data-plugin/public';
import { IndicatorsFiltersContextValue } from '../modules/indicators/hooks/use_filters_context';
import type { FilterManager } from '@kbn/data-plugin/public';
import type { IndicatorsFiltersContextValue } from '../modules/indicators/hooks/use_filters_context';
export const mockTimeRange = { from: '2022-10-03T07:48:31.498Z', to: '2022-10-03T07:48:31.498Z' };

View file

@ -6,9 +6,9 @@
*/
import React from 'react';
import { HoverActionsConfig } from '@kbn/timelines-plugin/public/components/hover_actions';
import type { HoverActionsConfig } from '@kbn/timelines-plugin/public/components/hover_actions';
import { EuiButtonIcon } from '@elastic/eui';
import { TimelinesUIStart } from '@kbn/timelines-plugin/public';
import type { TimelinesUIStart } from '@kbn/timelines-plugin/public';
/**
* Returns a default object to mock the timelines plugin for our unit tests and storybook stories.

View file

@ -7,15 +7,16 @@
import React from 'react';
import { EuiText } from '@elastic/eui';
import { TriggersAndActionsUIPublicPluginStart as TriggersActionsStart } from '@kbn/triggers-actions-ui-plugin/public';
import type { TriggersAndActionsUIPublicPluginStart as TriggersActionsStart } from '@kbn/triggers-actions-ui-plugin/public';
const styles = { display: 'inline' };
/**
* Returns a default object to mock the triggers actions ui plugin for our unit tests and storybook stories.
*/
export const mockTriggersActionsUiService: TriggersActionsStart = {
getFieldBrowser: () => (
<EuiText style={{ display: 'inline' }} size="xs">
Fields
<EuiText css={styles} size="xs">
{'Fields'}
</EuiText>
),
} as unknown as TriggersActionsStart;

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { IUiSettingsClient } from '@kbn/core/public';
import type { IUiSettingsClient } from '@kbn/core/public';
import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ } from '../constants/common';
/**

View file

@ -5,15 +5,16 @@
* 2.0.
*/
import { Filter } from '@kbn/es-query';
import type { Filter } from '@kbn/es-query';
import { BehaviorSubject } from 'rxjs';
import * as hook from '../hooks/use_kibana';
import * as hook from '../../common/lib/kibana';
jest.mock('../hooks/use_kibana');
jest.mock('../../common/lib/kibana');
interface MockConfig {
$filterUpdates?: BehaviorSubject<void>;
getFilters?: jest.Mock<Filter[]>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setFilters?: jest.Mock<any, Filter[]>;
}
@ -43,6 +44,7 @@ export const mockUseKibanaForFilters = ({
},
dataViews: { getFieldsForWildcard },
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
return { getFieldsForWildcard, setFilters, getFilters, $filterUpdates };

View file

@ -5,18 +5,17 @@
* 2.0.
*/
import React, { FC, ReactNode, VFC } from 'react';
import type { ReactNode, FC } from 'react';
import React from 'react';
import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
import { CoreStart, IUiSettingsClient } from '@kbn/core/public';
import { TimelinesUIStart } from '@kbn/timelines-plugin/public';
import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { CoreStart, IUiSettingsClient } from '@kbn/core/public';
import type { TimelinesUIStart } from '@kbn/timelines-plugin/public';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { SettingsStart } from '@kbn/core-ui-settings-browser';
import { mockIndicatorsFiltersContext } from './mock_indicators_filters_context';
import { SecuritySolutionContext } from '../containers/security_solution_context';
import { getSecuritySolutionContextMock } from './mock_security_context';
import { IndicatorsFiltersContext } from '../modules/indicators/hooks/use_filters_context';
import { FieldTypesContext } from '../containers/field_types_provider';
import { generateFieldTypeMap } from './mock_field_type_map';
@ -57,6 +56,7 @@ export interface StoryProvidersComponentProps {
const securityLayout = {
getPluginWrapper:
(): FC =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
({ children, isEmptyState, emptyPageBody }: any) => {
if (isEmptyState && emptyPageBody) {
return <>{emptyPageBody}</>;
@ -92,7 +92,7 @@ const defaultServices = {
* Helper functional component used in Storybook stories.
* Wraps the story with our {@link SecuritySolutionContext} and KibanaReactContext.
*/
export const StoryProvidersComponent: VFC<StoryProvidersComponentProps> = ({
export const StoryProvidersComponent: FC<StoryProvidersComponentProps> = ({
children,
kibana = {},
}) => {
@ -101,20 +101,16 @@ export const StoryProvidersComponent: VFC<StoryProvidersComponentProps> = ({
...kibana,
securityLayout,
});
const securitySolutionContextMock = getSecuritySolutionContextMock();
return (
<EuiThemeProvider>
<QueryClientProvider client={new QueryClient()}>
<InspectorContext.Provider value={{ requests: new RequestAdapter() }}>
<FieldTypesContext.Provider value={generateFieldTypeMap()}>
<SecuritySolutionContext.Provider value={securitySolutionContextMock}>
<IndicatorsFiltersContext.Provider value={mockIndicatorsFiltersContext}>
<KibanaReactContext.Provider>
<BlockListProvider>{children}</BlockListProvider>
</KibanaReactContext.Provider>
</IndicatorsFiltersContext.Provider>
</SecuritySolutionContext.Provider>
<IndicatorsFiltersContext.Provider value={mockIndicatorsFiltersContext}>
<KibanaReactContext.Provider>
<BlockListProvider>{children}</BlockListProvider>
</KibanaReactContext.Provider>
</IndicatorsFiltersContext.Provider>
</FieldTypesContext.Provider>
</InspectorContext.Provider>
</QueryClientProvider>

View file

@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { FC, PropsWithChildren } from 'react';
import React from 'react';
import type { IStorage } from '@kbn/kibana-utils-plugin/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter } from 'react-router-dom';
import type { ISearchStart } from '@kbn/data-plugin/public';
import moment from 'moment';
import { IndicatorsFiltersContext } from '../modules/indicators/hooks/use_filters_context';
import { mockIndicatorsFiltersContext } from './mock_indicators_filters_context';
import { FieldTypesContext } from '../containers/field_types_provider';
import { generateFieldTypeMap } from './mock_field_type_map';
import { InspectorContext } from '../containers/inspector';
import { TestProviders } from '../../common/mock/test_providers';
export const localStorageMock = (): IStorage => {
let store: Record<string, unknown> = {};
return {
getItem: (key: string) => {
return store[key] || null;
},
setItem: (key: string, value: unknown) => {
store[key] = value;
},
clear() {
store = {};
},
removeItem(key: string) {
delete store[key];
},
};
};
export const mockedSearchService = {
search: jest.fn(),
showError: jest.fn(),
} as unknown as ISearchStart;
const fixedMoment = moment(new Date('2025-05-16 00:00:00'));
export const mockedTimefilterService = {
timefilter: {
calculateBounds: jest.fn().mockReturnValue({ min: fixedMoment, max: fixedMoment }),
},
};
export const mockedQueryService = {
timefilter: mockedTimefilterService,
};
export const createTiStorageMock = () => {
const localStorage = localStorageMock();
return {
localStorage,
storage: new Storage(localStorage),
};
};
export const mockedServices = {
...createTiStorageMock(),
};
export const unifiedSearch = unifiedSearchPluginMock.createStartContract();
export const EMPTY_PAGE_SECURITY_TEMPLATE = 'empty-page-security-template' as const;
export const TestProvidersComponent: FC<PropsWithChildren<{}>> = ({ children }) => (
<TestProviders>
<MemoryRouter>
<InspectorContext.Provider value={{ requests: new RequestAdapter() }}>
<QueryClientProvider client={new QueryClient()}>
<FieldTypesContext.Provider value={generateFieldTypeMap()}>
<IndicatorsFiltersContext.Provider value={mockIndicatorsFiltersContext}>
{children}
</IndicatorsFiltersContext.Provider>
</FieldTypesContext.Provider>
</QueryClientProvider>
</InspectorContext.Provider>
</MemoryRouter>
</TestProviders>
);

View file

@ -8,9 +8,6 @@
import React from 'react';
import type { StoryFn } from '@storybook/react';
import { EuiContextMenuPanel } from '@elastic/eui';
import { SecuritySolutionContext } from '../../../containers/security_solution_context';
import { SecuritySolutionPluginContext } from '../../..';
import { getSecuritySolutionContextMock } from '../../../mocks/mock_security_context';
import { AddToBlockListContextMenu } from './add_to_block_list';
import { BlockListProvider } from '../../indicators/containers/block_list_provider';
@ -19,8 +16,6 @@ export default {
};
export const ContextMenu: StoryFn = () => {
const mockSecurityContext: SecuritySolutionPluginContext = getSecuritySolutionContextMock();
const mockIndicatorFileHashValue: string = 'abc';
const mockOnClick: () => void = () => window.alert('clicked!');
const items = [
@ -28,18 +23,13 @@ export const ContextMenu: StoryFn = () => {
];
return (
<SecuritySolutionContext.Provider value={mockSecurityContext}>
<BlockListProvider>
<EuiContextMenuPanel items={items} />
</BlockListProvider>
</SecuritySolutionContext.Provider>
<BlockListProvider>
<EuiContextMenuPanel items={items} />
</BlockListProvider>
);
};
export const Disabled: StoryFn = () => {
const mockSecurityContext: SecuritySolutionPluginContext = getSecuritySolutionContextMock();
mockSecurityContext.blockList.canWriteBlocklist = false;
const mockIndicatorFileHashValue: string = 'abc';
const mockOnClick: () => void = () => window.alert('clicked!');
const items = [
@ -47,10 +37,8 @@ export const Disabled: StoryFn = () => {
];
return (
<SecuritySolutionContext.Provider value={mockSecurityContext}>
<BlockListProvider>
<EuiContextMenuPanel items={items} />
</BlockListProvider>
</SecuritySolutionContext.Provider>
<BlockListProvider>
<EuiContextMenuPanel items={items} />
</BlockListProvider>
);
};

View file

@ -9,22 +9,18 @@ import React from 'react';
import { render } from '@testing-library/react';
import { AddToBlockListContextMenu } from './add_to_block_list';
import { BlockListProvider } from '../../indicators/containers/block_list_provider';
import { SecuritySolutionContext } from '../../../containers/security_solution_context';
import { SecuritySolutionPluginContext } from '../../..';
import { getSecuritySolutionContextMock } from '../../../mocks/mock_security_context';
import { I18nProvider } from '@kbn/i18n-react';
import { TestProvidersComponent } from '../../../mocks/test_providers';
const TEST_ID = 'test';
describe('<AddToBlockListContextMenu />', () => {
it('should render an EuiContextMenuItem', () => {
const mockSecurityContext: SecuritySolutionPluginContext = getSecuritySolutionContextMock();
const mockIndicatorFileHashValue: string = 'abc';
const mockOnClick: () => void = () => window.alert('clicked!');
const { getByTestId, getAllByText } = render(
<I18nProvider>
<SecuritySolutionContext.Provider value={mockSecurityContext}>
<TestProvidersComponent>
<I18nProvider>
<BlockListProvider>
<AddToBlockListContextMenu
data={mockIndicatorFileHashValue}
@ -32,8 +28,8 @@ describe('<AddToBlockListContextMenu />', () => {
data-test-subj={TEST_ID}
/>
</BlockListProvider>
</SecuritySolutionContext.Provider>
</I18nProvider>
</I18nProvider>
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toBeInTheDocument();
@ -41,14 +37,12 @@ describe('<AddToBlockListContextMenu />', () => {
});
it('should render a disabled EuiContextMenuItem if data is null', () => {
const mockSecurityContext: SecuritySolutionPluginContext = getSecuritySolutionContextMock();
const mockIndicatorFileHashValue = null;
const mockOnClick: () => void = () => window.alert('clicked!');
const { getByTestId } = render(
<I18nProvider>
<SecuritySolutionContext.Provider value={mockSecurityContext}>
<TestProvidersComponent>
<I18nProvider>
<BlockListProvider>
<AddToBlockListContextMenu
data={mockIndicatorFileHashValue}
@ -56,23 +50,20 @@ describe('<AddToBlockListContextMenu />', () => {
data-test-subj={TEST_ID}
/>
</BlockListProvider>
</SecuritySolutionContext.Provider>
</I18nProvider>
</I18nProvider>
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toHaveAttribute('disabled');
});
it('should render a disabled EuiContextMenuItem if no write blocklist privilege', () => {
const mockSecurityContext: SecuritySolutionPluginContext = getSecuritySolutionContextMock();
mockSecurityContext.blockList.canWriteBlocklist = false;
const mockIndicatorFileHashValue: string = 'abc';
const mockOnClick: () => void = () => window.alert('clicked!');
const { getByTestId } = render(
<I18nProvider>
<SecuritySolutionContext.Provider value={mockSecurityContext}>
<TestProvidersComponent>
<I18nProvider>
<BlockListProvider>
<AddToBlockListContextMenu
data={mockIndicatorFileHashValue}
@ -80,8 +71,8 @@ describe('<AddToBlockListContextMenu />', () => {
data-test-subj={TEST_ID}
/>
</BlockListProvider>
</SecuritySolutionContext.Provider>
</I18nProvider>
</I18nProvider>
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toHaveAttribute('disabled');

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import React, { VFC } from 'react';
import type { FC } from 'react';
import React from 'react';
import { EuiContextMenuItem } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { useSecurityContext } from '../../../hooks/use_security_context';
@ -33,7 +34,7 @@ export interface AddToBlockListProps {
* When clicking on the ContextMenuItem, the indicator filehash value is saved in context.
* The flyout is shown by adding a parameter to the url.
*/
export const AddToBlockListContextMenu: VFC<AddToBlockListProps> = ({
export const AddToBlockListContextMenu: FC<AddToBlockListProps> = ({
data,
'data-test-subj': dataTestSub,
onClick,
@ -61,7 +62,7 @@ export const AddToBlockListContextMenu: VFC<AddToBlockListProps> = ({
>
<FormattedMessage
defaultMessage="Add blocklist entry"
id="xpack.threatIntelligence.addToBlockList"
id="xpack.securitySolution.threatIntelligence.addToBlockList"
/>
</EuiContextMenuItem>
);

View file

@ -5,8 +5,9 @@
* 2.0.
*/
import React, { VFC } from 'react';
import {
import type { FC } from 'react';
import React from 'react';
import type {
CreateExceptionListItemSchema,
EntriesArray,
} from '@kbn/securitysolution-io-ts-list-types';
@ -28,7 +29,7 @@ export interface BlockListFlyoutProps {
* - the flyout component: x-pack/solutions/security/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_flyout.tsx
* - the form component: x-pack/solutions/security/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.tsx
*/
export const BlockListFlyout: VFC<BlockListFlyoutProps> = ({ indicatorFileHash }) => {
export const BlockListFlyout: FC<BlockListFlyoutProps> = ({ indicatorFileHash }) => {
const { setBlockListIndicatorValue } = useBlockListContext();
const { blockList } = useSecurityContext();
const Component = blockList.getFlyoutComponent();

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
export const ADD_TO_BLOCKLIST_FLYOUT_TITLE = i18n.translate(
'xpack.threatIntelligence.blocklist.flyoutTitle',
'xpack.securitySolution.threatIntelligence.blocklist.flyoutTitle',
{
defaultMessage: 'Add blocklist',
}

View file

@ -11,11 +11,13 @@ import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-quer
const createWrapper = () => {
const queryClient = new QueryClient();
// eslint-disable-next-line @typescript-eslint/no-explicit-any, react/display-name
return ({ children }: { children: any }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const renderUseQuery = (result: { items: any[] }) =>
renderHook(() => useQuery(['policies'], () => result), {
wrapper: createWrapper(),

View file

@ -6,7 +6,7 @@
*/
import { useQuery } from '@tanstack/react-query';
import { useKibana } from '../../../hooks/use_kibana';
import { useKibana } from '../../../../common/lib/kibana';
const POLICIES_URL = '/api/fleet/package_policies';
const PACKAGE_POLICY_SAVED_OBJECT_TYPE = 'ingest-package-policies';

View file

@ -5,11 +5,11 @@
* 2.0.
*/
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import {
generateMockFileIndicator,
Indicator,
RawIndicatorFieldId,
} from '../../../../common/types/indicator';
} from '../../../../../common/threat_intelligence/types/indicator';
import { canAddToBlockList } from './can_add_to_block_list';
import { getIndicatorFieldAndValue } from '../../indicators/utils/field_value';

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import { Indicator, RawIndicatorFieldId } from '../../../../common/types/indicator';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import { RawIndicatorFieldId } from '../../../../../common/threat_intelligence/types/indicator';
import { getIndicatorFieldAndValue } from '../../indicators/utils/field_value';
/**

View file

@ -9,7 +9,7 @@ import React from 'react';
import type { StoryFn } from '@storybook/react';
import { EuiContextMenuPanel } from '@elastic/eui';
import { StoryProvidersComponent } from '../../../mocks/story_providers';
import { generateMockUrlIndicator } from '../../../../common/types/indicator';
import { generateMockUrlIndicator } from '../../../../../common/threat_intelligence/types/indicator';
import { AddToExistingCase } from './add_to_existing_case';
export default {

View file

@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { render } from '@testing-library/react';
import { AddToExistingCase } from './add_to_existing_case';
import { TestProvidersComponent } from '../../../mocks/test_providers';
import {
generateMockFileIndicator,
type Indicator,
} from '../../../../../common/threat_intelligence/types/indicator';
const TEST_ID = 'test';
const indicator: Indicator = generateMockFileIndicator();
const onClick = () => window.alert('clicked');
describe('AddToExistingCase', () => {
it('should render an EuiContextMenuItem', () => {
const { getByTestId, getAllByText } = render(
<TestProvidersComponent>
<AddToExistingCase indicator={indicator} onClick={onClick} data-test-subj={TEST_ID} />
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toBeInTheDocument();
expect(getAllByText('Add to existing case')).toHaveLength(1);
});
it('should render the EuiContextMenuItem disabled if indicator is missing name', () => {
const fields = { ...indicator.fields };
delete fields['threat.indicator.name'];
const indicatorMissingName = {
_id: indicator._id,
fields,
};
const { getByTestId } = render(
<TestProvidersComponent>
<AddToExistingCase
indicator={indicatorMissingName}
onClick={onClick}
data-test-subj={TEST_ID}
/>
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toHaveAttribute('disabled');
});
it('should render the EuiContextMenuItem disabled if user has no update permission', () => {
const { getByTestId } = render(
<TestProvidersComponent>
<AddToExistingCase indicator={indicator} onClick={onClick} data-test-subj={TEST_ID} />
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toHaveAttribute('disabled');
});
});

View file

@ -5,18 +5,16 @@
* 2.0.
*/
import React, { VFC } from 'react';
import type { FC } from 'react';
import React from 'react';
import { EuiContextMenuItem } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import { useCaseDisabled } from '../hooks/use_case_permission';
import {
AttachmentMetadata,
generateAttachmentsMetadata,
generateAttachmentsWithoutOwner,
} from '../utils/attachments';
import { useKibana } from '../../../hooks/use_kibana';
import { Indicator } from '../../../../common/types/indicator';
import type { AttachmentMetadata } from '../utils/attachments';
import { generateAttachmentsMetadata, generateAttachmentsWithoutOwner } from '../utils/attachments';
import { useKibana } from '../../../../common/lib/kibana';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
export interface AddToExistingCaseProps {
/**
@ -42,7 +40,7 @@ export interface AddToExistingCaseProps {
*
* @returns add to existing case for a context menu
*/
export const AddToExistingCase: VFC<AddToExistingCaseProps> = ({
export const AddToExistingCase: FC<AddToExistingCaseProps> = ({
indicator,
onClick,
'data-test-subj': dataTestSubj,
@ -73,7 +71,7 @@ export const AddToExistingCase: VFC<AddToExistingCaseProps> = ({
>
<FormattedMessage
defaultMessage="Add to existing case"
id="xpack.threatIntelligence.addToExistingCase"
id="xpack.securitySolution.threatIntelligence.addToExistingCase"
/>
</EuiContextMenuItem>
);

View file

@ -10,7 +10,7 @@ import type { StoryFn } from '@storybook/react';
import { EuiContextMenuPanel } from '@elastic/eui';
import { AddToNewCase } from './add_to_new_case';
import { StoryProvidersComponent } from '../../../mocks/story_providers';
import { generateMockUrlIndicator } from '../../../../common/types/indicator';
import { generateMockUrlIndicator } from '../../../../../common/threat_intelligence/types/indicator';
export default {
title: 'AddToNewCase',

View file

@ -0,0 +1,56 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { render } from '@testing-library/react';
import React from 'react';
import {
generateMockFileIndicator,
type Indicator,
} from '../../../../../common/threat_intelligence/types/indicator';
import { TestProvidersComponent } from '../../../mocks/test_providers';
import { AddToNewCase } from './add_to_new_case';
const TEST_ID = 'test';
const indicator: Indicator = generateMockFileIndicator();
const onClick = () => window.alert('clicked');
describe('AddToNewCase', () => {
it('should render an EuiContextMenuItem', () => {
const { getByTestId, getAllByText } = render(
<TestProvidersComponent>
<AddToNewCase indicator={indicator} onClick={onClick} data-test-subj={TEST_ID} />
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toBeInTheDocument();
expect(getAllByText('Add to new case')).toHaveLength(1);
});
it('should render the EuiContextMenuItem disabled if indicator is missing name', () => {
const fields = { ...indicator.fields };
delete fields['threat.indicator.name'];
const indicatorMissingName = {
_id: indicator._id,
fields,
};
const { getByTestId } = render(
<TestProvidersComponent>
<AddToNewCase indicator={indicatorMissingName} onClick={onClick} data-test-subj={TEST_ID} />
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toHaveAttribute('disabled');
});
it('should render the EuiContextMenuItem disabled if user have no create permission', () => {
const { getByTestId } = render(
<TestProvidersComponent>
<AddToNewCase indicator={indicator} onClick={onClick} data-test-subj={TEST_ID} />
</TestProvidersComponent>
);
expect(getByTestId(TEST_ID)).toHaveAttribute('disabled');
});
});

View file

@ -5,18 +5,16 @@
* 2.0.
*/
import React, { VFC } from 'react';
import type { FC } from 'react';
import React from 'react';
import { EuiContextMenuItem } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import { useCaseDisabled } from '../hooks/use_case_permission';
import {
AttachmentMetadata,
generateAttachmentsMetadata,
generateAttachmentsWithoutOwner,
} from '../utils/attachments';
import { useKibana } from '../../../hooks/use_kibana';
import { Indicator } from '../../../../common/types/indicator';
import type { AttachmentMetadata } from '../utils/attachments';
import { generateAttachmentsMetadata, generateAttachmentsWithoutOwner } from '../utils/attachments';
import { useKibana } from '../../../../common/lib/kibana';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
export interface AddToNewCaseProps {
/**
@ -42,7 +40,7 @@ export interface AddToNewCaseProps {
*
* @returns add to existing case for a context menu
*/
export const AddToNewCase: VFC<AddToNewCaseProps> = ({
export const AddToNewCase: FC<AddToNewCaseProps> = ({
indicator,
onClick,
'data-test-subj': dataTestSubj,
@ -73,7 +71,7 @@ export const AddToNewCase: VFC<AddToNewCaseProps> = ({
>
<FormattedMessage
defaultMessage="Add to new case"
id="xpack.threatIntelligence.addToNewCase"
id="xpack.securitySolution.threatIntelligence.addToNewCase"
/>
</EuiContextMenuItem>
);

View file

@ -6,8 +6,8 @@
*/
import React from 'react';
import { ExternalReferenceAttachmentViewProps } from '@kbn/cases-plugin/public/client/attachment_framework/types';
import { AttachmentMetadata } from '../utils/attachments';
import type { ExternalReferenceAttachmentViewProps } from '@kbn/cases-plugin/public/client/attachment_framework/types';
import type { AttachmentMetadata } from '../utils/attachments';
import { CommentChildren } from './comment_children';
/**
@ -17,6 +17,7 @@ import { CommentChildren } from './comment_children';
* It renders some text and a flyout.
*/
export const initComponent = () => {
// eslint-disable-next-line react/display-name
return (props: ExternalReferenceAttachmentViewProps) => {
const indicatorId: string = props.externalReferenceId;
const metadata = props.externalReferenceMetadata as unknown as AttachmentMetadata;

View file

@ -9,10 +9,10 @@ import React from 'react';
import type { StoryFn } from '@storybook/react';
import { of } from 'rxjs';
import type { IKibanaSearchResponse } from '@kbn/search-types';
import { generateMockFileIndicator } from '../../../../common/types/indicator';
import { generateMockFileIndicator } from '../../../../../common/threat_intelligence/types/indicator';
import { CommentChildren } from './comment_children';
import { StoryProvidersComponent } from '../../../mocks/story_providers';
import { AttachmentMetadata } from '../utils/attachments';
import type { AttachmentMetadata } from '../utils/attachments';
export default {
title: 'CommentChildren',
@ -44,6 +44,7 @@ export const Default: StoryFn = () => {
};
return (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<StoryProvidersComponent kibana={kibana as any}>
<CommentChildren id={id} metadata={metadata} />
</StoryProvidersComponent>
@ -72,6 +73,7 @@ export const Loading: StoryFn = () => {
};
return (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<StoryProvidersComponent kibana={kibana as any}>
<CommentChildren id={id} metadata={metadata} />
</StoryProvidersComponent>

View file

@ -13,10 +13,11 @@ import {
INDICATOR_NAME_TEST_ID,
INDICATOR_TYPE_TEST_ID,
} from './comment_children';
import { AttachmentMetadata } from '../utils/attachments';
import type { AttachmentMetadata } from '../utils/attachments';
import { TestProvidersComponent } from '../../../mocks/test_providers';
import { useIndicatorById } from '../hooks/use_indicator_by_id';
import { generateMockFileIndicator, Indicator } from '../../../../common/types/indicator';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import { generateMockFileIndicator } from '../../../../../common/threat_intelligence/types/indicator';
import { LOADING_LOGO_TEST_ID } from './test_ids';
jest.mock('../hooks/use_indicator_by_id');

View file

@ -5,15 +5,16 @@
* 2.0.
*/
import React, { useMemo, useState, VFC } from 'react';
import type { FC } from 'react';
import React, { useMemo, useState } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiLoadingLogo, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { LOADING_LOGO_TEST_ID } from './test_ids';
import { Indicator } from '../../../../common/types/indicator';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import { IndicatorsFlyout } from '../../indicators/components/flyout/flyout';
import { useStyles } from './styles';
import { useIndicatorById } from '../hooks/use_indicator_by_id';
import { AttachmentMetadata } from '../utils/attachments';
import type { AttachmentMetadata } from '../utils/attachments';
export const INDICATOR_NAME_TEST_ID = 'tiCasesIndicatorName';
export const INDICATOR_FEED_NAME_TEST_ID = 'tiCasesIndicatorFeedName';
@ -34,7 +35,7 @@ export interface CommentChildrenProps {
* Renders some basic values (indicator name, type and feed name) in the comment section
* of the case attachment. Also renders a flyout for more details about the indicator.
*/
export const CommentChildren: VFC<CommentChildrenProps> = ({ id, metadata }) => {
export const CommentChildren: FC<CommentChildrenProps> = ({ id, metadata }) => {
const styles = useStyles();
const [expanded, setExpanded] = useState<boolean>(false);
@ -67,7 +68,7 @@ export const CommentChildren: VFC<CommentChildrenProps> = ({ id, metadata }) =>
<EuiText size="s">
<strong>
<FormattedMessage
id="xpack.threatIntelligence.cases.indicatorName"
id="xpack.securitySolution.threatIntelligence.cases.indicatorName"
defaultMessage="Indicator name:"
/>
</strong>
@ -87,7 +88,7 @@ export const CommentChildren: VFC<CommentChildrenProps> = ({ id, metadata }) =>
<EuiText size="s">
<strong>
<FormattedMessage
id="xpack.threatIntelligence.cases.indicatorFeedName"
id="xpack.securitySolution.threatIntelligence.cases.indicatorFeedName"
defaultMessage="Feed name:"
/>
</strong>
@ -105,7 +106,7 @@ export const CommentChildren: VFC<CommentChildrenProps> = ({ id, metadata }) =>
<EuiText size="s">
<strong>
<FormattedMessage
id="xpack.threatIntelligence.cases.indicatorType"
id="xpack.securitySolution.threatIntelligence.cases.indicatorType"
defaultMessage="Indicator type:"
/>
</strong>

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { CSSObject } from '@emotion/react';
import type { CSSObject } from '@emotion/react';
export const useStyles = () => {
const container: CSSObject = {

View file

@ -5,24 +5,27 @@
* 2.0.
*/
import React, { FC, ReactNode } from 'react';
import { renderHook, RenderHookResult } from '@testing-library/react';
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { FC, ReactNode } from 'react';
import React from 'react';
import type { RenderHookResult } from '@testing-library/react';
import { renderHook } from '@testing-library/react';
import { casesPluginMock } from '@kbn/cases-plugin/public/mocks';
import { KibanaContext } from '../../../hooks/use_kibana';
import { useCaseDisabled } from './use_case_permission';
import { TestProvidersComponent } from '../../../mocks/test_providers';
import { EMPTY_VALUE } from '../../../constants/common';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
const casesServiceMock = casesPluginMock.createStartContract();
const getProviderComponent =
(mockedServices: unknown) =>
// eslint-disable-next-line react/display-name
({ children }: { children: ReactNode }) =>
(
<TestProvidersComponent>
<KibanaContext.Provider value={{ services: mockedServices } as any}>
{children}
</KibanaContext.Provider>
<KibanaContextProvider services={mockedServices as any}>{children}</KibanaContextProvider>
</TestProvidersComponent>
);

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { CasesPermissions } from '@kbn/cases-plugin/common';
import type { CasesPermissions } from '@kbn/cases-plugin/common';
import { EMPTY_VALUE } from '../../../constants/common';
import { useKibana } from '../../../hooks/use_kibana';
import { useKibana } from '../../../../common/lib/kibana';
/**
* Decides if we enable or disable the add to existing and add to new case features.

View file

@ -9,7 +9,7 @@ import { waitFor, renderHook } from '@testing-library/react';
import { useIndicatorById } from './use_indicator_by_id';
import { TestProvidersComponent } from '../../../mocks/test_providers';
import { createFetchIndicatorById } from '../services/fetch_indicator_by_id';
import { Indicator } from '../../../../common/types/indicator';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
jest.mock('../services/fetch_indicator_by_id');

View file

@ -7,9 +7,10 @@
import { useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Indicator } from '../../../../common/types/indicator';
import { useKibana } from '../../../hooks/use_kibana';
import { createFetchIndicatorById, FetchParams } from '../services/fetch_indicator_by_id';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import { useKibana } from '../../../../common/lib/kibana';
import type { FetchParams } from '../services/fetch_indicator_by_id';
import { createFetchIndicatorById } from '../services/fetch_indicator_by_id';
const QUERY_ID = 'indicatorById';

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import { mockedSearchService } from '../../../mocks/test_providers';
import { BehaviorSubject, throwError } from 'rxjs';
import { createFetchIndicatorById } from './fetch_indicator_by_id';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import { mockedSearchService } from '../../../mocks/test_providers';
const indicatorsResponse = {
rawResponse: { hits: { hits: [{ _id: 'testId' }], total: 0 } },
@ -20,7 +20,9 @@ describe('FetchIndicatorByIdService', () => {
describe('fetchIndicatorById()', () => {
describe('when query is successful', () => {
beforeEach(() => {
mockedSearchService.search.mockReturnValue(new BehaviorSubject(indicatorsResponse));
jest
.mocked(mockedSearchService.search)
.mockReturnValue(new BehaviorSubject(indicatorsResponse));
});
it('should pass the query down to searchService', async () => {
@ -55,9 +57,9 @@ describe('FetchIndicatorByIdService', () => {
describe('when query fails', () => {
beforeEach(() => {
mockedSearchService.search.mockReturnValue(
throwError(() => new Error('some random exception'))
);
jest
.mocked(mockedSearchService.search)
.mockReturnValue(throwError(() => new Error('some random exception')));
});
it('should throw an error', async () => {

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import { ISearchStart } from '@kbn/data-plugin/public';
import { RequestAdapter } from '@kbn/inspector-plugin/common';
import type { ISearchStart } from '@kbn/data-plugin/public';
import type { RequestAdapter } from '@kbn/inspector-plugin/common';
import { search } from '../../../utils/search';
import { Indicator } from '../../../../common/types/indicator';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
interface FetchIndicatorsDependencies {
searchService: ISearchStart;
@ -21,6 +21,7 @@ interface FetchIndicatorsDependencies {
export interface RawIndicatorsResponse {
hits: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
hits: any[];
total: number;
};

View file

@ -5,13 +5,11 @@
* 2.0.
*/
import { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import { generateMockFileIndicator, Indicator } from '../../../../common/types/indicator';
import {
AttachmentMetadata,
generateAttachmentsMetadata,
generateAttachmentsWithoutOwner,
} from './attachments';
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import { generateMockFileIndicator } from '../../../../../common/threat_intelligence/types/indicator';
import type { AttachmentMetadata } from './attachments';
import { generateAttachmentsMetadata, generateAttachmentsWithoutOwner } from './attachments';
describe('generateAttachmentsWithoutOwner', () => {
it('should return empty array if external reference id is empty', () => {

View file

@ -5,16 +5,17 @@
* 2.0.
*/
import { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import type { CaseAttachmentsWithoutOwner } from '@kbn/cases-plugin/public';
import { AttachmentType, ExternalReferenceStorageType } from '@kbn/cases-plugin/common';
import { JsonValue } from '@kbn/utility-types';
import { ExternalReferenceAttachmentType } from '@kbn/cases-plugin/public/client/attachment_framework/types';
import type { JsonValue } from '@kbn/utility-types';
import type { ExternalReferenceAttachmentType } from '@kbn/cases-plugin/public/client/attachment_framework/types';
import React from 'react';
import { EuiAvatar } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { CASE_ATTACHMENT_TYPE_ID } from '../../../../common/constants';
import { CASE_ATTACHMENT_TYPE_ID } from '../../../../../common/threat_intelligence/constants';
import { EMPTY_VALUE } from '../../../constants/common';
import { Indicator, RawIndicatorFieldId } from '../../../../common/types/indicator';
import type { Indicator } from '../../../../../common/threat_intelligence/types/indicator';
import { RawIndicatorFieldId } from '../../../../../common/threat_intelligence/types/indicator';
import { getIndicatorFieldAndValue } from '../../indicators/utils/field_value';
/**
@ -45,7 +46,7 @@ export const generateAttachmentType = (): ExternalReferenceAttachmentType => ({
getAttachmentViewObject: () => ({
event: (
<FormattedMessage
id="xpack.threatIntelligence.cases.eventDescription"
id="xpack.securitySolution.threatIntelligence.cases.eventDescription"
defaultMessage="added an indicator of compromise"
/>
),

View file

@ -31,6 +31,7 @@ export function BasicEmptyPage() {
};
return (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<StoryProvidersComponent kibana={kibana as any}>
<EmptyPage />
</StoryProvidersComponent>

View file

@ -14,6 +14,7 @@ import { useIntegrationsPageLink } from '../../hooks/use_integrations_page_link'
jest.mock('../../hooks/use_integrations_page_link');
jest.mock('../../hooks/use_documentation_link');
jest.mock('../../containers/security_solution_plugin_template_wrapper');
const INTEGRATION_HREF = 'INTEGRATION_HREF';
const DOCUMENTATION_HREF = 'DOCUMENTATION_HREF';

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import React, { VFC } from 'react';
import type { FC } from 'react';
import React from 'react';
import { EuiButton, EuiEmptyPrompt, EuiImage, EuiLink } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
@ -19,7 +20,7 @@ export const DOCS_LINK_TEST_ID = 'tiEmptyPageDocsLink';
export const EMPTY_PROMPT_TEST_ID = 'tiEmptyPage';
export const INTEGRATION_LINK_ID = 'tiEmptyPageIntegrationsPageLink';
export const EmptyPage: VFC = () => {
export const EmptyPage: FC = () => {
const integrationsPageLink = useIntegrationsPageLink();
const documentationLink = useTIDocumentationLink();
@ -32,7 +33,7 @@ export const EmptyPage: VFC = () => {
title={
<h3>
<FormattedMessage
id="xpack.threatIntelligence.common.emptyPage.title"
id="xpack.securitySolution.threatIntelligence.common.emptyPage.title"
defaultMessage="Get started with Elastic Threat Intelligence"
/>
</h3>
@ -44,21 +45,21 @@ export const EmptyPage: VFC = () => {
<>
<p>
<FormattedMessage
id="xpack.threatIntelligence.common.emptyPage.body1"
id="xpack.securitySolution.threatIntelligence.common.emptyPage.body1"
defaultMessage="Elastic Threat Intelligence makes it easy to analyze and investigate potential security
threats by aggregating data from multiple sources in one place."
/>
</p>
<p>
<FormattedMessage
id="xpack.threatIntelligence.common.emptyPage.body2"
id="xpack.securitySolution.threatIntelligence.common.emptyPage.body2"
defaultMessage="Youll be able to view data from all activated threat intelligence feeds and take action
from this page."
/>
</p>
<p>
<FormattedMessage
id="xpack.threatIntelligence.common.emptyPage.body3"
id="xpack.securitySolution.threatIntelligence.common.emptyPage.body3"
defaultMessage="To get started with Elastic Threat Intelligence, enable one or more Threat Intelligence
Integrations from the Integrations page or ingest data using filebeat. For more
information, view the {docsLink}."
@ -70,7 +71,7 @@ export const EmptyPage: VFC = () => {
data-test-subj={DOCS_LINK_TEST_ID}
>
<FormattedMessage
id="xpack.threatIntelligence.common.emptyPage.docsLinkText"
id="xpack.securitySolution.threatIntelligence.common.emptyPage.docsLinkText"
defaultMessage="Security app documentation"
/>
</EuiLink>
@ -89,7 +90,7 @@ export const EmptyPage: VFC = () => {
fill
>
<FormattedMessage
id="xpack.threatIntelligence.common.emptyPage.buttonText"
id="xpack.securitySolution.threatIntelligence.common.emptyPage.buttonText"
defaultMessage="Add Integrations"
/>
</EuiButton>

View file

@ -7,6 +7,9 @@
import { i18n } from '@kbn/i18n';
export const IMAGE = i18n.translate('xpack.threatIntelligence.common.emptyPage.imgAlt', {
defaultMessage: 'Enable Threat Intelligence Integrations',
});
export const IMAGE = i18n.translate(
'xpack.securitySolution.threatIntelligence.common.emptyPage.imgAlt',
{
defaultMessage: 'Enable Threat Intelligence Integrations',
}
);

Some files were not shown because too many files have changed in this diff Show more