Skip to content

Commit

Permalink
[Security Solution] [Attack discovery] Attack Discovery RBAC / Displa…
Browse files Browse the repository at this point in the history
…y an upgrade CTA for the serverless essentials product tier (elastic#188788)

## [Security Solution] [Attack discovery] Attack Discovery RBAC / Display an upgrade CTA for the serverless essentials product tier

### Summary

This PR adds Role Based Access Control (RBAC) to Attack discovery.

Security users may enable or disable the new `Attack Discovery` RBAC feature shown in the figure below:

![rbac](https://github.com/user-attachments/assets/2ca3de6e-3e87-401f-8a06-0eb06d36d081)

_Above: The new `Attack discovery` RBAC feature_

It is possible to for example, configure a custom role that enables Attack discovery, but disables the assistant, as illustrated by the table below:

| Role                                      | License    | Navigation visible | Show upsell | Upsell has actions | View in assistant enabled |
|-------------------------------------------|------------|--------------------|-------------|--------------------|---------------------------|
| `has_attack_discovery_all_assistant_none`     | Basic      | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_all_assistant_none` | Trial      | ✅                  | ❌           | ❌                  | ❌                         |
| `has_attack_discovery_all_assistant_none` | Platinum   | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_all_assistant_none` | Enterprise | ✅                  | ❌           | ❌                  | ❌                         |

_Above: An example role that enables Attack discovery, but disables the assistant_

See the `Desk Testing` section of this PR for details.

This PR also fixes an issue where Attack discovery does not display an upgrade call to action (CTA) for the serverless _essentials_ product tier, per the before and after screenshots below:

#### Before

![serverless_essentials_before](https://github.com/user-attachments/assets/90e8f433-896d-40a3-b095-8f0cca0f7073)

_Above: Before the fix, an upgrade CTA is NOT displayed for the serverless essentials product tier_

#### After

![serverless_essentials_after](https://github.com/user-attachments/assets/4cdd146e-afac-4f3e-925b-4786e1908312)

_Above: After the fix, an upgrade CTA is displayed for the serverless essentials product tier_

The fix above is implemented by adopting the upselling framework.

### New Feature ID

This PR adds a new Feature ID for attack discovery:

```typescript
export const ATTACK_DISCOVERY_FEATURE_ID = 'securitySolutionAttackDiscovery' as const;
```

in `x-pack/packages/security-solution/features/src/constants.ts`

### Upselling framework usage

This PR updates the Attack discovery page to use the upselling framework via the following summarized steps:

1. Removed the branching logic from `x-pack/plugins/security_solution/public/attack_discovery/pages/upgrade/index.tsx`, and moved the component to an upselling `section` component in `x-pack/packages/security-solution/upselling/sections/attack_discovery/index.tsx`, where the component was renamed to `AttackDiscoveryUpsellingSection`.

This `section` component handles (just) the styling of the upselling message and actions (by itself, without the page wrapper), and receives the following props:

```typescript
interface Props {
  actions?: React.ReactNode;
  availabilityMessage: string;
  upgradeMessage: string;
}
```

The self managed and serverless-specific actions and `i18n` messages are passed down via the components described in the later steps below.

2. Removed all previous references to the `Upgrade` component (and references to `useProductTypes`) from the Attack discovery page in `x-pack/plugins/security_solution/public/attack_discovery/pages/index.tsx`, because the framework manages the upgrade case instead of the page itself.

3. Created an upselling `page` component `AttackDiscoveryUpsellingPage` in `x-pack/packages/security-solution/upselling/pages/attack_discovery/index.tsx`.

This component handles (just) the styling of the _page_ that wraps the Attack discovery `section`. It passes the same props to the previously described `AttackDiscoveryUpsellingSection` component.

4. Created a self-managed-specific `AttackDiscoveryUpsellingPageESS` component in `x-pack/plugins/security_solution_ess/public/upselling/pages/attack_discovery/index.tsx`

This component passes self-managed-specific upgrade action buttons / links and `i18n` strings to the previously described `AttackDiscoveryUpsellingPage`

5. Also for self managed, added a new `AttackDiscoveryUpsellingPageLazy` component to the existing file: `x-pack/plugins/security_solution_ess/public/upselling/lazy_upselling.tsx`

This component lazy loads the previously described `AttackDiscoveryUpsellingPageESS` component.

6. Added registration for the previously described `AttackDiscoveryUpsellingPageLazy` component to the existing `UpsellingPages` section in `x-pack/plugins/security_solution_ess/public/upselling/register_upsellings.tsx` with a `minimumLicenseRequired` of `enterprise`:

```
minimumLicenseRequired: 'enterprise',
```

7. Created a serverless-specific `AttackDiscoveryUpsellingPageServerless` component in `x-pack/plugins/security_solution_serverless/public/upselling/pages/attack_discovery/index.tsx`

This component passes serverless-specific `i18n` messages to the platform agnostic `AttackDiscoveryUpsellingPage` component.

8. Also for serverless, added a new `AttackDiscoveryUpsellingPageLazy` component to the existing file: `x-pack/plugins/security_solution_serverless/public/upselling/lazy_upselling.tsx`

9. Added registration for the previously described `AttackDiscoveryUpsellingPageLazy` component to the existing `upsellingPages` section in `x-pack/plugins/security_solution_serverless/public/upselling/upsellings.tsx` with the `assistant` PLI:

```
pli: ProductFeatureKey.assistant,
```

10. Added the `${ASSISTANT_FEATURE_ID}.ai-assistant` capability as an OR condition (via nested array, per the [framework](https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/public/common/lib/capabilities/has_capabilities.ts#L11-L22)) to the Attack discovery link in `x-pack/plugins/security_solution/public/attack_discovery/links.ts`. This addition enables the security route wrapper to check for upselling pages in serverless:

```
capabilities: [[`${SERVER_APP_ID}.show`, `${ASSISTANT_FEATURE_ID}.ai-assistant`]],
```

11. Added `licenseType: 'enterprise'` to the Attack discovery link in `x-pack/plugins/security_solution/public/attack_discovery/links.ts` to require an `enterprise` license for self managed

### Upgrade CTA gallery

The screenshots in this section document the CTA (or Welcome message when the feature is licensed) displayed for various license levels after the fix:

#### Users with the `None` privilege

If users with the `None` privilege manually enter an Attack discovery URL, e.g. `http://localhost:5601/app/security/attack_discovery`, the framework will display the following error prompt:

![privelages_required](https://github.com/user-attachments/assets/d282609e-5400-4ba9-8130-de5e10f8973d)

#### Self managed BASIC

![self_managed_basic_after](https://github.com/user-attachments/assets/048b2a3b-9e2d-4b95-a697-c739ea2dc5bb)

#### Self managed PLATINUM

![self_managed_platinum_after](https://github.com/user-attachments/assets/d7c49551-a8cf-4afb-b3bf-c3243e892219)

#### Self managed TRIAL

![self_managed_trial_after](https://github.com/user-attachments/assets/d5cc03a9-97aa-4c78-a5f5-92e5af3a85ac)

#### Self managed ENTERPRISE

![self_managed_enterprise_after](https://github.com/user-attachments/assets/a849b534-7e07-4481-9641-c48dee126466)

#### Serverless ESSENTIALS

![serverless_essentials_after](https://github.com/user-attachments/assets/4cdd146e-afac-4f3e-925b-4786e1908312)

#### Serverless COMPLETE

![serverless_complete_after](https://github.com/user-attachments/assets/8cab60c3-dea6-4d7a-b86a-b2cd11c9b4dd)

## Desk Testing

### Severless: Desk testing (just) the upgrade CTA

Reproduction steps:

1) Comment-out any preconfigured connectors in `config/kibana.dev.yml`

2) Edit the configuration of `config/serverless.security.yml` to enable the `essentials` product tier:

```yaml
xpack.securitySolutionServerless.productTypes:
  [
    { product_line: 'security', product_tier: 'essentials' }
  ]
```

3) Start Elasticsearch

```sh
yarn es serverless --projectType security
```

4) Start a development instance of Kibana

```
yarn start --serverless=security --no-base-path
```

5) Navigate to Security > Attack discovery

**Expected result**

- An upgrade CTA is displayed, as illustrated by the _after_ screenshot below:

![serverless_essentials_after](https://github.com/user-attachments/assets/4cdd146e-afac-4f3e-925b-4786e1908312)

- The video tour is NOT displayed for serverless, as noted in the [original PR](elastic#182605 (comment))

**Actual result**

- An upgrade CTA is NOT displayed, as illustrated by the _before_ screenshot below:

![serverless_essentials_before](https://github.com/user-attachments/assets/90e8f433-896d-40a3-b095-8f0cca0f7073)

### Desk testing Self Managed

To desk test self manged, we will:

1) Create (three) roles for testing
2) Create (three) users assigned to the roles
3) Test each role at `Basic`, `Trial`, `Platinum`, and `Enterprise` levels to verify:

- `Attack discovery` link visibility in the Security solution navigation
- Visibility of the upsell empty prompt for license levels where Attack discovery is unavailable
- The upsell empty prompt includes the `Subscription plans` and `Manage license` actions
- When Attack discoveries are generated, the `View in Ai Assistant` button and popover menu action are enabled / disabled, based on availability of the `AI Assistant` feature

#### Creating (three) roles for testing

In this section, we will start a new (development) self managed deployment, and create the following three roles via Kibana Dev Tools:

- `has_attack_discovery_all_assistant_all`
- `has_attack_discovery_all_assistant_none`
- `has_attack_discovery_none_assistant_all`

To start the deployment and create the roles:

1) Add a pre-configured GenAI connector to `config/kibana.dev.yml`

2) Start a new (development) instance of Elasticsearch:

```sh
yarn es snapshot -E path.data=/Users/$USERNAME/data-2024-07-31a
```

3) Start a local (development) instance of Kibana:

```
yarn start --no-base-path
````

4) Login to Kibana as the `elastic` user

5) Generate some alerts

6) Navigate to Dev Tools

7) Execute the following three API calls to create the roles:

<details><summary>PUT /_security/role/has_attack_discovery_all_assistant_all</summary>
<p>

``` ts
PUT /_security/role/has_attack_discovery_all_assistant_all
{
  "cluster": [
    "all"
  ],
  "indices": [
    {
      "names": [
        "*"
      ],
      "privileges": [
        "all"
      ],
      "field_security": {
        "grant": [
          "*"
        ],
        "except": []
      },
      "allow_restricted_indices": false
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": [
        "feature_securitySolutionAssistant.minimal_all",
        "feature_securitySolutionAttackDiscovery.minimal_all",
        "feature_siem.all",
        "feature_securitySolutionCases.all",
        "feature_actions.all"
      ],
      "resources": [
        "*"
      ]
    }
  ],
  "run_as": [],
  "metadata": {},
  "transient_metadata": {
    "enabled": true
  }
}
```

</p>
</details>

<details><summary>PUT /_security/role/has_attack_discovery_all_assistant_none</summary>
<p>

``` ts
PUT /_security/role/has_attack_discovery_all_assistant_none
{
  "cluster": [
    "all"
  ],
  "indices": [
    {
      "names": [
        "*"
      ],
      "privileges": [
        "all"
      ],
      "field_security": {
        "grant": [
          "*"
        ],
        "except": []
      },
      "allow_restricted_indices": false
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": [
        "feature_securitySolutionAttackDiscovery.minimal_all",
        "feature_siem.all",
        "feature_securitySolutionCases.all",
        "feature_actions.all"
      ],
      "resources": [
        "*"
      ]
    }
  ],
  "run_as": [],
  "metadata": {},
  "transient_metadata": {
    "enabled": true
  }
}
```

</p>
</details>

<details><summary>PUT /_security/role/has_attack_discovery_none_assistant_all</summary>
<p>

``` ts
PUT /_security/role/has_attack_discovery_none_assistant_all
{
  "cluster": [
    "all"
  ],
  "indices": [
    {
      "names": [
        "*"
      ],
      "privileges": [
        "all"
      ],
      "field_security": {
        "grant": [
          "*"
        ],
        "except": []
      },
      "allow_restricted_indices": false
    }
  ],
  "applications": [
    {
      "application": "kibana-.kibana",
      "privileges": [
        "feature_securitySolutionAssistant.minimal_all",
        "feature_siem.all",
        "feature_securitySolutionCases.all",
        "feature_actions.all"
      ],
      "resources": [
        "*"
      ]
    }
  ],
  "run_as": [],
  "metadata": {},
  "transient_metadata": {
    "enabled": true
  }
}
```

</p>
</details>

#### Creating (three) users assigned to the roles

In this section, we will create the following three users via Kibana Dev Tools using the API calls below (expand for details):

- `attack_discovery_all_assistant_all`
- `attack_discovery_all_assistant_none`
- `attack_discovery_none_assistant_all`

1) Navigate to Dev Tools

2) Execute the following three API calls to create the users:

<details><summary>POST /_security/user/attack_discovery_all_assistant_all</summary>
<p>

``` ts
POST /_security/user/attack_discovery_all_assistant_all
{
    "username": "attack_discovery_all_assistant_all",
    "password": "changeme",
    "roles": [
      "has_attack_discovery_all_assistant_all"
    ],
    "full_name": "Attack Discovery All Assistant All",
    "email": "user@example.com",
    "metadata": {},
    "enabled": true
}
```

</p>
</details>

<details><summary>POST /_security/user/attack_discovery_all_assistant_none</summary>
<p>

``` ts
POST /_security/user/attack_discovery_all_assistant_none
{
    "username": "attack_discovery_all_assistant_none",
    "password": "changeme",
    "roles": [
      "has_attack_discovery_all_assistant_none"
    ],
    "full_name": "Attack Discovery All Assistant None",
    "email": "user@example.com",
    "metadata": {},
    "enabled": true
}
```

</p>
</details>

<details><summary>POST /_security/user/attack_discovery_none_assistant_all</summary>
<p>

``` ts
POST /_security/user/attack_discovery_none_assistant_all
{
    "username": "attack_discovery_none_assistant_all",
    "password": "changeme",
    "roles": [
      "has_attack_discovery_none_assistant_all"
    ],
    "full_name": "Attack Discovery None Assistant All",
    "email": "user@example.com",
    "metadata": {},
    "enabled": true
}
```

</p>
</details>

#### Testing each role at `Basic`, `Trial`, `Platinum`, and `Enterprise` levels

In this section, we will test each of the self managed `Basic`, `Trial`, `Platinum`, and `Enterprise` license levels with the three roles we created for testing.

##### Testing the `has_attack_discovery_all_assistant_all` role

1) Login as the `attack_discovery_all_assistant_all` user

2) Navigate to the Security solution

3) For each of the `Basic`, `Trial`, `Platinum`, and `Enterprise` levels, verify your observations match the expected behavior in the table below:

| Role                                     | License    | Navigation visible | Show upsell | Upsell has actions | View in assistant enabled |
|------------------------------------------|------------|--------------------|-------------|--------------------|---------------------------|
| `has_attack_discovery_all_assistant_all` | Basic      | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_all_assistant_all` | Trial      | ✅                  | ❌           | ❌                  | ✅                         |
| `has_attack_discovery_all_assistant_all` | Platinum   | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_all_assistant_all` | Enterprise | ✅                  | ❌           | ❌                  | ✅                         |

##### Testing the `has_attack_discovery_all_assistant_none` role

1) Login as the `attack_discovery_all_assistant_none` user

2) Navigate to the Security solution

3) For each of the `Basic`, `Trial`, `Platinum`, and `Enterprise` levels, verify your observations match the expected behavior in the table below:

| Role                                      | License    | Navigation visible | Show upsell | Upsell has actions | View in assistant enabled |
|-------------------------------------------|------------|--------------------|-------------|--------------------|---------------------------|
| `has_attack_discovery_all_assistant_none`     | Basic      | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_all_assistant_none` | Trial      | ✅                  | ❌           | ❌                  | ❌                         |
| `has_attack_discovery_all_assistant_none` | Platinum   | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_all_assistant_none` | Enterprise | ✅                  | ❌           | ❌                  | ❌                         |

##### Testing the `has_attack_discovery_none_assistant_all` role

1) Login as the `attack_discovery_none_assistant_all` user

2) Navigate to the Security solution

3) For each of the `Basic`, `Trial`, `Platinum`, and `Enterprise` levels, verify your observations match the expected behavior in the table below:

| Role                                      | License    | Navigation visible | Show upsell | Upsell has actions | View in assistant enabled |
|-------------------------------------------|------------|--------------------|-------------|--------------------|---------------------------|
| `has_attack_discovery_none_assistant_all` | Basic      | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_none_assistant_all` | Trial      | ❌                  | ❌           | ❌                  | ❌                         |
| `has_attack_discovery_none_assistant_all` | Platinum   | ✅                  | ✅           | ✅                  | ❌                         |
| `has_attack_discovery_none_assistant_all` | Enterprise | ❌                  | ❌           | ❌                  | ❌                         |

---------------------------------------------

### Serverless Testing

To desk test serverless, we will test the `essentials` and `complete` product tiers to verify:

- `Attack discovery` link visibility in the Security project navigation
- Visibility of the upsell empty prompt for license levels where Attack discovery is unavailable
- The upsell empty prompt does NOT include the `Subscription plans` and `Manage license` actions
- When Attack discoveries are generated, the `View in Ai Assistant` button and popover menu action are enabled

#### Essentials tier testing

1) Add a pre-configured GenAI connector to `config/kibana.dev.yml`

2) Edit the configuration of `config/serverless.security.yml` to enable the `essentials` product tier:

```yaml
xpack.securitySolutionServerless.productTypes:
  [
    { product_line: 'security', product_tier: 'essentials' },
    { product_line: 'endpoint', product_tier: 'essentials' },
  ]
```

2) Start a new (development) instance of Elasticsearch:

```sh
yarn es serverless --clean --projectType security
```

3) Start a local (development) instance of Kibana:

```
yarn start --serverless=security --no-base-path
````

4) select the `admin` role

5) Generate some alerts

6) Verify your observations match the expected behavior in the table below:

| Role                          | Tier       | Navigation visible | Show upsell | Upsell has actions | View in assistant enabled |
|-------------------------------|------------|--------------------|-------------|--------------------|---------------------------|
| `viewer`                      | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `editor`                      | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `t1_analyst`                  | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `t2_analyst`                  | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `t3_analyst`                  | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `threat_intelligence_analyst` | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `rule_author`                 | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `soc_manager`                 | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `detections_admin`            | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `platform_engineer`           | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `endpoint_operations_analyst` | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `endpoint_policy_manager`     | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `admin`                       | essentials | ✅                  | ✅           | ❌                  | ❌                         |
| `system_indices_superuser`    | essentials | ✅                  | ✅           | ❌                  | ❌                         |

### Complete tier testing

1) Stop the running Kibana server (from the previous Essentials tier testing)

2) Edit the configuration of `config/serverless.security.yml` to enable the `complete` product tier:

```yaml
xpack.securitySolutionServerless.productTypes:
  [
    { product_line: 'security', product_tier: 'complete' },
    { product_line: 'endpoint', product_tier: 'complete' },
  ]
