Data Posture API Tutorial: Difference between revisions
(4 intermediate revisions by the same user not shown) | |||
Line 72: | Line 72: | ||
| '''dataSourceName''' || Affected resource | | '''dataSourceName''' || Affected resource | ||
|} | |} | ||
== 4. Mark Issues as Resolved == | == 4. Mark Issues as Resolved == | ||
Line 163: | Line 161: | ||
== Code Samples == | == Code Samples == | ||
<tabs> | |||
<tab name="Python"><syntaxhighlight lang="python" line> | |||
# Data Posture API Tutorial | |||
import requests | |||
import json | |||
# --- 1. Setup and Authentication --- | |||
# Base URL of the BigID API (training sandbox) | |||
base_url = "https://developer.bigid.com/api/v1" | |||
# Session token (replace SAMPLE with actual session token) | |||
AUTH_TOKEN = "SAMPLE" | |||
headers = { | |||
"Authorization": f"Bearer {AUTH_TOKEN}", | |||
"Content-Type": "application/json" | |||
} | |||
def get_issues(filters=None): | |||
""" | |||
Fetches security cases from the actionable-insights endpoint. | |||
Args: | |||
filters (dict): A dictionary of query parameters like {'limit': 10, 'filter': '...'}. | |||
Returns: | |||
list: A list of case objects, or an empty list if none are found. | |||
""" | |||
cases_url = f"{base_url}/actionable-insights/all-cases" | |||
try: | |||
response = requests.get(cases_url, headers=headers, params=filters) | |||
response.raise_for_status() | |||
issues = response.json() | |||
print(f" -> Found {len(issues)} issues.") | |||
return issues | |||
except requests.exceptions.HTTPError as http_err: | |||
print(f"HTTP error occurred while fetching issues: {http_err}") | |||
return [] | |||
def move_issues_to_system(issues): | |||
""" | |||
A placeholder function to simulate exporting issues to a third-party system. | |||
Args: | |||
issues (list): A list of case objects. | |||
Returns: | |||
list: A list of case IDs that were "exported". | |||
""" | |||
exported_ids = [] | |||
for issue in issues: | |||
case_id = issue.get("caseId") | |||
# Example mapping | |||
ticket_data = { | |||
"title": issue.get("caseLabel"), | |||
"priority": issue.get("severityLevel"), | |||
"description": f"Policy: {issue.get('policyName')}, Source: {issue.get('dataSourceName')}", | |||
"assignee": issue.get("assignee") | |||
} | |||
print(f" -> Creating ticket for Case ID {case_id}: {ticket_data['title']}") | |||
exported_ids.append(case_id) | |||
print(" -> Simulation complete.") | |||
return exported_ids | |||
def resolve_single_issue(case_id): | |||
""" | |||
Marks a single case as resolved. | |||
""" | |||
resolve_url = f"{base_url}/actionable-insights/case-status/{case_id}" | |||
payload = { | |||
"caseStatus": "resolved", | |||
"auditReason": f"Remediated and moved on {json.dumps(requests.get('http://worldtimeapi.org/api/ip').json()['datetime'])}" | |||
} | |||
try: | |||
response = requests.patch(resolve_url, headers=headers, json=payload) | |||
response.raise_for_status() | |||
print(f" -> Successfully marked case {case_id} as resolved.") | |||
return True | |||
except requests.exceptions.HTTPError as http_err: | |||
print(f"HTTP error occurred while resolving case {case_id}: {http_err}") | |||
return False | |||
def resolve_issues_in_bulk(policy_name): | |||
""" | |||
Marks all open cases for a given policy name as resolved. | |||
""" | |||
bulk_resolve_url = f"{base_url}/actionable-insights/cases:update" # Assuming 'update' is the actionType | |||
payload = { | |||
"type": "CasesDB", | |||
"subType": "updateCases", | |||
"additionalProperties": { | |||
"field": "caseStatus", # Field to update | |||
"newValue": "resolved", # New value | |||
"casesFilters": [ | |||
{ | |||
"filterField": "policyName", | |||
"filterValues": [ policy_name ] | |||
}, | |||
{ | |||
"filterField": "caseStatus", | |||
"filterValues": [ "open" ] # Only target open cases | |||
} | |||
] | |||
} | |||
} | |||
try: | |||
response = requests.patch(bulk_resolve_url, headers=headers, json=payload) | |||
response.raise_for_status() | |||
updated_cases = response.json() | |||
print(f" -> Successfully resolved {len(updated_cases.get('caseIds', []))} cases in bulk.") | |||
return updated_cases | |||
except requests.exceptions.HTTPError as http_err: | |||
print(f"HTTP error occurred during bulk resolve: {http_err}") | |||
return None | |||
# --- Main Workflow --- | |||
if __name__ == "__main__": | |||
# 2. Retrieve the first 5 open issues for demonstration | |||
open_issues = get_issues(filters={'limit': 5, 'filter': '{"caseStatus": "open"}'}) | |||
if open_issues: | |||
# 3. Simulate exporting these issues | |||
exported_case_ids = export_issues_to_system(open_issues) | |||
# 4. Mark issues as resolved | |||
if exported_case_ids: | |||
# Option A: Resolve the first exported issue individually | |||
resolve_single_issue(exported_case_ids[0]) | |||
# Option B: Resolve all issues for a specific policy in bulk | |||
# We'll use the policy from the second issue as an example | |||
if len(open_issues) > 1: | |||
example_policy = open_issues[1].get("policyName") | |||
if example_policy: | |||
resolve_issues_in_bulk(example_policy) | |||
</syntaxhighlight></tab> | |||
<tab name="JavaScript"><syntaxhighlight lang="javascript" line> | |||
// Data Posture API Tutorial | |||
// --- 1. Setup and Authentication --- | |||
// Base URL of the BigID API (training sandbox) | |||
const base_url = "https://developer.bigid.com/api/v1"; | |||
// Session token (replace SAMPLE with actual session token) | |||
const AUTH_TOKEN = "SAMPLE"; | |||
const headers = { | |||
"Authorization": `Bearer ${AUTH_TOKEN}`, | |||
"Content-Type": "application/json" | |||
}; | |||
/** | |||
* Fetches security cases from the actionable-insights endpoint. | |||
* @param {URLSearchParams} params - Query parameters for the request. | |||
* @returns {Promise<Array>} A list of case objects, or an empty list if none are found. | |||
*/ | |||
async function get_issues(params) { | |||
const cases_url = `${base_url}/actionable-insights/all-cases?${params}`; | |||
try { | |||
const response = await fetch(cases_url, { headers }); | |||
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); | |||
const issues = await response.json(); | |||
console.log(` -> Found ${issues.length} issues.`); | |||
return issues; | |||
} catch (error) { | |||
console.error("HTTP error occurred while fetching issues:", error.message); | |||
return []; | |||
} | |||
} | |||
/** | |||
* A placeholder function to simulate exporting issues to a third-party system. | |||
* @param {Array} issues - A list of case objects. | |||
* @returns {Array} A list of case IDs that were "exported". | |||
*/ | |||
function move_issues_to_system(issues) { | |||
const exported_ids = issues.map(issue => { | |||
const case_id = issue.caseId; | |||
// Example mapping | |||
const ticket_data = { | |||
title: issue.caseLabel, | |||
priority: issue.severityLevel, | |||
description: `Policy: ${issue.policyName}, Source: ${issue.dataSourceName}`, | |||
assignee: issue.assignee | |||
}; | |||
console.log(` -> Creating ticket for Case ID ${case_id}: ${ticket_data.title}`); | |||
return case_id; | |||
}); | |||
console.log(" -> Simulation complete."); | |||
return exported_ids; | |||
} | |||
/** | |||
* Marks a single case as resolved. | |||
* @param {string} case_id - The ID of the case to resolve. | |||
*/ | |||
async function resolve_single_issue(case_id) { | |||
const resolve_url = `${base_url}/actionable-insights/case-status/${case_id}`; | |||
const timeResponse = await fetch('http://worldtimeapi.org/api/ip'); | |||
const timeData = await timeResponse.json(); | |||
const payload = { | |||
caseStatus: "resolved", | |||
auditReason: `Remediated and moved on ${timeData.datetime}` | |||
}; | |||
try { | |||
const response = await fetch(resolve_url, { method: 'PATCH', headers, body: JSON.stringify(payload) }); | |||
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); | |||
console.log(` -> Successfully marked case ${case_id} as resolved.`); | |||
return true; | |||
} catch (error) { | |||
console.error(`HTTP error occurred while resolving case ${case_id}:`, error.message); | |||
return false; | |||
} | |||
} | |||
/** | |||
* Marks all open cases for a given policy name as resolved. | |||
* @param {string} policy_name - The name of the policy to filter by. | |||
*/ | |||
async function resolve_issues_in_bulk(policy_name) { | |||
const bulk_resolve_url = `${base_url}/actionable-insights/cases:update`; // Assuming 'update' is the actionType | |||
const payload = { | |||
"type": "CasesDB", | |||
"subType": "updateCases", | |||
"additionalProperties": { | |||
"field": "caseStatus", // Field to update | |||
"newValue": "resolved", // New value | |||
"casesFilters": [ | |||
{ "filterField": "policyName", "filterValues": [policy_name] }, | |||
{ "filterField": "caseStatus", "filterValues": ["open"] } // Only target open cases | |||
] | |||
} | |||
}; | |||
try { | |||
const response = await fetch(bulk_resolve_url, { method: 'PATCH', headers, body: JSON.stringify(payload) }); | |||
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`); | |||
const updated_cases = await response.json(); | |||
console.log(` -> Successfully resolved ${updated_cases.caseIds?.length || 0} cases in bulk.`); | |||
return updated_cases; | |||
} catch (error) { | |||
console.error("HTTP error occurred during bulk resolve:", error.message); | |||
return null; | |||
} | |||
} | |||
// --- Main Workflow --- | |||
async function runWorkflow() { | |||
// 2. Retrieve the first 5 open issues for demonstration | |||
const params = new URLSearchParams({ | |||
limit: 5, | |||
filter: JSON.stringify({ "caseStatus": "open" }) | |||
}); | |||
const open_issues = await get_issues(params); | |||
if (open_issues.length > 0) { | |||
// 3. Simulate exporting these issues | |||
const exported_case_ids = move_issues_to_system(open_issues); | |||
// 4. Mark issues as resolved | |||
if (exported_case_ids.length > 0) { | |||
// Option A: Resolve the first exported issue individually | |||
await resolve_single_issue(exported_case_ids[0]); | |||
// Option B: Resolve all issues for a specific policy in bulk | |||
// We'll use the policy from the second issue as an example | |||
const example_policy = open_issues[1]?.policyName; | |||
if (example_policy) { | |||
await resolve_issues_in_bulk(example_policy); | |||
} | |||
} | |||
} | |||
} | |||
runWorkflow(); | |||
</syntaxhighlight> | |||
</tab> | |||
</tabs> | |||
<html> | |||
<style> | |||
.tabs-tabbox > .tabs-container { | |||
margin-top: -1px; | |||
padding: | |||
2px 6px; | |||
border-radius: | |||
8px; | |||
position: relative; | |||
border: | |||
2px solid #848484; | |||
width: inherit; | |||
max-width: inherit; | |||
min-width: inherit; | |||
box-shadow: | |||
0px 4px 6px 1px rgba(0, 0, 0, 0.1); | |||
z-index: 1; | |||
} | |||
.tabs-tabbox > .tabs-label { | |||
margin: | |||
0 3px; | |||
border-bottom: | |||
none; | |||
border-radius: | |||
4px 4px 0 0; | |||
position: relative; | |||
display: inline-block; | |||
vertical-align: bottom; | |||
padding-left: 10px; | |||
padding-right: 10px; | |||
padding-bottom: 3px; | |||
padding-top: 3px; | |||
} | |||
.tabs-tabbox > .tabs-input:checked + .tabs-label, .tabs-input-0:checked + .tabs-input-1 + .tabs-label { | |||
background-color: #0e69b2 !important; | |||
border-color: | |||
#848484; | |||
z-index: 0; | |||
color: white; | |||
} | |||
.tabs-label { | |||
cursor: pointer; | |||
border: | |||
2px solid #848484; | |||
} | |||
.mw-body .tabs-label { | |||
background-color: #ffffff26; | |||
} | |||
</style> | |||
</html> | |||
== Summary == | == Summary == | ||
Congratulations! In this tutorial, you have learned how to retrieve open security issues from BigID, export those issues to a third-party system for remediation, and mark the issues as resolved in BigID to keep your backlog clean and accurate. By following these steps, you can streamline your remediation process, reduce manual effort, and maintain a clear, up-to-date view of your organization’s security posture. | Congratulations! In this tutorial, you have learned how to retrieve open security issues from BigID, export those issues to a third-party system for remediation, and mark the issues as resolved in BigID to keep your backlog clean and accurate. By following these steps, you can streamline your remediation process, reduce manual effort, and maintain a clear, up-to-date view of your organization’s security posture. |
Latest revision as of 14:12, 5 August 2025
- How to retrieve security issues from the Data Posture API.
- How to export relevant issues to a third-party system.
- How to use the Apply Action API to update multiple issues at once.
- How to mark issues as resolved after export to keep BigID in sync.
In this tutorial, we'll use SAMPLE as our session token. This is unique to the training sandbox and will not work in other environments. See BigID API/Tutorial for information on authenticating with BigID.
To view the complete code for all steps, see the section labelled Code Samples.
For more information on the API capabilities used in this tutorial, check out the Data Posture API Docs.
1. Authenticate Using Your API Key
All API requests require authentication using a valid API key. Refer to BigID Documentation to obtain your token. Then, define the Authorization header using the format Authorization: Bearer YOUR_API_KEY. This header must be included in every request to ensure proper authentication and access to BigID’s API endpoints. Throughout the tutorial, we will be using SAMPLE as our token.
2. Retrieve Security Issues
There are multiple endpoints available for fetching security cases, but because our goal is to export these issues to a third party system, we want to use the GET /api/v1/actionable-insights/all-cases. This will allow us to fetch all existing security issues, as well as limit the selection based on various parameters if necessary.
In the case that you do not want to fetch all cases, you can filter the response based on several parameters, all of which are outlined in the following table:
Parameter | Type | Description |
---|---|---|
skip | integer | Number of records to skip (for pagination) |
limit | integer | Number of records to return |
filter | string | BigID Query Language filter to narrow results |
fields | string | Comma-separated list of fields to return |
sort | string | Field to sort by, plus optional ASC/DESC |
requireTotalCount | boolean | Whether to include totalCount in response |
Once you have fetched the details for all of the security cases you are interested in, you can proceed to the next step.
3. Export Issues to Your Third-Party System
Once you retrieve the list of open security issues, the next step is to export them to your third-party system for remediation. This could be a ticketing platform like Jira, ServiceNow, or a SOAR tool for automated workflows.
For each issue, map the relevant fields to your third-party system’s API. Common mappings might include:
BigID Field | Third-Party Field |
---|---|
caseLabel | Ticket title |
policyName | Category or label |
severityLevel | Priority |
assignee | Assigned owner |
dataSourceName | Affected resource |
4. Mark Issues as Resolved
After successfully exporting the issues, you’ll want to mark them as resolved in BigID to avoid duplicate work and keep the backlog clean. You have two options for marking issues as resolved using the API.
First, you can do so in bulk using the PATCH /api/v1/actionable-insights/cases:{actionType} endpoint. In order to use this endpoint, you should:
- In the request, tell BigID which field to update (in this case, caseStatus) and what the new value should be (set it to resolved).
- Add filters to select the cases you want to update, like policyName or caseStatus:open.
- Run the request. BigID will return the list of case IDs that were successfully updated.
For example, your request may be structured like the following:
{
"type": "CasesDB",
"subType": "updateCases",
"additionalProperties": {
"field": "assignee",
"newValue": "[email protected]",
"casesFilters": [
{
"filterField": "policyName",
"filterValues": [
"policy1234"
]
},
{
"filterField": "caseStatus",
"filterValues": [
"remediated"
]
}
]
}
}
The following request uses the example request body above. To actually test this endpoint, replace the fields with real values based on the previous steps.
If you only need to update the status of specific cases, this can be done using the PATCH /api/v1/actionable-insights/case-status/{caseId} endpoint. To do so:
- Replace {caseId} with the actual ID of the case you want to update.
- In the request body, set caseStatus to resolved.
- Add an auditReason so your team knows why the change was made (for example, “Exported to Jira on July 14th”).
For example, your request may be structured like the following:
{
"caseStatus": "resolved",
"auditReason": "Exported to Jira on July 14th"
}
In the request below, the {caseId} is currently represented by a fake ID, 123abc. In order to test the endpoint, replace it with a case ID you have addressed in the previous steps.
5. Troubleshooting
If your request fails, here’s what the server might tell you, and how to fix it:
Status Code | Example Response | What It Means | How to Fix It |
---|---|---|---|
200 | Successful response with scan data | Everything’s looking good! | Keep cruising. |
400 | { "error": "Scan ID is invalid" } |
Bad or malformed scan ID provided | Double-check the scan ID you’re using. |
404 | { "error": "Scan 1234 was not found" } |
Scan ID doesn’t exist | Make sure the ID is valid and fetched from the parent scans endpoint. |
401 | Unauthorized | API key missing or invalid | Verify your API key and authorization header. |
500 | { "status": "error", "message": "Server error", "errors": [{}] } |
BigID server hit a snag (internal error) | Wait a moment and retry. If it persists, reach out to support. |
Code Samples
# Data Posture API Tutorial
import requests
import json
# --- 1. Setup and Authentication ---
# Base URL of the BigID API (training sandbox)
base_url = "https://developer.bigid.com/api/v1"
# Session token (replace SAMPLE with actual session token)
AUTH_TOKEN = "SAMPLE"
headers = {
"Authorization": f"Bearer {AUTH_TOKEN}",
"Content-Type": "application/json"
}
def get_issues(filters=None):
"""
Fetches security cases from the actionable-insights endpoint.
Args:
filters (dict): A dictionary of query parameters like {'limit': 10, 'filter': '...'}.
Returns:
list: A list of case objects, or an empty list if none are found.
"""
cases_url = f"{base_url}/actionable-insights/all-cases"
try:
response = requests.get(cases_url, headers=headers, params=filters)
response.raise_for_status()
issues = response.json()
print(f" -> Found {len(issues)} issues.")
return issues
except requests.exceptions.HTTPError as http_err:
print(f"HTTP error occurred while fetching issues: {http_err}")
return []
def move_issues_to_system(issues):
"""
A placeholder function to simulate exporting issues to a third-party system.
Args:
issues (list): A list of case objects.
Returns:
list: A list of case IDs that were "exported".
"""
exported_ids = []
for issue in issues:
case_id = issue.get("caseId")
# Example mapping
ticket_data = {
"title": issue.get("caseLabel"),
"priority": issue.get("severityLevel"),
"description": f"Policy: {issue.get('policyName')}, Source: {issue.get('dataSourceName')}",
"assignee": issue.get("assignee")
}
print(f" -> Creating ticket for Case ID {case_id}: {ticket_data['title']}")
exported_ids.append(case_id)
print(" -> Simulation complete.")
return exported_ids
def resolve_single_issue(case_id):
"""
Marks a single case as resolved.
"""
resolve_url = f"{base_url}/actionable-insights/case-status/{case_id}"
payload = {
"caseStatus": "resolved",
"auditReason": f"Remediated and moved on {json.dumps(requests.get('http://worldtimeapi.org/api/ip').json()['datetime'])}"
}
try:
response = requests.patch(resolve_url, headers=headers, json=payload)
response.raise_for_status()
print(f" -> Successfully marked case {case_id} as resolved.")
return True
except requests.exceptions.HTTPError as http_err:
print(f"HTTP error occurred while resolving case {case_id}: {http_err}")
return False
def resolve_issues_in_bulk(policy_name):
"""
Marks all open cases for a given policy name as resolved.
"""
bulk_resolve_url = f"{base_url}/actionable-insights/cases:update" # Assuming 'update' is the actionType
payload = {
"type": "CasesDB",
"subType": "updateCases",
"additionalProperties": {
"field": "caseStatus", # Field to update
"newValue": "resolved", # New value
"casesFilters": [
{
"filterField": "policyName",
"filterValues": [ policy_name ]
},
{
"filterField": "caseStatus",
"filterValues": [ "open" ] # Only target open cases
}
]
}
}
try:
response = requests.patch(bulk_resolve_url, headers=headers, json=payload)
response.raise_for_status()
updated_cases = response.json()
print(f" -> Successfully resolved {len(updated_cases.get('caseIds', []))} cases in bulk.")
return updated_cases
except requests.exceptions.HTTPError as http_err:
print(f"HTTP error occurred during bulk resolve: {http_err}")
return None
# --- Main Workflow ---
if __name__ == "__main__":
# 2. Retrieve the first 5 open issues for demonstration
open_issues = get_issues(filters={'limit': 5, 'filter': '{"caseStatus": "open"}'})
if open_issues:
# 3. Simulate exporting these issues
exported_case_ids = export_issues_to_system(open_issues)
# 4. Mark issues as resolved
if exported_case_ids:
# Option A: Resolve the first exported issue individually
resolve_single_issue(exported_case_ids[0])
# Option B: Resolve all issues for a specific policy in bulk
# We'll use the policy from the second issue as an example
if len(open_issues) > 1:
example_policy = open_issues[1].get("policyName")
if example_policy:
resolve_issues_in_bulk(example_policy)
// Data Posture API Tutorial
// --- 1. Setup and Authentication ---
// Base URL of the BigID API (training sandbox)
const base_url = "https://developer.bigid.com/api/v1";
// Session token (replace SAMPLE with actual session token)
const AUTH_TOKEN = "SAMPLE";
const headers = {
"Authorization": `Bearer ${AUTH_TOKEN}`,
"Content-Type": "application/json"
};
/**
* Fetches security cases from the actionable-insights endpoint.
* @param {URLSearchParams} params - Query parameters for the request.
* @returns {Promise<Array>} A list of case objects, or an empty list if none are found.
*/
async function get_issues(params) {
const cases_url = `${base_url}/actionable-insights/all-cases?${params}`;
try {
const response = await fetch(cases_url, { headers });
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
const issues = await response.json();
console.log(` -> Found ${issues.length} issues.`);
return issues;
} catch (error) {
console.error("HTTP error occurred while fetching issues:", error.message);
return [];
}
}
/**
* A placeholder function to simulate exporting issues to a third-party system.
* @param {Array} issues - A list of case objects.
* @returns {Array} A list of case IDs that were "exported".
*/
function move_issues_to_system(issues) {
const exported_ids = issues.map(issue => {
const case_id = issue.caseId;
// Example mapping
const ticket_data = {
title: issue.caseLabel,
priority: issue.severityLevel,
description: `Policy: ${issue.policyName}, Source: ${issue.dataSourceName}`,
assignee: issue.assignee
};
console.log(` -> Creating ticket for Case ID ${case_id}: ${ticket_data.title}`);
return case_id;
});
console.log(" -> Simulation complete.");
return exported_ids;
}
/**
* Marks a single case as resolved.
* @param {string} case_id - The ID of the case to resolve.
*/
async function resolve_single_issue(case_id) {
const resolve_url = `${base_url}/actionable-insights/case-status/${case_id}`;
const timeResponse = await fetch('http://worldtimeapi.org/api/ip');
const timeData = await timeResponse.json();
const payload = {
caseStatus: "resolved",
auditReason: `Remediated and moved on ${timeData.datetime}`
};
try {
const response = await fetch(resolve_url, { method: 'PATCH', headers, body: JSON.stringify(payload) });
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
console.log(` -> Successfully marked case ${case_id} as resolved.`);
return true;
} catch (error) {
console.error(`HTTP error occurred while resolving case ${case_id}:`, error.message);
return false;
}
}
/**
* Marks all open cases for a given policy name as resolved.
* @param {string} policy_name - The name of the policy to filter by.
*/
async function resolve_issues_in_bulk(policy_name) {
const bulk_resolve_url = `${base_url}/actionable-insights/cases:update`; // Assuming 'update' is the actionType
const payload = {
"type": "CasesDB",
"subType": "updateCases",
"additionalProperties": {
"field": "caseStatus", // Field to update
"newValue": "resolved", // New value
"casesFilters": [
{ "filterField": "policyName", "filterValues": [policy_name] },
{ "filterField": "caseStatus", "filterValues": ["open"] } // Only target open cases
]
}
};
try {
const response = await fetch(bulk_resolve_url, { method: 'PATCH', headers, body: JSON.stringify(payload) });
if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
const updated_cases = await response.json();
console.log(` -> Successfully resolved ${updated_cases.caseIds?.length || 0} cases in bulk.`);
return updated_cases;
} catch (error) {
console.error("HTTP error occurred during bulk resolve:", error.message);
return null;
}
}
// --- Main Workflow ---
async function runWorkflow() {
// 2. Retrieve the first 5 open issues for demonstration
const params = new URLSearchParams({
limit: 5,
filter: JSON.stringify({ "caseStatus": "open" })
});
const open_issues = await get_issues(params);
if (open_issues.length > 0) {
// 3. Simulate exporting these issues
const exported_case_ids = move_issues_to_system(open_issues);
// 4. Mark issues as resolved
if (exported_case_ids.length > 0) {
// Option A: Resolve the first exported issue individually
await resolve_single_issue(exported_case_ids[0]);
// Option B: Resolve all issues for a specific policy in bulk
// We'll use the policy from the second issue as an example
const example_policy = open_issues[1]?.policyName;
if (example_policy) {
await resolve_issues_in_bulk(example_policy);
}
}
}
}
runWorkflow();
Summary
Congratulations! In this tutorial, you have learned how to retrieve open security issues from BigID, export those issues to a third-party system for remediation, and mark the issues as resolved in BigID to keep your backlog clean and accurate. By following these steps, you can streamline your remediation process, reduce manual effort, and maintain a clear, up-to-date view of your organization’s security posture.