Skip to content

Commit

Permalink
Rapid7 InsightVM Cloud - 840 - Action Asset Search: Added optional as…
Browse files Browse the repository at this point in the history
…set and vulnerability criteria logical operator | Updated action to return more than 500 results (#2894)
  • Loading branch information
igorski-r7 authored Oct 28, 2024
1 parent 0675afc commit bd1755b
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 60 deletions.
8 changes: 4 additions & 4 deletions plugins/rapid7_insightvm_cloud/.CHECKSUM
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"spec": "f8a386a8b13e83d35404a6db19ba66d3",
"manifest": "2ec65710afd59eba0f073c1ca495e371",
"setup": "36a1e57b169858bc4bb58962de0bbd98",
"spec": "7f1fcd452a00968b4db4499701b0927c",
"manifest": "46c573508c6f9244eaf54d485ec8d14f",
"setup": "7636fcd09663aced0fa6da252ad9d556",
"schemas": [
{
"identifier": "asset_search/schema.py",
"hash": "26518fe5826c1ec369f5cd28436d3133"
"hash": "6fda8474fb613499b7ee698fec90f8ec"
},
{
"identifier": "get_asset/schema.py",
Expand Down
2 changes: 1 addition & 1 deletion plugins/rapid7_insightvm_cloud/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.1.2
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.1.4

LABEL organization=rapid7
LABEL sdk=python
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ from sys import argv

Name = "Rapid7 InsightVM Cloud"
Vendor = "rapid7"
Version = "8.0.0"
Version = "8.1.0"
Description = "InsightVM is a powerful vulnerability management tool which finds, prioritizes, and remediates vulnerabilities. This plugin uses the InsightVM Cloud Integrations API to view assets and start scans"


Expand Down
5 changes: 4 additions & 1 deletion plugins/rapid7_insightvm_cloud/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ This action is used to search for assets using filtered asset search
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|asset_criteria|string|None|False|Filters to apply to the asset search such as IPv4 or IPv6 addresses and hostnames|None|asset.ipv4 = 2001:db8:1:1:1:1:1:1 || asset.name STARTS WITH 'example'|None|None|
|comparison_time|date|None|False|The date and time to compare the asset current state against to detect changes|None|2021-04-15T17:56:47Z|None|None|
|criteria_operator|string|None|False|The logical query operator used to combine asset and/or vulnerability criteria. Only applicable when both asset and vulnerability criteria are entered|["", "AND", "OR"]|AND|None|None|
|current_time|date|None|False|The current date and time to compare against the asset state to detect changes|None|2021-04-15T17:56:47Z|None|None|
|size|integer|200|False|The number of assets to retrieve. If blank then will default to 200 assets returned, the maximum limit is 500 assets|None|100|None|None|
|size|integer|200|False|The number of assets to retrieve. If blank then will default to 200 assets returned|None|100|None|None|
|sort_criteria|object|None|False|JSON object for sorting by criteria. Multiple criteria can be specified with an order of 'asc' (ascending) or 'desc' (descending)|None|{"risk-score": "asc", "criticality-tag": "desc"}|None|None|
|vuln_criteria|string|None|False|Vulnerability criteria to filter by|None|vulnerability.categories IN ['example']|None|None|

Expand All @@ -64,6 +65,7 @@ Example input:
{
"asset_criteria": "asset.ipv4 = 2001:db8:1:1:1:1:1:1 || asset.name STARTS WITH 'example'",
"comparison_time": "2021-04-15T17:56:47Z",
"criteria_operator": "AND",
"current_time": "2021-04-15T17:56:47Z",
"size": 200,
"sort_criteria": {
Expand Down Expand Up @@ -890,6 +892,7 @@ Example output:

# Version History

* 8.1.0 - Action `Asset Search`: Added optional asset and vulnerability criteria logical operator | Updated action to return more than 500 results
* 8.0.0 - Output for `Asset Search` and `Get Asset` to label fields `ID` and `Solution Type` as un-required
* 7.0.0 - `Asset Search` and `Get Asset` actions output field `remediated` updated to type array of object
* 6.0.0 - Asset Search: Modify type of output field `new` when `comparison_time` input is used.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from typing import Dict, Any

import insightconnect_plugin_runtime
from insightconnect_plugin_runtime.helper import clean

from .schema import AssetSearchInput, AssetSearchOutput, Input, Output, Component
from icon_rapid7_insightvm_cloud.util.constants import CRITERIA_OPERATOR_MAP


class AssetSearch(insightconnect_plugin_runtime.Action):
Expand All @@ -13,26 +12,52 @@ def __init__(self):
)

def run(self, params={}):
body = clean(
{"asset": params.pop(Input.ASSET_CRITERIA, None), "vulnerability": params.pop(Input.VULN_CRITERIA, None)}
)
parameters = {
Input.SIZE: self._get_size(params),
"currentTime": params.get(Input.CURRENT_TIME),
"comparisonTime": params.get(Input.COMPARISON_TIME),
# START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION
asset_criteria = params.get(Input.ASSET_CRITERIA, "")
vulnerability_criteria = params.get(Input.VULN_CRITERIA, "")
operator_criteria = params.get(Input.CRITERIA_OPERATOR, "")
current_time = params.get(Input.CURRENT_TIME, "")
comparison_time = params.get(Input.COMPARISON_TIME, "")
sort_criteria = params.get(Input.SORT_CRITERIA, {})
size = params.get(Input.SIZE, 200)
# END INPUT BINDING - DO NOT REMOVE

# Setting up the JSON body for request
json_body = {"asset": asset_criteria, "vulnerability": vulnerability_criteria}
if all((asset_criteria, vulnerability_criteria)):
vulnerability_query = vulnerability_criteria.replace("vulnerability.", "asset.vulnerability.")
json_body = {
"asset": f"{asset_criteria} {CRITERIA_OPERATOR_MAP.get(operator_criteria, '&&')} {vulnerability_query}"
}

# Setting up query parameters for request
query_parameters = {
"size": size,
"currentTime": current_time,
"comparisonTime": comparison_time,
}
for key, value in params.get("sort_criteria", {}).items():
parameters["sort"] = f"{key},{value}"

parameters = clean(parameters)
resources = self.connection.ivm_cloud_api.call_api("assets", "POST", parameters, body)

assets = resources.get("data", [])
for key, value in sort_criteria.items():
query_parameters["sort"] = f"{key},{value}"

assets = []
for page in range(0, 10_000):
self.logger.info(f"Receiving {page} page of results...")
query_parameters["page"] = page
resources = self.connection.ivm_cloud_api.call_api(
"assets", "POST", clean(query_parameters), clean(json_body)
).get("data", [])
assets += resources

# If no more records returned, then we pulled all the search results
if not resources:
self.logger.info("Pagination has finished.")
break

# If the `size` parameter is greater than 500, then we will have 500 results on each page. If we want to retrieve 502 results, then size needs to be set to 502
# we should retrieve data from 2 pages in that case and cut off unnecessary results to return 502 of them.
if len(assets) >= size:
assets = assets[:size]
break

self.logger.info(f"Found {len(assets)} assets. Returning results...")
return {Output.ASSETS: assets}

def _get_size(self, params: Dict[str, Any]) -> int:
size = params.get(Input.SIZE, 200)
if size > 500:
self.logger.info(f"'{size}' too large, set to max size of 500.")
size = 500
return size
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Component:
class Input:
ASSET_CRITERIA = "asset_criteria"
COMPARISON_TIME = "comparison_time"
CRITERIA_OPERATOR = "criteria_operator"
CURRENT_TIME = "current_time"
SIZE = "size"
SORT_CRITERIA = "sort_criteria"
Expand Down Expand Up @@ -38,20 +39,31 @@ class AssetSearchInput(insightconnect_plugin_runtime.Input):
"displayType": "date",
"title": "Comparison Time",
"description": "The date and time to compare the asset current state against to detect changes",
"order": 6
"order": 7
},
"criteria_operator": {
"type": "string",
"title": "Criteria Logical Operator",
"description": "The logical query operator used to combine asset and/or vulnerability criteria. Only applicable when both asset and vulnerability criteria are entered",
"enum": [
"",
"AND",
"OR"
],
"order": 5
},
"current_time": {
"type": "string",
"format": "date-time",
"displayType": "date",
"title": "Current Time",
"description": "The current date and time to compare against the asset state to detect changes",
"order": 5
"order": 6
},
"size": {
"type": "integer",
"title": "Size",
"description": "The number of assets to retrieve. If blank then will default to 200 assets returned, the maximum limit is 500 assets",
"description": "The number of assets to retrieve. If blank then will default to 200 assets returned",
"default": 200,
"order": 1
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CRITERIA_OPERATOR_MAP = {"AND": "&&", "OR": "||"}
57 changes: 34 additions & 23 deletions plugins/rapid7_insightvm_cloud/plugin.spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,58 @@ products: [insightconnect]
name: rapid7_insightvm_cloud
title: Rapid7 InsightVM Cloud
description: InsightVM is a powerful vulnerability management tool which finds, prioritizes, and remediates vulnerabilities. This plugin uses the InsightVM Cloud Integrations API to view assets and start scans
version: 8.0.0
version: 8.1.0
connection_version: 6
key_features:
- "Perform scan management functionality including starting and checking the status of scans"
- "Perform asset searches leveraging flexible asset and vulnerability filters"
- "Retrieve individual asset information"
requirements:
- "Requires an InsightVM API Key"
- "InsightVM Scan Engine(s) paired to the Insight Platform"
version_history:
- "8.1.0 - Action `Asset Search`: Added optional asset and vulnerability criteria logical operator | Updated action to return more than 500 results"
- "8.0.0 - Output for `Asset Search` and `Get Asset` to label fields `ID` and `Solution Type` as un-required"
- "7.0.0 - `Asset Search` and `Get Asset` actions output field `remediated` updated to type array of object"
- "6.0.0 - Asset Search: Modify type of output field `new` when `comparison_time` input is used."
- "5.0.0 - Vulnerability Search: fix malware_kits output and remove Asset Criteria input | Updated the documentation with links related to query builder and operators | Updated the SDK"
- "4.0.0 - Vulnerability Search: fix schema validation problem for exploits field"
- "3.3.0 - Asset Search: add filter fields: `current_time`, `comparison_time`"
- "3.2.0 - Add vulnerability search action"
- "3.1.0 - Add Cloud enablement to plugin | Updated exception information and error handling | Made status code output for Stop Scan and Get Scan actions more exact | Fix bug relating to empty inputs being passed in request body"
- "3.0.0 - Changed output of Get Asset action to include vulnerabilities properly"
- "2.2.0 - Added ability to include vulnerabilities on Get Asset action | API call update"
- "2.1.0 - Added scanned asset_ids as an output of start_scan"
- "2.0.0 - Fix issue where string data-type should be date in actions | Update docs"
- "1.0.0 - Initial plugin"
links:
- "[InsightVM Query Builder](https://docs.rapid7.com/insightvm/query-builder/)"
- "[InsightVM Query Operators](https://docs.rapid7.com/insightvm/query-operators-1/)"
references:
- "[InsightVM Cloud API](https://help.rapid7.com/insightvm/en-us/api/integrations.html)"
- "[Managing Platform API Keys](https://docs.rapid7.com/insight/managing-platform-api-keys)"
- "[Scan Engine Pairing](https://docs.rapid7.com/insightvm/scan-engine-management-on-the-insight-platform/#how-to-pair-your-scan-engines-to-the-insight-platform)"
requirements:
- "Requires an InsightVM API Key"
- "InsightVM Scan Engine(s) paired to the Insight Platform"
vendor: rapid7
support: rapid7
supported_versions: ["InsightVM Cloud Integration API v4", "2024-06-19"]
status: []
cloud_ready: true
sdk:
type: slim
version: 6.1.2
version: 6.1.4
user: nobody
resources:
source_url: https://github.com/rapid7/insightconnect-plugins/tree/master/plugins/rapid7_insightvm_cloud
license_url: https://github.com/rapid7/insightconnect-plugins/blob/master/LICENSE
vendor_url: https://www.rapid7.com
tags:
- insightvm
- rapid7
- vulnerability
- insightvm
- rapid7
- vulnerability
hub_tags:
use_cases: [asset_inventory, vulnerability_management]
keywords: [insightvm, rapid7, cloud, cloud_enabled]
features: []
version_history:
- "8.0.0 - Output for `Asset Search` and `Get Asset` to label fields `ID` and `Solution Type` as un-required"
- "7.0.0 - `Asset Search` and `Get Asset` actions output field `remediated` updated to type array of object"
- "6.0.0 - Asset Search: Modify type of output field `new` when `comparison_time` input is used."
- "5.0.0 - Vulnerability Search: fix malware_kits output and remove Asset Criteria input | Updated the documentation with links related to query builder and operators | Updated the SDK"
- "4.0.0 - Vulnerability Search: fix schema validation problem for exploits field"
- "3.3.0 - Asset Search: add filter fields: `current_time`, `comparison_time`"
- "3.2.0 - Add vulnerability search action"
- "3.1.0 - Add Cloud enablement to plugin | Updated exception information and error handling | Made status code output for Stop Scan and Get Scan actions more exact | Fix bug relating to empty inputs being passed in request body"
- "3.0.0 - Changed output of Get Asset action to include vulnerabilities properly"
- "2.2.0 - Added ability to include vulnerabilities on Get Asset action | API call update"
- "2.1.0 - Added scanned asset_ids as an output of start_scan"
- "2.0.0 - Fix issue where string data-type should be date in actions | Update docs"
- "1.0.0 - Initial plugin"
types:
link:
href:
Expand Down Expand Up @@ -1131,7 +1132,7 @@ actions:
input:
size:
title: Size
description: The number of assets to retrieve. If blank then will default to 200 assets returned, the maximum limit is 500 assets
description: The number of assets to retrieve. If blank then will default to 200 assets returned
type: integer
required: false
default: 200
Expand All @@ -1154,6 +1155,16 @@ actions:
type: string
required: false
example: "vulnerability.categories IN ['example']"
criteria_operator:
title: Criteria Logical Operator
description: The logical query operator used to combine asset and/or vulnerability criteria. Only applicable when both asset and vulnerability criteria are entered
type: string
required: false
enum:
- ""
- AND
- OR
example: AND
current_time:
title: Current Time
description: The current date and time to compare against the asset state to detect changes
Expand Down
2 changes: 1 addition & 1 deletion plugins/rapid7_insightvm_cloud/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# List third-party dependencies here, separated by newlines.
# All dependencies must be version-pinned, eg. requests==1.2.0
# See: https://pip.pypa.io/en/stable/user_guide/#requirements-files
# See: https://pip.pypa.io/en/stable/user_guide/#requirements-files
2 changes: 1 addition & 1 deletion plugins/rapid7_insightvm_cloud/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


setup(name="rapid7_insightvm_cloud-rapid7-plugin",
version="8.0.0",
version="8.1.0",
description="InsightVM is a powerful vulnerability management tool which finds, prioritizes, and remediates vulnerabilities. This plugin uses the InsightVM Cloud Integrations API to view assets and start scans",
author="rapid7",
author_email="",
Expand Down
6 changes: 4 additions & 2 deletions plugins/rapid7_insightvm_cloud/unit_test/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ def mock_request_post(url, params, headers, data): # noqa: MC0001
if headers.get("x-api-key") == STUB_SECRET_KEY_SERVER_ERROR:
return MockResponse("server_error", 500)
if url == f"https://{STUB_REGION}.api.insight.rapid7.com/vm/v4/integration/assets":
if data.get("asset") == STUB_BAD_ASSET_CRITERIA:
if params.get("page"):
return MockResponse("asset_search_empty", 200)
if data.get("asset", "") == STUB_BAD_ASSET_CRITERIA or STUB_BAD_ASSET_CRITERIA in data.get("asset", ""):
return MockResponse("asset_search_invalid_asset_criteria", 400)
if data.get("vulnerability") == STUB_BAD_VULN_CRITERIA:
if data.get("vulnerability") == STUB_BAD_VULN_CRITERIA or STUB_BAD_VULN_CRITERIA in data.get("asset", ""):
return MockResponse("asset_search_invalid_vuln_criteria", 400)
return MockResponse("asset_search", 200)
if url == f"https://{STUB_REGION}.api.insight.rapid7.com/vm/v4/integration/vulnerabilities":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"data": [
],
"metadata": {
"number": 0,
"size": 100,
"totalResources": 2,
"totalPages": 1
},
"links": [
{
"href": "https://us.api.insight.rapid7.com:443/vm/v4/integration/assets?asset_criteria=last_scan_end+%3E+2000-01-01T00%3A00%3A00.000Z&sort_criteria=risk-score&sort_criteria=criticality-tag&vuln_criteria=severity+IN+%5B%27Critical%27%2C+%27Severe%27%5D&page=0&size=10&sort=id,asc",
"rel": "self"
}
]
}
3 changes: 3 additions & 0 deletions plugins/rapid7_insightvm_cloud/unit_test/test_asset_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def test_asset_search_all_inputs(self, _mock_req: MagicMock) -> None:
Input.SIZE: self.params.get("size"),
Input.SORT_CRITERIA: self.params.get("sort_criteria"),
Input.VULN_CRITERIA: self.params.get("vuln_criteria"),
Input.CRITERIA_OPERATOR: "OR",
}
)
expected = Utils.read_file_to_dict("expected_responses/asset_search.json.resp")
Expand All @@ -67,6 +68,7 @@ def test_asset_invalid_asset_criteria(self, _mock_req: MagicMock) -> None:
Input.SIZE: self.params.get("size"),
Input.SORT_CRITERIA: self.params.get("sort_criteria"),
Input.VULN_CRITERIA: self.params.get("vuln_criteria"),
Input.CRITERIA_OPERATOR: "OR",
}
)
cause = "The server is unable to process the request."
Expand All @@ -86,6 +88,7 @@ def test_asset_vuln_criteria_invalid(self, _mock_req: MagicMock) -> None:
Input.SIZE: self.params.get("size"),
Input.SORT_CRITERIA: self.params.get("sort_criteria"),
Input.VULN_CRITERIA: self.params.get("vuln_criteria_invalid"),
Input.CRITERIA_OPERATOR: "OR",
}
)
cause = "The server is unable to process the request."
Expand Down

0 comments on commit bd1755b

Please sign in to comment.