```

3) Restart a local (development) instance of Kibana:

```
yarn start --serverless=security --no-base-path
````

4) Verify your observations match the expected behavior in the table below:

| Role                          | Tier     | Navigation visible | Show upsell | Upsell has actions | View in assistant enabled |
|-------------------------------|----------|--------------------|-------------|--------------------|---------------------------|
| `viewer`                      | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `editor`                      | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `t1_analyst`                  | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `t2_analyst`                  | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `t3_analyst`                  | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `threat_intelligence_analyst` | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `rule_author`                 | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `soc_manager`                 | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `detections_admin`            | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `platform_engineer`           | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `endpoint_operations_analyst` | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `endpoint_policy_manager`     | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `admin`                       | complete | ✅                  | ❌           | ❌                  | ✅                         |
| `system_indices_superuser`    | complete | ✅                  | ❌           | ❌                  | ✅                         |
  • Loading branch information
andrew-goldstein authored and bryce-b committed Aug 13, 2024
1 parent f3a6a8a commit 09182ad
Show file tree
Hide file tree
Showing 73 changed files with 1,191 additions and 288 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ viewer:
- feature_siem.endpoint_list_read
- feature_securitySolutionCases.read
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.read
- feature_osquery.read
Expand Down Expand Up @@ -124,6 +125,7 @@ editor:
- feature_siem.file_operations_all
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.all
- feature_osquery.all
Expand Down Expand Up @@ -171,6 +173,7 @@ t1_analyst:
- feature_siem.endpoint_list_read
- feature_securitySolutionCases.read
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.read
- feature_osquery.read
Expand Down Expand Up @@ -224,6 +227,7 @@ t2_analyst:
- feature_siem.endpoint_list_read
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.read
- feature_osquery.read
Expand Down Expand Up @@ -292,6 +296,7 @@ t3_analyst:
- feature_siem.scan_operations_all
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.all
- feature_osquery.all
Expand Down Expand Up @@ -352,6 +357,7 @@ threat_intelligence_analyst:
- feature_siem.blocklist_all
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.read
- feature_osquery.all
Expand Down Expand Up @@ -418,6 +424,7 @@ rule_author:
- feature_siem.actions_log_management_read
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.read
- feature_builtInAlerts.all
- feature_osquery.all
Expand Down Expand Up @@ -488,6 +495,7 @@ soc_manager:
- feature_siem.scan_operations_all
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.all
- feature_builtInAlerts.all
- feature_osquery.all
Expand Down Expand Up @@ -546,6 +554,7 @@ detections_admin:
- feature_siem.crud_alerts
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.all
- feature_builtInAlerts.all
- feature_dev_tools.all
Expand Down Expand Up @@ -603,6 +612,7 @@ platform_engineer:
- feature_siem.actions_log_management_read
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.all
- feature_builtInAlerts.all
- feature_fleet.all
Expand Down Expand Up @@ -674,6 +684,7 @@ endpoint_operations_analyst:
- feature_siem.scan_operations_all
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.all
- feature_builtInAlerts.all
- feature_osquery.all
Expand Down Expand Up @@ -747,6 +758,7 @@ endpoint_policy_manager:
- feature_siem.blocklist_all # Elastic Defend Policy Management
- feature_securitySolutionCases.all
- feature_securitySolutionAssistant.all
- feature_securitySolutionAttackDiscovery.all
- feature_actions.all
- feature_builtInAlerts.all
- feature_osquery.all
Expand Down
7 changes: 7 additions & 0 deletions packages/kbn-es/src/serverless_resources/security_roles.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"ml": ["read"],
"siem": ["read", "read_alerts"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"securitySolutionCases": ["read"],
"actions": ["read"],
"builtInAlerts": ["read"]
Expand Down Expand Up @@ -80,6 +81,7 @@
"ml": ["read"],
"siem": ["read", "read_alerts"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"securitySolutionCases": ["read"],
"actions": ["read"],
"builtInAlerts": ["read"]
Expand Down Expand Up @@ -145,6 +147,7 @@
],
"securitySolutionCases": ["all"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"actions": ["read"],
"builtInAlerts": ["all"],
"osquery": ["all"],
Expand Down Expand Up @@ -201,6 +204,7 @@
"ml": ["read"],
"siem": ["all", "read_alerts", "crud_alerts"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"securitySolutionCases": ["all"],
"actions": ["read"],
"builtInAlerts": ["all"]
Expand Down Expand Up @@ -253,6 +257,7 @@
"ml": ["read"],
"siem": ["all", "read_alerts", "crud_alerts"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"securitySolutionCases": ["all"],
"actions": ["all"],
"builtInAlerts": ["all"]
Expand Down Expand Up @@ -300,6 +305,7 @@
"ml": ["all"],
"siem": ["all", "read_alerts", "crud_alerts"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"securitySolutionCases": ["all"],
"actions": ["read"],
"builtInAlerts": ["all"],
Expand Down Expand Up @@ -354,6 +360,7 @@
"ml": ["all"],
"siem": ["all", "read_alerts", "crud_alerts"],
"securitySolutionAssistant": ["all"],
"securitySolutionAttackDiscovery": ["all"],
"securitySolutionCases": ["all"],
"actions": ["all"],
"builtInAlerts": ["all"]
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pageLoadAssetSize:
searchprofiler: 67080
security: 81771
securitySolution: 98429
securitySolutionEss: 16573
securitySolutionEss: 31781
securitySolutionServerless: 62488
serverless: 16573
serverlessObservability: 68747
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ActionTypeSelectorModal = React.memo(
({ actionTypes, actionTypeRegistry, onClose, onSelect, actionTypeSelectorInline }: Props) => {
const content = useMemo(
() => (
<EuiFlexGroup>
<EuiFlexGroup justifyContent="center" responsive={false} wrap={true}>
{actionTypes?.map((actionType: ActionType) => {
const fullAction = actionTypeRegistry.get(actionType.id);
return (
Expand Down
1 change: 1 addition & 0 deletions x-pack/packages/security-solution/features/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
export { securityDefaultProductFeaturesConfig } from './src/security/product_feature_config';
export { getCasesDefaultProductFeaturesConfig } from './src/cases/product_feature_config';
export { assistantDefaultProductFeaturesConfig } from './src/assistant/product_feature_config';
export { attackDiscoveryDefaultProductFeaturesConfig } from './src/attack_discovery/product_feature_config';

export { createEnabledProductFeaturesConfigMap } from './src/helpers';
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
export { getSecurityFeature } from './src/security';
export { getCasesFeature } from './src/cases';
export { getAssistantFeature } from './src/assistant';
export { getAttackDiscoveryFeature } from './src/attack_discovery';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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 { getAttackDiscoveryBaseKibanaFeature } from './kibana_features';
import type { ProductFeatureParams } from '../types';

export const getAttackDiscoveryFeature = (): ProductFeatureParams => ({
baseKibanaFeature: getAttackDiscoveryBaseKibanaFeature(),
baseKibanaSubFeatureIds: [],
subFeaturesMap: new Map(),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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 { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common';
import { i18n } from '@kbn/i18n';

import { APP_ID, ATTACK_DISCOVERY_FEATURE_ID } from '../constants';
import { type BaseKibanaFeatureConfig } from '../types';

export const getAttackDiscoveryBaseKibanaFeature = (): BaseKibanaFeatureConfig => ({
id: ATTACK_DISCOVERY_FEATURE_ID,
name: i18n.translate(
'securitySolutionPackages.features.featureRegistry.linkSecuritySolutionAttackDiscoveryTitle',
{
defaultMessage: 'Attack discovery',
}
),
order: 1100,
category: DEFAULT_APP_CATEGORIES.security,
app: [ATTACK_DISCOVERY_FEATURE_ID, 'kibana'],
catalogue: [APP_ID],
minimumLicense: 'enterprise',
privileges: {
all: {
api: ['elasticAssistant'],
app: [ATTACK_DISCOVERY_FEATURE_ID, 'kibana'],
catalogue: [APP_ID],
savedObject: {
all: [],
read: [],
},
ui: [],
},
read: {
// No read-only mode currently supported
disabled: true,
savedObject: {
all: [],
read: [],
},
ui: [],
},
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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 { ProductFeatureAttackDiscoveryKey } from '../product_features_keys';
import type { ProductFeatureKibanaConfig } from '../types';

/**
* App features privileges configuration for the Attack discovery feature.
* These are the configs that are shared between both offering types (ess and serverless).
* They can be extended on each offering plugin to register privileges using different way on each offering type.
*
* Privileges can be added in different ways:
* - `privileges`: the privileges that will be added directly into the main Security feature.
* - `subFeatureIds`: the ids of the sub-features that will be added into the Security subFeatures entry.
* - `subFeaturesPrivileges`: the privileges that will be added into the existing Security subFeature with the privilege `id` specified.
*/
export const attackDiscoveryDefaultProductFeaturesConfig: Record<
ProductFeatureAttackDiscoveryKey,
ProductFeatureKibanaConfig
> = {
[ProductFeatureAttackDiscoveryKey.attackDiscovery]: {
privileges: {
all: {
ui: ['attack-discovery'],
},
},
subFeatureIds: [],
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const SERVER_APP_ID = 'siem' as const;

export const CASES_FEATURE_ID = 'securitySolutionCases' as const;
export const ASSISTANT_FEATURE_ID = 'securitySolutionAssistant' as const;
export const ATTACK_DISCOVERY_FEATURE_ID = 'securitySolutionAttackDiscovery' as const;

// Same as the plugin id defined by Cloud Security Posture
export const CLOUD_POSTURE_APP_ID = 'csp' as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,26 @@ export enum ProductFeatureAssistantKey {
assistant = 'assistant',
}

export enum ProductFeatureAttackDiscoveryKey {
/**
* Enables Attack discovery
*/
attackDiscovery = 'attack_discovery',
}

// Merges the two enums.
export const ProductFeatureKey = {
...ProductFeatureSecurityKey,
...ProductFeatureCasesKey,
...ProductFeatureAssistantKey,
...ProductFeatureAttackDiscoveryKey,
};
// We need to merge the value and the type and export both to replicate how enum works.
export type ProductFeatureKeyType =
| ProductFeatureSecurityKey
| ProductFeatureCasesKey
| ProductFeatureAssistantKey;
| ProductFeatureAssistantKey
| ProductFeatureAttackDiscoveryKey;

export const ALL_PRODUCT_FEATURE_KEYS = Object.freeze(Object.values(ProductFeatureKey));

Expand Down
6 changes: 6 additions & 0 deletions x-pack/packages/security-solution/features/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
import type { RecursivePartial } from '@kbn/utility-types';
import type {
ProductFeatureAssistantKey,
ProductFeatureAttackDiscoveryKey,
ProductFeatureCasesKey,
ProductFeatureKeyType,
ProductFeatureSecurityKey,
Expand Down Expand Up @@ -51,6 +52,11 @@ export type ProductFeaturesAssistantConfig = Map<
ProductFeatureKibanaConfig<AssistantSubFeatureId>
>;

export type ProductFeaturesAttackDiscoveryConfig = Map<
ProductFeatureAttackDiscoveryKey,
ProductFeatureKibanaConfig
>;

export type AppSubFeaturesMap<T extends string = string> = Map<T, SubFeatureConfig>;

export interface ProductFeatureParams<T extends string = string> {
Expand Down
Original file line number Diff line number Diff line change
@@ -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, screen } from '@testing-library/react';
import React from 'react';

import { AttackDiscoveryUpsellingPage } from '.';

const availabilityMessage = 'This feature is available...';
const upgradeMessage = 'Please upgrade...';

const mockActions = <div data-test-subj="mockActions" />;

jest.mock('@kbn/security-solution-navigation', () => {
const original = jest.requireActual('@kbn/security-solution-navigation');
return {
...original,
useNavigation: () => ({
navigateTo: jest.fn(),
}),
};
});

describe('AttackDiscoveryUpsellingPage', () => {
beforeEach(() => {
render(
<AttackDiscoveryUpsellingPage
actions={mockActions}
availabilityMessage={availabilityMessage}
upgradeMessage={upgradeMessage}
/>
);
});

it('renders the availability message', () => {
const attackDiscoveryIsAvailable = screen.getByTestId('availabilityMessage');

expect(attackDiscoveryIsAvailable).toHaveTextContent(availabilityMessage);
});

it('renders the upgrade message', () => {
const pleaseUpgrade = screen.getByTestId('upgradeMessage');

expect(pleaseUpgrade).toHaveTextContent(upgradeMessage);
});

it('renders the actions', () => {
const actions = screen.getByTestId('mockActions');

expect(actions).toBeInTheDocument();
});
});
Loading

0 comments on commit 09182ad

Please sign in to comment.