-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Onboarding security analytics dashboards plugin. (opensearch-project#380
) * Added security analytics dashboards. Signed-off-by: AWSHurneyt <[email protected]> * Fixed url is visit() call. Signed-off-by: AWSHurneyt <[email protected]> * Enabled github action on PRs to 2.x branch. Signed-off-by: AWSHurneyt <[email protected]> * Adjusted workflow to run without security. Signed-off-by: AWSHurneyt <[email protected]> * clean up commands Signed-off-by: Kawika Avilla <[email protected]> * Enabled security for onboarding experimental plugin. Signed-off-by: AWSHurneyt <[email protected]> Signed-off-by: AWSHurneyt <[email protected]> Signed-off-by: Kawika Avilla <[email protected]> Co-authored-by: Kawika Avilla <[email protected]> Signed-off-by: [email protected] <[email protected]>
- Loading branch information
1 parent
100e313
commit eb10f43
Showing
9 changed files
with
332 additions
and
0 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
.github/workflows/security-analytics-release-e2e-workflow.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
name: Security Analytics Release tests workflow in Bundled OpenSearch Dashboards | ||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
- dev-* | ||
- 2.x | ||
jobs: | ||
changes: | ||
runs-on: ubuntu-latest | ||
outputs: | ||
tests: ${{ steps.filter.outputs.tests }} | ||
steps: | ||
- uses: dorny/paths-filter@v2 | ||
id: filter | ||
with: | ||
filters: | | ||
tests: | ||
- 'cypress/**/security-analytics-dashboards-plugin/**' | ||
tests: | ||
needs: changes | ||
if: ${{ needs.changes.outputs.tests == 'true' }} | ||
uses: ./.github/workflows/release-e2e-workflow-template.yml | ||
with: | ||
test-name: Security Analytics | ||
test-command: yarn cypress:run-with-security --browser chromium --spec 'cypress/integration/plugins/security-analytics-dashboards-plugin/*' |
201 changes: 201 additions & 0 deletions
201
cypress/integration/plugins/security-analytics-dashboards-plugin/rules_spec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { PLUGIN_NAME, TWENTY_SECONDS_TIMEOUT } from '../../../utils/plugins/security-analytics-dashboards-plugin/constants' | ||
import {BASE_PATH} from "../../../utils/base_constants"; | ||
|
||
const SAMPLE_RULE = { | ||
name: 'Cypress test rule', | ||
logType: 'windows', | ||
description: 'This is a rule used to test the rule creation workflow. Not for production use.', | ||
detection: | ||
'selection:\n Provider_Name: Service Control Manager\nEventID: 7045\nServiceName: ZzNetSvc\n{backspace}{backspace}condition: selection', | ||
detectionLine: [ | ||
'selection:', | ||
'Provider_Name: Service Control Manager', | ||
'EventID: 7045', | ||
'ServiceName: ZzNetSvc', | ||
'condition: selection', | ||
], | ||
severity: 'critical', | ||
tags: ['attack.persistence', 'attack.privilege_escalation', 'attack.t1543.003'], | ||
references: 'https://nohello.com', | ||
falsePositive: 'unknown', | ||
author: 'Cypress Test Runner', | ||
status: 'experimental', | ||
}; | ||
|
||
describe('Rules', () => { | ||
before(() => { | ||
// Deleting pre-existing test rules | ||
cy.deleteRule(SAMPLE_RULE.name); | ||
}); | ||
beforeEach(() => { | ||
// Visit Rules page | ||
cy.visit(`${BASE_PATH}/app/${PLUGIN_NAME}#/rules`); | ||
}); | ||
|
||
describe('Can be created', () => { | ||
it('manually using UI', () => { | ||
// Click "create new rule" button | ||
cy.get('[data-test-subj="create_rule_button"]', TWENTY_SECONDS_TIMEOUT).click({ | ||
force: true, | ||
}); | ||
|
||
// Enter the name | ||
cy.get('[data-test-subj="rule_name_field"]', TWENTY_SECONDS_TIMEOUT).type(SAMPLE_RULE.name); | ||
|
||
// Enter the log type | ||
cy.get('[data-test-subj="rule_type_dropdown"]', TWENTY_SECONDS_TIMEOUT).select( | ||
SAMPLE_RULE.logType | ||
); | ||
|
||
// Enter the description | ||
cy.get('[data-test-subj="rule_description_field"]', TWENTY_SECONDS_TIMEOUT).type( | ||
SAMPLE_RULE.description | ||
); | ||
|
||
// Enter the detection | ||
cy.get('[data-test-subj="rule_detection_field"]', TWENTY_SECONDS_TIMEOUT).type( | ||
SAMPLE_RULE.detection | ||
); | ||
|
||
// Enter the severity | ||
cy.get('[data-test-subj="rule_severity_dropdown"]', TWENTY_SECONDS_TIMEOUT).select( | ||
SAMPLE_RULE.severity | ||
); | ||
|
||
// Enter the tags | ||
SAMPLE_RULE.tags.forEach((tag) => | ||
cy | ||
.get('[data-test-subj="rule_tags_dropdown"]', TWENTY_SECONDS_TIMEOUT) | ||
.type(`${tag}{enter}{esc}`) | ||
); | ||
|
||
// Enter the reference | ||
cy.get('[data-test-subj="rule_references_field_0"]', TWENTY_SECONDS_TIMEOUT).type( | ||
SAMPLE_RULE.references | ||
); | ||
|
||
// Enter the false positive cases | ||
cy.get('[data-test-subj="rule_false_positive_cases_field_0"]', TWENTY_SECONDS_TIMEOUT).type( | ||
SAMPLE_RULE.falsePositive | ||
); | ||
|
||
// Enter the author | ||
cy.get('[data-test-subj="rule_author_field"]', TWENTY_SECONDS_TIMEOUT).type( | ||
SAMPLE_RULE.author | ||
); | ||
|
||
// Enter the log type | ||
cy.get('[data-test-subj="rule_status_dropdown"]', TWENTY_SECONDS_TIMEOUT).select( | ||
SAMPLE_RULE.status | ||
); | ||
|
||
// Click "create" button | ||
cy.get('[data-test-subj="create_rule_button"]', TWENTY_SECONDS_TIMEOUT).click({ | ||
force: true, | ||
}); | ||
|
||
// Wait for the page to finish loading | ||
cy.wait(5000); | ||
cy.contains('No items found', TWENTY_SECONDS_TIMEOUT).should('not.exist'); | ||
|
||
// Search for the rule | ||
cy.get(`input[type="search"]`, TWENTY_SECONDS_TIMEOUT) | ||
// .focus() | ||
.type(`${SAMPLE_RULE.name}{enter}`); | ||
|
||
// Click the rule link to open the details flyout | ||
cy.get(`[data-test-subj="rule_link_${SAMPLE_RULE.name}"]`, TWENTY_SECONDS_TIMEOUT).click(); | ||
|
||
// Confirm the flyout contains the expected values | ||
cy.get(`[data-test-subj="rule_flyout_${SAMPLE_RULE.name}"]`, TWENTY_SECONDS_TIMEOUT) | ||
.click({ force: true }) | ||
.within(() => { | ||
// Validate name | ||
cy.get('[data-test-subj="rule_flyout_rule_name"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
SAMPLE_RULE.name, | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate log type | ||
cy.get('[data-test-subj="rule_flyout_rule_log_type"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
SAMPLE_RULE.logType, | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate description | ||
cy.get( | ||
'[data-test-subj="rule_flyout_rule_description"]', | ||
TWENTY_SECONDS_TIMEOUT | ||
).contains(SAMPLE_RULE.description, TWENTY_SECONDS_TIMEOUT); | ||
|
||
// Validate author | ||
cy.get('[data-test-subj="rule_flyout_rule_author"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
SAMPLE_RULE.author, | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate source is "custom" | ||
cy.get('[data-test-subj="rule_flyout_rule_source"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
'Custom', | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate severity | ||
cy.get('[data-test-subj="rule_flyout_rule_severity"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
SAMPLE_RULE.severity, | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate tags | ||
SAMPLE_RULE.tags.forEach((tag) => | ||
cy | ||
.get('[data-test-subj="rule_flyout_rule_tags"]', TWENTY_SECONDS_TIMEOUT) | ||
.contains(tag, TWENTY_SECONDS_TIMEOUT) | ||
); | ||
|
||
// Validate references | ||
cy.get('[data-test-subj="rule_flyout_rule_references"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
SAMPLE_RULE.references, | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate false positives | ||
cy.get( | ||
'[data-test-subj="rule_flyout_rule_false_positives"]', | ||
TWENTY_SECONDS_TIMEOUT | ||
).contains(SAMPLE_RULE.falsePositive, TWENTY_SECONDS_TIMEOUT); | ||
|
||
// Validate status | ||
cy.get('[data-test-subj="rule_flyout_rule_status"]', TWENTY_SECONDS_TIMEOUT).contains( | ||
SAMPLE_RULE.status, | ||
TWENTY_SECONDS_TIMEOUT | ||
); | ||
|
||
// Validate detection | ||
SAMPLE_RULE.detectionLine.forEach((line) => | ||
cy | ||
.get('[data-test-subj="rule_flyout_rule_detection"]', TWENTY_SECONDS_TIMEOUT) | ||
.contains(line, TWENTY_SECONDS_TIMEOUT) | ||
); | ||
|
||
// Close the flyout | ||
cy.get('[data-test-subj="euiFlyoutCloseButton"]', TWENTY_SECONDS_TIMEOUT).click({ | ||
force: true, | ||
}); | ||
}); | ||
|
||
// Confirm flyout closed | ||
cy.contains(`[data-test-subj="rule_flyout_${SAMPLE_RULE.name}"]`).should('not.exist'); | ||
}); | ||
}); | ||
|
||
after(() => { | ||
// Deleting test rules | ||
cy.deleteRule(SAMPLE_RULE.name); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
cypress/utils/plugins/security-analytics-dashboards-plugin/commands.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
const { NODE_API } = require('./constants'); | ||
|
||
// *********************************************** | ||
// This example commands.js shows you how to | ||
// create various custom commands and overwrite | ||
// existing commands. | ||
// | ||
// For more comprehensive examples of custom | ||
// commands please read more here: | ||
// https://on.cypress.io/custom-commands | ||
// *********************************************** | ||
// | ||
// | ||
// -- This is a parent command -- | ||
|
||
|
||
Cypress.Commands.add('createRule', (ruleJSON) => { | ||
cy.request('POST', `${Cypress.env('opensearch')}${NODE_API.RULES_BASE}`, ruleJSON); | ||
}); | ||
|
||
Cypress.Commands.add('updateRule', (ruleId, ruleJSON) => { | ||
cy.request('PUT', `${Cypress.env('opensearch')}/${NODE_API.RULES_BASE}/${ruleId}`, ruleJSON); | ||
}); | ||
|
||
Cypress.Commands.add('deleteRule', (ruleName) => { | ||
const body = { | ||
from: 0, | ||
size: 5000, | ||
query: { | ||
nested: { | ||
path: 'rule', | ||
query: { | ||
bool: { | ||
must: [{ match: { 'rule.title': 'Cypress test rule' } }], | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; | ||
cy.request({ | ||
method: 'POST', | ||
url: `${Cypress.env('opensearch')}${NODE_API.RULES_BASE}/_search?pre_packaged=false`, | ||
failOnStatusCode: false, | ||
body, | ||
}).then((response) => { | ||
if (response.status === 200) { | ||
for (let hit of response.body.hits.hits) { | ||
if (hit._source.title === ruleName) | ||
cy.request( | ||
'DELETE', | ||
`${Cypress.env('opensearch')}${NODE_API.RULES_BASE}/${hit._id}?forced=true` | ||
); | ||
} | ||
} | ||
}); | ||
}); | ||
|
31 changes: 31 additions & 0 deletions
31
cypress/utils/plugins/security-analytics-dashboards-plugin/constants.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
export const TWENTY_SECONDS_TIMEOUT = { timeout: 20000 }; | ||
|
||
export const INDICES = { | ||
DETECTORS_INDEX: '.opensearch-detectors-config', | ||
PRE_PACKAGED_RULES_INDEX: '.opensearch-pre-packaged-rules-config', | ||
CUSTOM_RULES_INDEX: '.opensearch-custom-rules-config', | ||
}; | ||
|
||
export const PLUGIN_NAME = 'opensearch_security_analytics_dashboards'; | ||
export const BASE_API_PATH = '/_plugins/_security_analytics'; | ||
|
||
export const NODE_API = { | ||
DETECTORS_BASE: `${BASE_API_PATH}/detectors`, | ||
SEARCH_DETECTORS: `${BASE_API_PATH}/detectors/_search`, | ||
INDICES_BASE: `${BASE_API_PATH}/indices`, | ||
GET_FINDINGS: `${BASE_API_PATH}/findings/_search`, | ||
DOCUMENT_IDS_QUERY: `${BASE_API_PATH}/document_ids_query`, | ||
TIME_RANGE_QUERY: `${BASE_API_PATH}/time_range_query`, | ||
MAPPINGS_BASE: `${BASE_API_PATH}/mappings`, | ||
MAPPINGS_VIEW: `${BASE_API_PATH}/mappings/view`, | ||
GET_ALERTS: `${BASE_API_PATH}/alerts`, | ||
RULES_BASE: `${BASE_API_PATH}/rules`, | ||
CHANNELS: `${BASE_API_PATH}/_notifications/channels`, | ||
ACKNOWLEDGE_ALERTS: `${BASE_API_PATH}/detectors/{detector_id}/_acknowledge/alerts`, | ||
INDEX_TEMPLATE_BASE: '/_index_template', | ||
}; |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters