Palo Alto Networks Prisma AIRS - AI Runtime Security
Integrate with Palo Alto Networks Prisma AIRs for AI security capabilities including runtime scanning, red teaming, AI supply chain security, and DLP configuration.
Cloud Security · Palo Alto Networks - Prisma AIRs AI Security
Details
| ID | Palo Alto Networks Prisma AIRS - AI Runtime Security |
|---|---|
| Provider | Palo Alto Networks |
| Category | Cloud Security |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.14.12343672 |
README
Integrate with Palo Alto Networks Prisma AIRs for AI security capabilities including runtime scanning, red teaming, AI supply chain security, and DLP configuration.
This integration was integrated and tested with Palo Alto Networks Prisma AIRS - AI Runtime Security.
Configure Palo Alto Networks Prisma AIRS - AI Runtime Security in Cortex
| Parameter | Description | Required |
|---|---|---|
| Server URL | True | |
| API Client ID | True | |
| API Client Secret | True | |
| Runtime API Key | Runtime API Key for Prisma AIRs Scanner API. This is used exclusively for runtime scanning operations and is different from the OAuth2 Client ID/Secret used for management operations. | True |
| Tenant Services Group ID | Default Tenant Services Group ID to use for API calls. Example: 1234567890. | True |
| Scanner API Base URL | Scanner API base URL for runtime scanning operations. Default is US region. For other regions: EU: https://service-de.api.aisecurity.paloaltonetworks.com, IN: https://service-in.api.aisecurity.paloaltonetworks.com, SG: https://service-sg.api.aisecurity.paloaltonetworks.com. This must match the region selected during deployment profile creation. | False |
| DLP API Base URL | DLP API base URL for DLP management operations (dictionaries, patterns, filtering profiles). Default is the global DLP endpoint. Change only if using a regional or custom DLP endpoint. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
prisma-airs-runtime-scan
Scan a single prompt against a security profile for AI security threats.
Base Command
prisma-airs-runtime-scan
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_name | The name of the security profile to use for scanning. | Required |
| prompt | The prompt text to scan. | Required |
| response | The optional response text to scan alongside the prompt. | Optional |
| tr_id | The unique identifier string for correlating the prompt and response transactions. Returned in the scan response. | Optional |
| session_id | The unique identifier string for tracking sessions. Returned in the scan response. | Optional |
| app_name | The AI application requesting the content scan. | Optional |
| app_user | The end user using the AI application. | Optional |
| ai_model | The AI model serving the AI application. | Optional |
| user_ip | The end user IP address using the AI application. | Optional |
| agent_id | The agent identifier for metadata tracking. | Optional |
| agent_version | The agent version for metadata tracking. | Optional |
| agent_arn | The agent ARN for metadata tracking. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.RuntimeScan.scan_id | String | The unique scan identifier. |
| PrismaAIRs.RuntimeScan.report_id | String | The report identifier for this scan. |
| PrismaAIRs.RuntimeScan.tr_id | String | The transaction ID passed in the request and returned in the response. |
| PrismaAIRs.RuntimeScan.session_id | String | The session ID passed in the request and returned in the response. |
| PrismaAIRs.RuntimeScan.prompt | String | The scanned prompt text. |
| PrismaAIRs.RuntimeScan.response | String | The scanned response text. |
| PrismaAIRs.RuntimeScan.action | String | The action taken (allow or block). |
| PrismaAIRs.RuntimeScan.category | String | The threat category (benign, malicious, etc.). |
| PrismaAIRs.RuntimeScan.detected | Boolean | Whether any threat was detected across prompt or response. |
| PrismaAIRs.RuntimeScan.prompt_detected | Unknown | The object containing all detection types for the prompt (e.g., injection, dlp, toxic_content, topic_violation, url_cats, malicious_code, agent). |
| PrismaAIRs.RuntimeScan.response_detected | Unknown | The object containing all detection types for the response (e.g., dlp, toxic_content, topic_violation, url_cats, malicious_code, agent, db_security, ungrounded). |
| PrismaAIRs.RuntimeScan.profile_id | String | The profile ID used for scanning. |
| PrismaAIRs.RuntimeScan.profile_name | String | The profile name used for scanning. |
| PrismaAIRs.RuntimeScan.source | String | The source of the scan request. |
| PrismaAIRs.RuntimeScan.timeout | Boolean | Whether any detection service timed out. |
| PrismaAIRs.RuntimeScan.error | Boolean | Whether any detection service encountered an error. |
| PrismaAIRs.RuntimeScan.errors | Unknown | The list of detection service errors or timeouts. |
Command example
!prisma-airs-runtime-scan profile_name="readme-example-profile" prompt="do you want to play a game mr wolf"
Context Example
{
"action": "allow",
"category": "benign",
"detected": false,
"profile_id": "a0e6e9b0-edda-44cc-b1ed-37407ab7098c",
"profile_name": "readme-example-profile",
"prompt": "do you want to play a game mr wolf",
"prompt_detected": {
"injection": false,
"url_cats": false
},
"report_id": "R0522f0db-d150-44c4-a919-f80fdd70679d",
"response": null,
"response_detected": {},
"scan_id": "0522f0db-d150-44c4-a919-f80fdd70679d",
"session_id": "pan_dbf07dbe-5b19-440d-a715-2a3f39949479",
"source": "AI-Runtime-API",
"tr_id": "pan_dbf07dbe-5b19-440d-a715-2a3f39949479"
}
Human Readable Output
Prisma AIRs Runtime Scan Results
Scan Summary
Scan ID Report ID Profile Action Category Detected 0522f0db-d150-44c4-a919-f80fdd70679d R0522f0db-d150-44c4-a919-f80fdd70679d readme-example-profile ALLOW benign No Metadata
Field Value Transaction ID pan_dbf07dbe-5b19-440d-a715-2a3f39949479 Session ID pan_dbf07dbe-5b19-440d-a715-2a3f39949479 Scanned Content
Type Content Threats Detected Prompt do you want to play a game mr wolf No Prompt Detections
Detection Type Detected Injection No Url Cats No
prisma-airs-runtime-api-keys-list
List all Runtime API Keys configured in Prisma AIRs.
Base Command
prisma-airs-runtime-api-keys-list
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of API keys to return. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.ApiKey.id | String | The API Key ID (UUID). |
| PrismaAIRs.ApiKey.name | String | The API Key name. |
| PrismaAIRs.ApiKey.last8 | String | The last 8 characters of the API key (for identification). |
| PrismaAIRs.ApiKey.created_at | Date | The API Key creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.ApiKey.expires_at | Date | The API Key expiration timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.ApiKey.revoked | Boolean | Whether the API key has been revoked. |
Command example
!prisma-airs-runtime-api-keys-list
Context Example
[
{
"created_at": null,
"expires_at": "2026-09-29T23:59:59Z",
"id": "11111111-1111-1111-1111-111111111111",
"last8": "UOaZEClq",
"name": "example-api-key-1",
"revoked": false
},
{
"created_at": null,
"expires_at": "2026-09-29T23:59:59Z",
"id": "22222222-2222-2222-2222-222222222222",
"last8": "31CQgQ3p",
"name": "example-api-key-2",
"revoked": false
}
]
Human Readable Output
Prisma AIRs Runtime API Keys
Id Name Last8 Created At Expires At Revoked 11111111-1111-1111-1111-111111111111 example-api-key-1 UOaZEClq 2026-09-29T23:59:59Z false 22222222-2222-2222-2222-222222222222 example-api-key-2
prisma-airs-runtime-api-keys-create
Create a new Runtime API Key. WARNING - The full API key secret is only shown once during creation. Save it securely.
Base Command
prisma-airs-runtime-api-keys-create
Input
| Argument Name | Description | Required |
|---|---|---|
| api_key_name | The name for the new API key. | Required |
| auth_code | The deployment profile auth code (obtained from deployment profile). | Required |
| cust_app | The customer application name using this API key. | Required |
| rotation_time_interval | The rotation time interval (number). | Required |
| rotation_time_unit | The rotation time unit. Possible values are: hours, days, months. | Required |
| created_by | The email of the user creating the API key. | Required |
| dp_name | The deployment profile name (optional). | Optional |
| cust_env | The customer environment (e.g., production, staging). The underlying customer app record mandates an environment value; omitting it causes the API to return “Error inserting/updating customer app record”, so this argument is required. | Required |
| cust_cloud_provider | The customer cloud provider (e.g., aws, gcp, azure). The underlying customer app record mandates a cloud provider value; omitting it causes the API to return “Error inserting/updating customer app record”, so this argument is required. | Required |
| cust_ai_agent_framework | The customer AI agent framework (optional). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.ApiKeyCreate.id | String | The created API Key ID (UUID). |
| PrismaAIRs.ApiKeyCreate.name | String | The API Key name. |
| PrismaAIRs.ApiKeyCreate.api_key | String | The FULL API KEY SECRET - Only shown once! Save this securely. |
| PrismaAIRs.ApiKeyCreate.last8 | String | The last 8 characters of the API key. |
| PrismaAIRs.ApiKeyCreate.auth_code | String | The auth code associated with the key. |
| PrismaAIRs.ApiKeyCreate.expires_at | Date | The API Key expiration timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.ApiKeyCreate.revoked | Boolean | Whether the API key has been revoked. |
| PrismaAIRs.ApiKeyCreate.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.ApiKeyCreate.created_by | String | The user who created the key. |
| PrismaAIRs.ApiKeyCreate.cust_app | String | The customer application name. |
prisma-airs-runtime-api-keys-regenerate
Regenerate an existing Runtime API Key. WARNING - This creates a NEW key with a NEW UUID and invalidates the old key. The new secret is only shown once.
Base Command
prisma-airs-runtime-api-keys-regenerate
Input
| Argument Name | Description | Required |
|---|---|---|
| api_key_id | The UUID of the API key to regenerate. | Required |
| rotation_time_interval | The new rotation time interval (number). | Required |
| rotation_time_unit | The new rotation time unit. Possible values are: hours, days, months. | Required |
| updated_by | The email of the user performing regeneration (optional). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.ApiKeyRegenerate.id | String | The NEW API Key ID (UUID) - different from the old one. |
| PrismaAIRs.ApiKeyRegenerate.name | String | The API Key name (same as before). |
| PrismaAIRs.ApiKeyRegenerate.api_key | String | The NEW FULL API KEY SECRET - Only shown once! The old key is now invalid. |
| PrismaAIRs.ApiKeyRegenerate.last8 | String | The last 8 characters of the new API key. |
| PrismaAIRs.ApiKeyRegenerate.auth_code | String | The auth code associated with the key. |
| PrismaAIRs.ApiKeyRegenerate.expires_at | Date | The new expiration timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.ApiKeyRegenerate.revoked | Boolean | Whether the API key has been revoked. |
| PrismaAIRs.ApiKeyRegenerate.updated_at | Date | The update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.ApiKeyRegenerate.updated_by | String | The user who regenerated the key. |
| PrismaAIRs.ApiKeyRegenerate.cust_app | String | The customer application name. |
prisma-airs-runtime-api-keys-delete
Delete a Runtime API Key by name. WARNING - This action cannot be undone and immediately revokes access for all applications using this key.
Base Command
prisma-airs-runtime-api-keys-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| api_key_name | The name of the API key to delete. | Required |
| updated_by | The email of the user performing the deletion. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.ApiKeyDeleted.api_key_name | String | The name of the deleted API key. |
| PrismaAIRs.ApiKeyDeleted.deleted_by | String | The email of the user who deleted the key. |
| PrismaAIRs.ApiKeyDeleted.message | String | The deletion confirmation message. |
| PrismaAIRs.ApiKeyDeleted.deleted | Boolean | The boolean indicating successful deletion. |
prisma-airs-runtime-profiles-list
List all runtime security profiles.
Base Command
prisma-airs-runtime-profiles-list
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of profiles to return. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.SecurityProfile.id | String | The profile ID (UUID). |
| PrismaAIRs.SecurityProfile.name | String | The profile name. |
| PrismaAIRs.SecurityProfile.revision | Number | The profile revision number. |
| PrismaAIRs.SecurityProfile.active | Boolean | Whether the profile is active. |
| PrismaAIRs.SecurityProfile.created_by | String | The user who created the profile. |
| PrismaAIRs.SecurityProfile.updated_by | String | The user who last updated the profile. |
| PrismaAIRs.SecurityProfile.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.SecurityProfile.tsg_id | String | The tenant Service Group ID. |
Command example
!prisma-airs-runtime-profiles-list
Context Example
[
{
"active": true,
"created_by": "test@test.com",
"id": "c921be1a-51ec-4393-9b33-548da58e7906",
"last_modified_ts": "2026-05-21T13:18:41Z",
"name": "example-target-2",
"revision": 2,
"tsg_id": "1234567",
"updated_by": "test@test.com"
},
{
"active": true,
"created_by": "test@test.com",
"id": "535cbb48-aad4-43be-a27e-d6ad4be7bbe7",
"last_modified_ts": "2026-05-12T20:22:49Z",
"name": "example-target-1",
"revision": 3,
"tsg_id": "1234567",
"updated_by": "test@test.com"
}
]
Human Readable Output
Prisma AIRs Security Profiles
Id Name Revision Active Created By Updated By Last Modified Ts c921be1a-51ec-4393-9b33-548da58e7906 example-target-2 2 true test@test.com test@test.com 2026-05-21T13:18:41Z 535cbb48-aad4-43be-a27e-d6ad4be7bbe7 example-target-1 3 true test@test.com test@test.com 2026-05-12T20:22:49Z
prisma-airs-runtime-profiles-get
Get a specific security profile by ID or name. Returns the highest-revision profile if filtering by name.
Base Command
prisma-airs-runtime-profiles-get
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The profile UUID (either profile_id or profile_name is required). | Optional |
| profile_name | The profile name (returns highest-revision match if multiple exist). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.SecurityProfileGet.id | String | The profile ID (UUID). |
| PrismaAIRs.SecurityProfileGet.name | String | The profile name. |
| PrismaAIRs.SecurityProfileGet.revision | Number | The profile revision number. |
| PrismaAIRs.SecurityProfileGet.active | Boolean | Whether the profile is active. |
| PrismaAIRs.SecurityProfileGet.policy | Unknown | The full policy configuration (AI security profiles and DLP data profiles). |
| PrismaAIRs.SecurityProfileGet.created_by | String | The user who created the profile. |
| PrismaAIRs.SecurityProfileGet.updated_by | String | The user who last updated the profile. |
| PrismaAIRs.SecurityProfileGet.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.SecurityProfileGet.tsg_id | String | The tenant Service Group ID. |
| PrismaAIRs.SecurityProfileGet.csp_id | String | The cloud Service Provider ID. |
Command example
!prisma-airs-runtime-profiles-get profile_id=${PrismaAIRs.SecurityProfileCreate.id}
Context Example
{
"active": true,
"created_by": "test@test.com",
"csp_id": "XXXXXX",
"id": "2f8b3f67-3596-48f6-88cd-957e10508d95",
"last_modified_ts": "2026-06-26T13:50:21Z",
"name": "readme-example-profile",
"policy": {
"ai-security-profiles": [
{
"model-configuration": {
"app-protection": {
"default-url-category": {
"member": [
"malicious"
]
},
"url-detected-action": "block"
},
"data-protection": {
"data-leak-detection": {
"action": "",
"mask-data-inline": false,
"member": null
},
"database-security": null
},
"latency": {
"inline-timeout-action": "block",
"max-inline-latency": 5
},
"mask-data-in-storage": false,
"model-protection": [
{
"action": "block",
"name": "prompt-injection"
}
]
},
"model-type": "default"
}
],
"dlp-data-profiles": []
},
"revision": 1,
"tsg_id": "1234567",
"updated_by": "test@test.com"
}
Human Readable Output
Security Profile: readme-example-profile
Id Name Revision Active Created By Updated By Last Modified Ts 2f8b3f67-3596-48f6-88cd-957e10508d95 readme-example-profile 1 true test@test.com test@test.com 2026-06-26T13:50:21Z Policy:
- AI Security Profiles: 1
- DLP Data Profiles: 0
prisma-airs-runtime-profiles-create
Create a new security profile with custom policy configuration.
Base Command
prisma-airs-runtime-profiles-create
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_name | The name for the new security profile (must be unique). | Required |
| active | Whether the profile should be active. Possible values are: true, false. Default is true. | Optional |
| policy | The policy configuration as JSON string. Structure - ai-security-profiles array and dlp-data-profiles array. If omitted, creates empty policy. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.SecurityProfileCreate.id | String | The profile ID (UUID). |
| PrismaAIRs.SecurityProfileCreate.name | String | The profile name. |
| PrismaAIRs.SecurityProfileCreate.revision | Number | The profile revision number (starts at 1). |
| PrismaAIRs.SecurityProfileCreate.active | Boolean | Whether the profile is active. |
| PrismaAIRs.SecurityProfileCreate.policy | Unknown | The full policy configuration. |
| PrismaAIRs.SecurityProfileCreate.created_by | String | The user who created the profile. |
| PrismaAIRs.SecurityProfileCreate.updated_by | String | The user who last updated the profile. |
| PrismaAIRs.SecurityProfileCreate.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.SecurityProfileCreate.tsg_id | String | The tenant Service Group ID. |
| PrismaAIRs.SecurityProfileCreate.csp_id | String | The cloud Service Provider ID. |
Command example
!prisma-airs-runtime-profiles-create profile_name="readme-example-profile" policy=`{"ai-security-profiles":[{"model-type":"default","model-configuration":{"model-protection":[{"name":"prompt-injection","action":"block"}],"app-protection":{"default-url-category":{"member":["malicious"]},"url-detected-action":"block"},"data-protection":{"data-leak-detection":{"action":"","mask-data-inline":false,"member":null},"database-security":null},"latency":{"inline-timeout-action":"block","max-inline-latency":5},"mask-data-in-storage":false}}],"dlp-data-profiles":[]}`
Context Example
{
"active": true,
"created_by": "test@test.com",
"csp_id": "XXXXXX",
"id": "2f8b3f67-3596-48f6-88cd-957e10508d95",
"last_modified_ts": "2026-06-26T13:50:21Z",
"name": "readme-example-profile",
"policy": {
"ai-security-profiles": [
{
"model-configuration": {
"app-protection": {
"default-url-category": {
"member": [
"malicious"
]
},
"url-detected-action": "block"
},
"data-protection": {
"data-leak-detection": {
"action": "",
"mask-data-inline": false,
"member": null
},
"database-security": null
},
"latency": {
"inline-timeout-action": "block",
"max-inline-latency": 5
},
"mask-data-in-storage": false,
"model-protection": [
{
"action": "block",
"name": "prompt-injection"
}
]
},
"model-type": "default"
}
],
"dlp-data-profiles": []
},
"revision": 1,
"tsg_id": "1234567",
"updated_by": "test@test.com"
}
Human Readable Output
Security Profile Created
Id Name Revision Active Created By 2f8b3f67-3596-48f6-88cd-957e10508d95 readme-example-profile 1 true test@test.com Policy:
- AI Security Profiles: 1
- DLP Data Profiles: 0
prisma-airs-runtime-profiles-update
Update an existing security profile. WARNING - Modifying profile configuration can break scanning if misconfigured.
Base Command
prisma-airs-runtime-profiles-update
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The profile UUID to update. | Required |
| profile_name | The profile name (can be changed or kept the same). | Required |
| active | Whether the profile should be active. Possible values are: true, false. | Optional |
| policy | The updated policy configuration as JSON string. If omitted, policy remains unchanged. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.SecurityProfileUpdate.id | String | The profile ID (UUID). |
| PrismaAIRs.SecurityProfileUpdate.name | String | The profile name. |
| PrismaAIRs.SecurityProfileUpdate.revision | Number | The profile revision number (incremented after update). |
| PrismaAIRs.SecurityProfileUpdate.active | Boolean | Whether the profile is active. |
| PrismaAIRs.SecurityProfileUpdate.policy | Unknown | The full policy configuration. |
| PrismaAIRs.SecurityProfileUpdate.created_by | String | The user who created the profile. |
| PrismaAIRs.SecurityProfileUpdate.updated_by | String | The user who last updated the profile. |
| PrismaAIRs.SecurityProfileUpdate.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.SecurityProfileUpdate.tsg_id | String | The tenant Service Group ID. |
| PrismaAIRs.SecurityProfileUpdate.csp_id | String | The cloud Service Provider ID. |
Command example
!prisma-airs-runtime-profiles-update profile_id=${PrismaAIRs.SecurityProfileCreate.id} profile_name="readme-example-profile" active="true" policy=`{"ai-security-profiles":[{"model-type":"default","model-configuration":{"model-protection":[{"name":"prompt-injection","action":"block"}],"app-protection":{"default-url-category":{"member":["malicious"]},"url-detected-action":"block"},"data-protection":{"data-leak-detection":{"action":"","mask-data-inline":false,"member":null},"database-security":null},"latency":{"inline-timeout-action":"block","max-inline-latency":5},"mask-data-in-storage":false}}],"dlp-data-profiles":[]}`
Context Example
{
"active": true,
"created_by": "test@test.com",
"csp_id": "XXXXXX",
"id": "a0e6e9b0-edda-44cc-b1ed-37407ab7098c",
"last_modified_ts": "2026-06-26T13:50:26Z",
"name": "readme-example-profile",
"policy": {
"ai-security-profiles": [
{
"model-configuration": {
"app-protection": {
"default-url-category": {
"member": [
"malicious"
]
},
"url-detected-action": "block"
},
"data-protection": {
"data-leak-detection": {
"action": "",
"mask-data-inline": false,
"member": null
},
"database-security": null
},
"latency": {
"inline-timeout-action": "block",
"max-inline-latency": 5
},
"mask-data-in-storage": false,
"model-protection": [
{
"action": "block",
"name": "prompt-injection"
}
]
},
"model-type": "default"
}
],
"dlp-data-profiles": []
},
"revision": 2,
"tsg_id": "1234567",
"updated_by": "none"
}
Human Readable Output
Security Profile Updated
Id Name Revision Active Updated By Last Modified Ts a0e6e9b0-edda-44cc-b1ed-37407ab7098c readme-example-profile 2 true none 2026-06-26T13:50:26Z Policy:
- AI Security Profiles: 1
- DLP Data Profiles: 0
prisma-airs-runtime-profiles-delete
Delete a security profile. WARNING - This action cannot be undone and permanently removes the profile.
Base Command
prisma-airs-runtime-profiles-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The profile UUID to delete. | Required |
| force | Whether to force-delete the profile, bypassing safety checks. Requires updated_by. Possible values are: true, false. Default is false. | Optional |
| updated_by | The email of the user performing the deletion. Required when force is true. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.SecurityProfileDeleted.profile_id | String | The deleted profile ID. |
| PrismaAIRs.SecurityProfileDeleted.message | String | The deletion confirmation message. |
| PrismaAIRs.SecurityProfileDeleted.deleted | Boolean | The boolean indicating successful deletion. |
| PrismaAIRs.SecurityProfileDeleted.force | Boolean | Whether the profile was force-deleted. |
Command example
!prisma-airs-runtime-profiles-delete profile_id=${PrismaAIRs.SecurityProfileUpdate.id}
Context Example
[
{
"deleted": true,
"message": "successfully deleted profileId: a0e6e9b0-edda-44cc-b1ed-37407ab7098c",
"profile_id": "a0e6e9b0-edda-44cc-b1ed-37407ab7098c"
},
{
"deleted": true,
"message": "successfully deleted profileId: 2f8b3f67-3596-48f6-88cd-957e10508d95",
"profile_id": "2f8b3f67-3596-48f6-88cd-957e10508d95"
}
]
Human Readable Output
Security Profile Deleted
Profile Id Message Deleted Force a0e6e9b0-edda-44cc-b1ed-37407ab7098c successfully deleted profileId: a0e6e9b0-edda-44cc-b1ed-37407ab7098c true false ⚠️ WARNING: This action cannot be undone. The security profile has been permanently deleted.
Command example (force-delete)
!prisma-airs-runtime-profiles-delete profile_id="96f9d6c1-1613-40db-bcca-74aeb3ff6ba1" force="true" updated_by="admin@example.com"
Human Readable Output (force-delete)
Security Profile Force-Deleted
Profile Id Message Deleted Force 96f9d6c1-1613-40db-bcca-74aeb3ff6ba1 successfully force deleted profileId: 96f9d6c1-1613-40db-bcca-74aeb3ff6ba1 true true ⚠️ WARNING: This action cannot be undone. The security profile has been permanently deleted.
prisma-airs-runtime-customer-apps-list
List all customer applications.
Base Command
prisma-airs-runtime-customer-apps-list
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of customer apps to return. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.CustomerApp.id | String | The customer App ID. |
| PrismaAIRs.CustomerApp.name | String | The customer App name. |
| PrismaAIRs.CustomerApp.model_name | String | The model name used by the app. |
| PrismaAIRs.CustomerApp.cloud_provider | String | The cloud provider. |
| PrismaAIRs.CustomerApp.environment | String | The environment (prod, staging, dev). |
| PrismaAIRs.CustomerApp.ai_agent_framework | String | The AI agent framework used. |
| PrismaAIRs.CustomerApp.tsg_id | String | The tenant Service Group ID. |
Command example
!prisma-airs-runtime-customer-apps-list
Context Example
[
{
"ai_agent_framework": "",
"cloud_provider": "gcp",
"environment": "prod",
"id": "85ddfdbb-7dfe-4910-91c4-699fc9944927",
"model_name": "default",
"name": "example-app-1",
"tsg_id": "1234567"
},
{
"ai_agent_framework": "",
"cloud_provider": "gcp",
"environment": "prod",
"id": "350b61e7-3cdf-45d3-bb0e-457f92f5c0b0",
"model_name": "default",
"name": "example-app-2",
"tsg_id": "1234567"
}
]
Human Readable Output
Prisma AIRs Customer Applications
Id Name Model Name Cloud Provider Environment Ai Agent Framework 85ddfdbb-7dfe-4910-91c4-699fc9944927 example-app-1 default gcp prod 350b61e7-3cdf-45d3-bb0e-457f92f5c0b0 example-app-2 default gcp prod
prisma-airs-runtime-customer-apps-get
Get customer application details by name.
Base Command
prisma-airs-runtime-customer-apps-get
Input
| Argument Name | Description | Required |
|---|---|---|
| app_name | The name of the customer application to retrieve. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.CustomerAppGet.id | String | The customer App ID (UUID). |
| PrismaAIRs.CustomerAppGet.name | String | The customer App name. |
| PrismaAIRs.CustomerAppGet.model_name | String | The model name used by the app. |
| PrismaAIRs.CustomerAppGet.cloud_provider | String | The cloud provider (aws, azure, gcp, other). |
| PrismaAIRs.CustomerAppGet.environment | String | The environment (prod, staging, dev). |
| PrismaAIRs.CustomerAppGet.ai_agent_framework | String | The AI agent framework used. |
| PrismaAIRs.CustomerAppGet.tsg_id | String | The tenant Service Group ID. |
| PrismaAIRs.CustomerAppGet.status | String | The customer App status. |
| PrismaAIRs.CustomerAppGet.created_by | String | The email of user who created the app. |
| PrismaAIRs.CustomerAppGet.updated_by | String | The email of user who last updated the app. |
prisma-airs-runtime-customer-apps-update
Update a customer application configuration.
Base Command
prisma-airs-runtime-customer-apps-update
Input
| Argument Name | Description | Required |
|---|---|---|
| customer_app_id | The UUID of the customer application to update. | Required |
| app_name | The application name. | Required |
| cloud_provider | The cloud provider. Possible values are: aws, azure, gcp, other. | Required |
| environment | The environment. Possible values are: prod, staging, dev. | Required |
| tsg_id | The tenant Service Group ID. If not provided, the configured TSG ID is used. | Optional |
| model_name | The model name used by the application. | Optional |
| ai_agent_framework | The AI agent framework used by the application. | Optional |
| updated_by | The email of user performing the update. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.CustomerAppUpdate.id | String | The customer App ID (UUID). |
| PrismaAIRs.CustomerAppUpdate.name | String | The customer App name. |
| PrismaAIRs.CustomerAppUpdate.model_name | String | The model name used by the app. |
| PrismaAIRs.CustomerAppUpdate.cloud_provider | String | The cloud provider (aws, azure, gcp, other). |
| PrismaAIRs.CustomerAppUpdate.environment | String | The environment (prod, staging, dev). |
| PrismaAIRs.CustomerAppUpdate.ai_agent_framework | String | The AI agent framework used. |
| PrismaAIRs.CustomerAppUpdate.tsg_id | String | The tenant Service Group ID. |
| PrismaAIRs.CustomerAppUpdate.status | String | The customer App status. |
| PrismaAIRs.CustomerAppUpdate.created_by | String | The email of user who created the app. |
| PrismaAIRs.CustomerAppUpdate.updated_by | String | The email of user who last updated the app. |
prisma-airs-runtime-customer-apps-consumption
Get per-application token consumption and session statistics over the requested time window.
Base Command
prisma-airs-runtime-customer-apps-consumption
Input
| Argument Name | Description | Required |
|---|---|---|
| app_id | The customer Application UUID (from customer-apps-list or customer-apps-get). | Required |
| app_name | The application display name (literal metadata.app_name value from scan payloads). | Required |
| time_interval | The look-back window in days (7, 30, or 60). Possible values are: 7, 30, 60. Default is 30. | Optional |
| time_unit | The time unit (only ‘days’ is supported by API). Default is days. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.CustomerAppConsumption.id | String | The customer App ID. |
| PrismaAIRs.CustomerAppConsumption.name | String | The application name. |
| PrismaAIRs.CustomerAppConsumption.cloud | String | The cloud provider. |
| PrismaAIRs.CustomerAppConsumption.source | String | The source (api, sdk, etc.). |
| PrismaAIRs.CustomerAppConsumption.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.CustomerAppConsumption.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.CustomerAppConsumption.profiles | Unknown | The attached security profiles. |
| PrismaAIRs.CustomerAppConsumption.average_daily_tokens | Number | The average daily token consumption. |
| PrismaAIRs.CustomerAppConsumption.average_daily_tokens_scale | String | The scale for daily tokens (K, M, etc.). |
| PrismaAIRs.CustomerAppConsumption.monthly_total_tokens | Number | The monthly total token consumption. |
| PrismaAIRs.CustomerAppConsumption.monthly_total_tokens_scale | String | The scale for monthly tokens (K, M, etc.). |
| PrismaAIRs.CustomerAppConsumption.sessions_total | Number | The total sessions in time window. |
| PrismaAIRs.CustomerAppConsumption.sessions_violating | Number | The number of violating sessions. |
| PrismaAIRs.CustomerAppConsumption.last_session_id | String | The last session ID. |
| PrismaAIRs.CustomerAppConsumption.most_recent_session_time | Date | The most recent session timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.CustomerAppConsumption.violations_critical | Number | The critical violations count. |
| PrismaAIRs.CustomerAppConsumption.violations_high | Number | The high violations count. |
| PrismaAIRs.CustomerAppConsumption.violations_medium | Number | The medium violations count. |
| PrismaAIRs.CustomerAppConsumption.violations_low | Number | The low violations count. |
| PrismaAIRs.CustomerAppConsumption.violations_total | Number | The total violations count. |
prisma-airs-runtime-customer-apps-violations
Get per-detector violation severity breakdown for an application over the requested time window.
Base Command
prisma-airs-runtime-customer-apps-violations
Input
| Argument Name | Description | Required |
|---|---|---|
| app_id | The customer Application UUID (from customer-apps-list or customer-apps-get). | Required |
| app_name | The application display name (literal metadata.app_name value from scan payloads). | Required |
| time_interval | The look-back window in days (7, 30, or 60). Possible values are: 7, 30, 60. Default is 30. | Optional |
| time_unit | The time unit (only ‘days’ is supported by API). Default is days. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.CustomerAppViolations.app_id | String | The customer App ID. |
| PrismaAIRs.CustomerAppViolations.app_name | String | The application name. |
| PrismaAIRs.CustomerAppViolations.total_violating | Number | The total number of violating sessions. |
| PrismaAIRs.CustomerAppViolations.time_interval | Number | The time window in days. |
| PrismaAIRs.CustomerAppViolations.time_unit | String | The time unit used. |
| PrismaAIRs.CustomerAppViolations.detectors | Unknown | The per-detector violation breakdown array. |
| PrismaAIRs.CustomerAppViolations.detectors.detection_type | String | The detector type (agent_security, dbs, dlp, malicious_code, pi, source_code, tc, topic_guardrails, uf, contextual_grounding). |
| PrismaAIRs.CustomerAppViolations.detectors.critical | Number | The critical violations count for this detector. |
| PrismaAIRs.CustomerAppViolations.detectors.high | Number | The high violations count for this detector. |
| PrismaAIRs.CustomerAppViolations.detectors.medium | Number | The medium violations count for this detector. |
| PrismaAIRs.CustomerAppViolations.detectors.low | Number | The low violations count for this detector. |
| PrismaAIRs.CustomerAppViolations.detectors.total | Number | The total violations count for this detector. |
prisma-airs-runtime-customer-apps-delete
Delete a customer application and all associated API keys. WARNING - This action cannot be undone and immediately revokes all API keys for this application.
Base Command
prisma-airs-runtime-customer-apps-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| app_name | The name of the customer application to delete. | Required |
| updated_by | The email of the user performing the deletion. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.CustomerAppDeleted.app_name | String | The name of the deleted customer application. |
| PrismaAIRs.CustomerAppDeleted.deleted_by | String | The email of the user who deleted the application. |
| PrismaAIRs.CustomerAppDeleted.message | String | The deletion confirmation message. |
| PrismaAIRs.CustomerAppDeleted.deleted | Boolean | The boolean indicating successful deletion. |
prisma-airs-runtime-deployment-profiles-list
List all deployment profiles.
Base Command
prisma-airs-runtime-deployment-profiles-list
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of deployment profiles to return. Default is 50. | Optional |
| unactivated | Whether to show only unactivated profiles. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DeploymentProfile.name | String | The deployment Profile name. |
| PrismaAIRs.DeploymentProfile.auth_code | String | The authentication code. |
| PrismaAIRs.DeploymentProfile.tsg_id | String | The tenant Service Group ID. |
| PrismaAIRs.DeploymentProfile.status | String | The profile status. |
| PrismaAIRs.DeploymentProfile.expiration_date | Date | The expiration date in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DeploymentProfile.ave_text_records | Number | The average text records. |
Command example
!prisma-airs-runtime-deployment-profiles-list
Context Example
{
"auth_code": "DXXXXXX",
"ave_text_records": null,
"expiration_date": "2026-09-29 23:59:59 +0000 UTC",
"name": "example-deployment-profile",
"status": "activated",
"tsg_id": "1234567"
}
Human Readable Output
Prisma AIRs Deployment Profiles
Name Auth Code Status Expiration Date Ave Text Records example-deployment-profile DXXXXXX activated 2026-09-29 23:59:59 +0000 UTC
prisma-airs-runtime-dlp-profiles-list
List all DLP data profiles (v2 API).
Base Command
prisma-airs-runtime-dlp-profiles-list
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The page number for pagination. Default is 0. | Optional |
| size | The number of results per page. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpProfile.id | String | The DLP Profile ID. |
| PrismaAIRs.DlpProfile.name | String | The DLP Profile name. |
| PrismaAIRs.DlpProfile.description | String | The DLP Profile description. |
| PrismaAIRs.DlpProfile.tenant_id | String | The tenant ID. |
| PrismaAIRs.DlpProfile.type | String | The profile type (custom or predefined). |
| PrismaAIRs.DlpProfile.profile_status | String | The profile status (active, disabled, deleted). |
| PrismaAIRs.DlpProfile.profile_type | String | The profile type (basic or advanced). |
| PrismaAIRs.DlpProfile.is_granular_data_profile | Boolean | Whether this is a granular data profile. |
| PrismaAIRs.DlpProfile.is_parent_managed | Boolean | Whether the profile is parent-managed. |
| PrismaAIRs.DlpProfile.version | Number | The DLP Profile version. |
| PrismaAIRs.DlpProfile.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfile.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfile.created_by | String | The user who created the profile. |
| PrismaAIRs.DlpProfile.updated_by | String | The user who last updated the profile. |
Command example
!prisma-airs-runtime-dlp-profiles-list
Context Example
[
{
"created_at": 1782433839552,
"created_by": "api",
"description": "CC AND Passport-CA, any matches, low confidence",
"id": "11995054",
"is_granular_data_profile": false,
"is_parent_managed": false,
"name": "test-dlp-profile",
"profile_status": "active",
"profile_type": "advanced",
"tenant_id": "1234567890123456789",
"type": "custom",
"updated_at": 1782433839552,
"updated_by": "api",
"version": 1
},
{
"created_at": 1778613252311,
"created_by": "Strata Cloud Manager",
"description": null,
"id": "11995053",
"is_granular_data_profile": false,
"is_parent_managed": false,
"name": "Custom-MCP-Tools_Call",
"profile_status": "active",
"profile_type": "advanced",
"tenant_id": "1234567890123456789",
"type": "custom",
"updated_at": 1778618115601,
"updated_by": "Strata Cloud Manager",
"version": 11
}
]
Human Readable Output
Prisma AIRs DLP Data Profiles (Page 1/1, 36 of 36)
Id Name Type Profile Status Profile Type Version 11995054 test-dlp-profile custom active advanced 1 11995053 Custom-MCP-Tools_Call custom active advanced 11
prisma-airs-runtime-dlp-profiles-get
Get a single DLP data profile by ID.
Base Command
prisma-airs-runtime-dlp-profiles-get
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The ID of the DLP data profile to retrieve. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpProfileGet.id | String | The DLP Profile ID. |
| PrismaAIRs.DlpProfileGet.name | String | The DLP Profile name. |
| PrismaAIRs.DlpProfileGet.description | String | The DLP Profile description. |
| PrismaAIRs.DlpProfileGet.tenant_id | String | The tenant ID. |
| PrismaAIRs.DlpProfileGet.type | String | The profile type (custom or predefined). |
| PrismaAIRs.DlpProfileGet.profile_status | String | The profile status (active, disabled, deleted). |
| PrismaAIRs.DlpProfileGet.profile_type | String | The profile type (basic or advanced). |
| PrismaAIRs.DlpProfileGet.is_granular_data_profile | Boolean | Whether this is a granular data profile. |
| PrismaAIRs.DlpProfileGet.is_parent_managed | Boolean | Whether the profile is parent-managed. |
| PrismaAIRs.DlpProfileGet.version | Number | The DLP Profile version. |
| PrismaAIRs.DlpProfileGet.detection_rules | Unknown | The detection rules array (expression_tree or multi_profile). |
| PrismaAIRs.DlpProfileGet.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfileGet.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfileGet.created_by | String | The user who created the profile. |
| PrismaAIRs.DlpProfileGet.updated_by | String | The user who last updated the profile. |
prisma-airs-runtime-dlp-profiles-create
Create a new DLP data profile with detection rules.
Base Command
prisma-airs-runtime-dlp-profiles-create
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The profile name (1-64 characters). | Required |
| detection_rules | The detection rules as JSON array. Each rule must have rule_type (expression_tree or multi_profile) and corresponding structure. | Required |
| description | The profile description. | Optional |
| is_granular_data_profile | Whether this is a granular data profile. Possible values are: true, false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpProfileCreate.id | String | The DLP Profile ID. |
| PrismaAIRs.DlpProfileCreate.name | String | The DLP Profile name. |
| PrismaAIRs.DlpProfileCreate.description | String | The DLP Profile description. |
| PrismaAIRs.DlpProfileCreate.type | String | The profile type. |
| PrismaAIRs.DlpProfileCreate.profile_status | String | The profile status. |
| PrismaAIRs.DlpProfileCreate.profile_type | String | The profile type (basic or advanced). |
| PrismaAIRs.DlpProfileCreate.is_granular_data_profile | Boolean | Whether this is a granular data profile. |
| PrismaAIRs.DlpProfileCreate.version | Number | The profile version. |
| PrismaAIRs.DlpProfileCreate.detection_rules | Unknown | The detection rules array. |
| PrismaAIRs.DlpProfileCreate.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfileCreate.created_by | String | The user who created the profile. |
prisma-airs-runtime-dlp-profiles-patch
Partially update a DLP data profile (JSON Merge Patch). Fields set to “null” will be cleared.
Base Command
prisma-airs-runtime-dlp-profiles-patch
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The ID of the DLP data profile to update. | Required |
| name | The profile name (required for PATCH, cannot be cleared). | Required |
| profile_type | The profile type (required for PATCH, cannot be cleared). Possible values are: basic, advanced. | Required |
| description | The profile description (set to “null” to clear). | Optional |
| detection_rules | The detection rules as JSON array (set to “null” to clear). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpProfilePatch.id | String | The DLP Profile ID. |
| PrismaAIRs.DlpProfilePatch.name | String | The DLP Profile name. |
| PrismaAIRs.DlpProfilePatch.description | String | The DLP Profile description. |
| PrismaAIRs.DlpProfilePatch.type | String | The profile type. |
| PrismaAIRs.DlpProfilePatch.profile_status | String | The profile status. |
| PrismaAIRs.DlpProfilePatch.profile_type | String | The profile type. |
| PrismaAIRs.DlpProfilePatch.version | Number | The profile version. |
| PrismaAIRs.DlpProfilePatch.detection_rules | Unknown | The detection rules array. |
| PrismaAIRs.DlpProfilePatch.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfilePatch.updated_by | String | The user who last updated the profile. |
prisma-airs-runtime-dlp-profiles-replace
Replace (full update) a DLP data profile. This replaces the entire profile configuration.
Base Command
prisma-airs-runtime-dlp-profiles-replace
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The ID of the DLP data profile to replace. | Required |
| name | The profile name (1-64 characters). | Required |
| detection_rules | The detection rules as JSON array. | Required |
| description | The profile description. | Optional |
| is_granular_data_profile | Whether this is a granular data profile. Possible values are: true, false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpProfileReplace.id | String | The DLP Profile ID. |
| PrismaAIRs.DlpProfileReplace.name | String | The DLP Profile name. |
| PrismaAIRs.DlpProfileReplace.description | String | The DLP Profile description. |
| PrismaAIRs.DlpProfileReplace.type | String | The profile type. |
| PrismaAIRs.DlpProfileReplace.profile_status | String | The profile status. |
| PrismaAIRs.DlpProfileReplace.profile_type | String | The profile type. |
| PrismaAIRs.DlpProfileReplace.version | Number | The profile version. |
| PrismaAIRs.DlpProfileReplace.detection_rules | Unknown | The detection rules array. |
| PrismaAIRs.DlpProfileReplace.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpProfileReplace.updated_by | String | The user who last updated the profile. |
prisma-airs-runtime-dlp-profiles-delete
Soft-delete a DLP data profile. The DLP API has no DELETE endpoint, so the profile is patched to a deleted lifecycle state (profile_status=”deleted”). The command first fetches the profile to obtain its name and profile_type (required by the merge-patch). This action cannot be undone.
Base Command
prisma-airs-runtime-dlp-profiles-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The ID of the DLP data profile to delete. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpProfileDelete.id | String | The ID of the deleted DLP data profile. |
| PrismaAIRs.DlpProfileDelete.name | String | The name of the deleted DLP data profile. |
| PrismaAIRs.DlpProfileDelete.profile_status | String | The lifecycle status after deletion (deleted). |
| PrismaAIRs.DlpProfileDelete.deleted | Boolean | Whether the profile was successfully soft-deleted. |
| PrismaAIRs.DlpProfileDelete.status | String | The human-readable deletion status. |
prisma-airs-runtime-dlp-dictionaries-list
List DLP dictionaries.
Base Command
prisma-airs-runtime-dlp-dictionaries-list
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The page number for pagination. Default is 0. | Optional |
| size | The number of results per page. Default is 50. | Optional |
| include_keywords | Whether to include the keyword list in the response. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpDictionary.id | String | The dictionary ID. |
| PrismaAIRs.DlpDictionary.name | String | The dictionary name. |
| PrismaAIRs.DlpDictionary.description | String | The dictionary description. |
| PrismaAIRs.DlpDictionary.category | String | The dictionary category. |
| PrismaAIRs.DlpDictionary.region_name | String | The region name. |
| PrismaAIRs.DlpDictionary.type | String | The dictionary type (predefined or custom). |
| PrismaAIRs.DlpDictionary.is_case_sensitive | Boolean | Whether the dictionary is case sensitive. |
| PrismaAIRs.DlpDictionary.detection_technique | String | The detection technique. |
| PrismaAIRs.DlpDictionary.number_of_keywords | Number | The number of keywords in the dictionary. |
| PrismaAIRs.DlpDictionary.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpDictionary.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
Command example
!prisma-airs-runtime-dlp-dictionaries-list
Context Example
[
{
"category": "Financial",
"created_at": 1764730933326,
"created_by": "prisma-access",
"description": "top 10 banking and insurance competitors",
"detection_technique": "dictionary",
"id": "692fa835f65002a77b78018a",
"is_case_sensitive": false,
"is_parent_managed": false,
"name": "Custom Canada Banking",
"number_of_keywords": 30,
"region_name": "United States",
"type": "custom",
"updated_at": 1764774087254,
"updated_by": "prisma-access"
},
{
"category": "Academic",
"created_at": 1764712548699,
"created_by": "prisma-access",
"description": "profanity word list",
"detection_technique": "dictionary",
"id": "692f60646fa0612010d314c2",
"is_case_sensitive": false,
"is_parent_managed": false,
"name": "Custom profanity5",
"number_of_keywords": 13,
"region_name": "United States",
"type": "custom",
"updated_at": 1764774071150,
"updated_by": "prisma-access"
}
]
Human Readable Output
Prisma AIRs DLP Dictionaries (Page 1/1, 38 of 38)
Id Name Category Type Number Of Keywords Region Name 692fa835f65002a77b78018a Custom Canada Banking Financial custom 30 United States 692f60646fa0612010d314c2 Custom profanity5 Academic custom 13 United States
prisma-airs-runtime-dlp-dictionaries-get
Get a single DLP dictionary by ID, optionally including keywords.
Base Command
prisma-airs-runtime-dlp-dictionaries-get
Input
| Argument Name | Description | Required |
|---|---|---|
| dictionary_id | The ID of the DLP dictionary to retrieve. | Required |
| include_keywords | Whether to include the keyword list in the response. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpDictionaryGet.id | String | The dictionary ID. |
| PrismaAIRs.DlpDictionaryGet.name | String | The dictionary name. |
| PrismaAIRs.DlpDictionaryGet.description | String | The dictionary description. |
| PrismaAIRs.DlpDictionaryGet.category | String | The dictionary category. |
| PrismaAIRs.DlpDictionaryGet.region_name | String | The region name. |
| PrismaAIRs.DlpDictionaryGet.type | String | The dictionary type (predefined or custom). |
| PrismaAIRs.DlpDictionaryGet.is_case_sensitive | Boolean | Whether the dictionary is case sensitive. |
| PrismaAIRs.DlpDictionaryGet.is_parent_managed | Boolean | Whether the dictionary is parent-managed. |
| PrismaAIRs.DlpDictionaryGet.detection_technique | String | The detection technique. |
| PrismaAIRs.DlpDictionaryGet.detection_sub_technique | String | The detection sub-technique. |
| PrismaAIRs.DlpDictionaryGet.dictionary_metadata | Unknown | The dictionary metadata (number of keywords, file size, original filename). |
| PrismaAIRs.DlpDictionaryGet.keywords | Unknown | The keyword list (only populated if include_keywords is true). |
| PrismaAIRs.DlpDictionaryGet.tags | Unknown | The tags (classification array). |
| PrismaAIRs.DlpDictionaryGet.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpDictionaryGet.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpDictionaryGet.created_by | String | The user who created the dictionary. |
| PrismaAIRs.DlpDictionaryGet.updated_by | String | The user who last updated the dictionary. |
prisma-airs-runtime-dlp-dictionaries-create
Create a new DLP dictionary by uploading a keyword file.
Base Command
prisma-airs-runtime-dlp-dictionaries-create
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The dictionary name. | Required |
| category | The dictionary category. Possible values are: Academic, Confidential, Employment, Financial, Government, Healthcare, Legal, Marketing, Source Code. | Required |
| region_name | The region name (e.g., us-west-2). | Required |
| entry_id | The war room entry ID of the keyword file to upload. | Required |
| description | The dictionary description. | Optional |
| is_case_sensitive | Whether the dictionary is case sensitive. Possible values are: true, false. | Optional |
| type | The dictionary type. Possible values are: predefined, custom. | Optional |
| include_keywords | Whether to include the keyword list in the response. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpDictionaryCreate.id | String | The dictionary ID. |
| PrismaAIRs.DlpDictionaryCreate.name | String | The dictionary name. |
| PrismaAIRs.DlpDictionaryCreate.description | String | The dictionary description. |
| PrismaAIRs.DlpDictionaryCreate.category | String | The dictionary category. |
| PrismaAIRs.DlpDictionaryCreate.region_name | String | The region name. |
| PrismaAIRs.DlpDictionaryCreate.type | String | The dictionary type. |
| PrismaAIRs.DlpDictionaryCreate.is_case_sensitive | Boolean | Whether the dictionary is case sensitive. |
| PrismaAIRs.DlpDictionaryCreate.detection_technique | String | The detection technique. |
| PrismaAIRs.DlpDictionaryCreate.dictionary_metadata | Unknown | The dictionary metadata. |
| PrismaAIRs.DlpDictionaryCreate.keywords | Unknown | The keyword list. |
| PrismaAIRs.DlpDictionaryCreate.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpDictionaryCreate.created_by | String | The user who created the dictionary. |
prisma-airs-runtime-dlp-dictionaries-patch
Partially update a DLP dictionary (JSON Merge Patch). Fields set to “null” will be cleared.
Base Command
prisma-airs-runtime-dlp-dictionaries-patch
Input
| Argument Name | Description | Required |
|---|---|---|
| dictionary_id | The ID of the DLP dictionary to update. | Required |
| name | The dictionary name (required for PATCH, cannot be cleared). | Required |
| category | The dictionary category (required for PATCH, cannot be cleared). Possible values are: Academic, Confidential, Employment, Financial, Government, Healthcare, Legal, Marketing, Source Code. | Required |
| original_file_name | The original filename (required for PATCH, cannot be cleared). | Required |
| description | The dictionary description (set to “null” to clear). | Optional |
| is_case_sensitive | Whether the dictionary is case sensitive (set to “null” to clear). Possible values are: true, false, null. | Optional |
| region_name | The region name (set to “null” to clear). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpDictionaryPatch.id | String | The dictionary ID. |
| PrismaAIRs.DlpDictionaryPatch.name | String | The dictionary name. |
| PrismaAIRs.DlpDictionaryPatch.description | String | The dictionary description. |
| PrismaAIRs.DlpDictionaryPatch.category | String | The dictionary category. |
| PrismaAIRs.DlpDictionaryPatch.region_name | String | The region name. |
| PrismaAIRs.DlpDictionaryPatch.type | String | The dictionary type. |
| PrismaAIRs.DlpDictionaryPatch.is_case_sensitive | Boolean | Whether the dictionary is case sensitive. |
| PrismaAIRs.DlpDictionaryPatch.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpDictionaryPatch.updated_by | String | The user who last updated the dictionary. |
prisma-airs-runtime-dlp-dictionaries-replace
Replace (full update) a DLP dictionary by uploading a new keyword file.
Base Command
prisma-airs-runtime-dlp-dictionaries-replace
Input
| Argument Name | Description | Required |
|---|---|---|
| dictionary_id | The ID of the DLP dictionary to replace. | Required |
| name | The dictionary name. | Required |
| category | The dictionary category. Possible values are: Academic, Confidential, Employment, Financial, Government, Healthcare, Legal, Marketing, Source Code. | Required |
| region_name | The region name (e.g., us-west-2). | Required |
| entry_id | The war room entry ID of the keyword file to upload. | Required |
| description | The dictionary description. | Optional |
| is_case_sensitive | Whether the dictionary is case sensitive. Possible values are: true, false. | Optional |
| type | The dictionary type. Possible values are: predefined, custom. | Optional |
| include_keywords | Whether to include the keyword list in the response. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpDictionaryReplace.id | String | The dictionary ID. |
| PrismaAIRs.DlpDictionaryReplace.name | String | The dictionary name. |
| PrismaAIRs.DlpDictionaryReplace.description | String | The dictionary description. |
| PrismaAIRs.DlpDictionaryReplace.category | String | The dictionary category. |
| PrismaAIRs.DlpDictionaryReplace.region_name | String | The region name. |
| PrismaAIRs.DlpDictionaryReplace.type | String | The dictionary type. |
| PrismaAIRs.DlpDictionaryReplace.is_case_sensitive | Boolean | Whether the dictionary is case sensitive. |
| PrismaAIRs.DlpDictionaryReplace.keywords | Unknown | The keyword list. |
| PrismaAIRs.DlpDictionaryReplace.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpDictionaryReplace.updated_by | String | The user who last updated the dictionary. |
prisma-airs-runtime-dlp-dictionaries-delete
Delete a DLP dictionary. This action cannot be undone.
Base Command
prisma-airs-runtime-dlp-dictionaries-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| dictionary_id | The ID of the DLP dictionary to delete. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpDictionaryDelete.id | String | The ID of the deleted DLP dictionary. |
| PrismaAIRs.DlpDictionaryDelete.deleted | Boolean | Whether the dictionary was successfully deleted. |
| PrismaAIRs.DlpDictionaryDelete.status | String | The human-readable deletion status. |
prisma-airs-runtime-dlp-patterns-list
List DLP data patterns.
Base Command
prisma-airs-runtime-dlp-patterns-list
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The page number for pagination. Default is 0. | Optional |
| size | The number of results per page. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpPattern.id | String | The pattern ID. |
| PrismaAIRs.DlpPattern.name | String | The pattern name. |
| PrismaAIRs.DlpPattern.description | String | The pattern description. |
| PrismaAIRs.DlpPattern.category | String | The pattern category. |
| PrismaAIRs.DlpPattern.region_name | String | The region name. |
| PrismaAIRs.DlpPattern.type | String | The pattern type (predefined or custom). |
| PrismaAIRs.DlpPattern.detection_technique | String | The detection technique. |
| PrismaAIRs.DlpPattern.detection_sub_technique | String | The detection sub-technique. |
| PrismaAIRs.DlpPattern.pattern_status | String | The pattern status. |
| PrismaAIRs.DlpPattern.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpPattern.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
Command example
!prisma-airs-runtime-dlp-patterns-list
Context Example
[
{
"category": null,
"created_at": 1782430393022,
"created_by": null,
"description": "Replaced by test playbook",
"detection_sub_technique": null,
"detection_technique": null,
"id": "6a3dbab97c44baabe7d4a3f2",
"is_parent_managed": false,
"name": "test-dlp-pattern_archived_20260625233319",
"pattern_status": null,
"region_name": null,
"type": "custom",
"updated_at": 1782430399479,
"updated_by": null
},
{
"category": null,
"created_at": 1782429425823,
"created_by": "api",
"description": null,
"detection_sub_technique": null,
"detection_technique": null,
"id": "6a3db6f110bca195474257c8",
"is_parent_managed": false,
"name": "test-dlp-pattern_archived_20260625232019",
"pattern_status": null,
"region_name": null,
"type": "custom",
"updated_at": 1782429619802,
"updated_by": null
}
]
Human Readable Output
Prisma AIRs DLP Patterns (Page 1/23, 50 of 1130)
|Id|Name|Category|Type|Detection Technique|Pattern Status|
|—|—|—|—|—|—|
| 6a3dbab97c44baabe7d4a3f2 | test-dlp-pattern_archived_20260625233319 | | custom | | |
| 6a3db6f110bca195474257c8 | test-dlp-pattern_archived_20260625232019 | | custom | | |
| 6a037babfe42bf6d0e602012 | custom-mcp-tool_call | | custom | | |
| 69c69833b3293364869f762e | Cloud Provider Secrets - Google API Key | | custom | | |
| 69c691d97dc0d64123835a5e | Payment Service Secrets - Stripe Publishable Key | | custom | | |
| 69c691c06854cb631a5cf435 | Payment Service Secrets - Stripe Secret Key | | custom | | |
| 69c55b2bbb6eef6b05a207d9 | Cryptocurrency - Monero Address | | custom | | |
| 69c55ae70962bc71b8d5e585 | Cryptocurrency - Ripple Address | | custom | | |
| 69305a99f65002a77b7801c5 | Custom-brace | | custom | | |
| 693057f2f65002a77b7801c3 | Custom-banking-regex | | custom | | |
| 692dffc5c56c6c4b3793d6b2 | Custom-XML | | custom | | |
| 6928bae36fa0612010d3119c | custom-url-exclude | | custom | | |
| 69289832182e76e8088db89f | custom-url-include | | custom | | |
| 68ff6020e66e2c793430df82 | Driver License - Italy | | predefined | | |
| 68ff6020e66e2c793430df72 | Driver License - Brazil | | predefined | | |
| 68ff6020e66e2c793430df84 | Driver License - Lithuania | | predefined | | |
| 68ff6020e66e2c793430df86 | Driver License - Latvia | | predefined | | |
| 68ff6020e66e2c793430df6a | Secret Key - RSA Private Key | | predefined | | |
| 68ff6020e66e2c793430df74 | Driver License - Cyprus | | predefined | | |
| 68ff6020e66e2c793430df88 | Driver License - Netherlands | | predefined | | |
| 68ff6020e66e2c793430df8a | Driver License - Norway | | predefined | | |
| 68ff6020e66e2c793430df76 | Driver License - Germany | | predefined | | |
| 68ff6020e66e2c793430df8c | Driver License - Portugal | | predefined | | |
| 68ff6020e66e2c793430df8e | Driver License - Switzerland | | predefined | | |
| 68ff6020e66e2c793430df66 | Secret Key - AWS Access Key ID | | predefined | | |
| 68ff6020e66e2c793430df6c | Company Confidential | | predefined | | |
| 68ff6020e66e2c793430df78 | Driver License - Estonia | | predefined | | |
| 68ff6020e66e2c793430df90 | Driver License - Slovenia | | predefined | | |
| 68ff6020e66e2c793430df81 | Driver License - Iceland | | predefined | | |
| 68ff6020e66e2c793430df71 | Driver License - Belgium | | predefined | | |
| 68ff6020e66e2c793430df83 | Driver License - Liechtenstein | | predefined | | |
| 68ff6020e66e2c793430df69 | Secret Key - Google Cloud Secret Access Key | | predefined | | |
| 68ff6020e66e2c793430df85 | Driver License - Luxembourg | | predefined | | |
| 68ff6020e66e2c793430df73 | Driver License - Bulgaria | | predefined | | |
| 68ff6020e66e2c793430df87 | Driver License - Malta | | predefined | | |
| 68ff6020e66e2c793430df65 | Bank - Statements | | predefined | | |
| 68ff6020e66e2c793430df89 | Driver License - New Zealand | | predefined | | |
| 68ff6020e66e2c793430df75 | Driver License - Czech Republic | | predefined | | |
| 68ff6020e66e2c793430df8b | Driver License - Poland | | predefined | | |
| 68ff6020e66e2c793430df6b | Bank - Committee on Uniform Securities Identification Procedures number | | predefined | | |
| 68ff6020e66e2c793430df8d | Driver License - Romania | | predefined | | |
| 68ff6020e66e2c793430df77 | Driver License - Denmark | | predefined | | |
| 68ff6020e66e2c793430df8f | Driver License - Sweden | | predefined | | |
| 68ff6020e66e2c793430df63 | Bank - Bankruptcy Filings | | predefined | | |
| 68ff6020e66e2c793430df91 | Driver License - Slovakia | | predefined | | |
| 68ff6020e66e2c793430df79 | Driver License - Spain | | predefined | | |
| 68ff6020e66e2c793430df92 | Driver License - Turkey | | predefined | | |
… (truncated)
prisma-airs-runtime-dlp-patterns-get
Get a single DLP data pattern by ID.
Base Command
prisma-airs-runtime-dlp-patterns-get
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | The ID of the DLP data pattern to retrieve. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpPatternGet.id | String | The pattern ID. |
| PrismaAIRs.DlpPatternGet.name | String | The pattern name. |
| PrismaAIRs.DlpPatternGet.description | String | The pattern description. |
| PrismaAIRs.DlpPatternGet.tenant_id | String | The tenant ID. |
| PrismaAIRs.DlpPatternGet.type | String | The pattern type (predefined, custom, file_property). |
| PrismaAIRs.DlpPatternGet.status | String | The pattern status (active, disabled, deleted, deprecated, silent). |
| PrismaAIRs.DlpPatternGet.license_type | String | The license tier (standard, enterprise, essentials). |
| PrismaAIRs.DlpPatternGet.is_parent_managed | Boolean | Whether the pattern is parent-managed. |
| PrismaAIRs.DlpPatternGet.version | Number | The pattern version number. |
| PrismaAIRs.DlpPatternGet.detection_config | Unknown | The detection configuration (technique and confidence levels). |
| PrismaAIRs.DlpPatternGet.matching_rules | Unknown | The matching rules (proximity, delimiters, regexes, metadata). |
| PrismaAIRs.DlpPatternGet.tags | Unknown | The tags (classification, compliance, geography). |
| PrismaAIRs.DlpPatternGet.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpPatternGet.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpPatternGet.created_by | String | The user who created the pattern. |
| PrismaAIRs.DlpPatternGet.updated_by | String | The user who last updated the pattern. |
Command example
!prisma-airs-runtime-dlp-patterns-get pattern_id=${PrismaAIRs.DlpPatternCreate.id}
Context Example
{
"created_at": 1782481855433,
"created_by": "api",
"description": null,
"detection_config": {
"supported_confidence_levels": [
"high",
"low"
],
"technique": "regex"
},
"id": "6a3e83bf22dd876b13ee58c9",
"is_parent_managed": false,
"license_type": "standard",
"matching_rules": {
"delimiter": null,
"metadata_criteria": null,
"proximity_distance": 200,
"proximity_keywords": null,
"regexes": [
{
"regex": "[0-9]{3}-[0-9]{2}-[0-9]{4}",
"weight": 1
}
]
},
"name": "readme-example-pattern",
"status": "active",
"tags": {
"classification": [
"pab",
"endpoint"
]
},
"tenant_id": "1234567890123456789",
"type": "custom",
"updated_at": 1782481855433,
"updated_by": "api",
"version": 1
}
Human Readable Output
Prisma AIRs DLP Pattern: readme-example-pattern
Id Name Type Status License Type Description 6a3e83bf22dd876b13ee58c9 readme-example-pattern custom active standard
prisma-airs-runtime-dlp-patterns-create
Create a new DLP data pattern.
Base Command
prisma-airs-runtime-dlp-patterns-create
Input
| Argument Name | Description | Required |
|---|---|---|
| name | The pattern name (1-64 characters). | Required |
| type | The pattern type. Possible values are: predefined, custom, file_property. | Required |
| detection_technique | The detection technique. Possible values are: edm, document_fingerprint, trainable_classifier, ml_document, regex, weighted_regex, ml, titus_tag, wildfire, file_property, dictionary, pab, document_classifier. | Required |
| supported_confidence_levels | A comma-separated list of confidence levels (low, medium, high). Alternatively, a JSON array. | Optional |
| description | The pattern description. | Optional |
| matching_rules | The matching rules as JSON object (proximity, delimiters, regexes, metadata_criteria). | Optional |
| tags | The tags as JSON object with classification, compliance, geography arrays. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpPatternCreate.id | String | The pattern ID. |
| PrismaAIRs.DlpPatternCreate.name | String | The pattern name. |
| PrismaAIRs.DlpPatternCreate.description | String | The pattern description. |
| PrismaAIRs.DlpPatternCreate.type | String | The pattern type. |
| PrismaAIRs.DlpPatternCreate.status | String | The pattern status. |
| PrismaAIRs.DlpPatternCreate.detection_config | Unknown | The detection configuration. |
| PrismaAIRs.DlpPatternCreate.matching_rules | Unknown | The matching rules. |
| PrismaAIRs.DlpPatternCreate.tags | Unknown | The tags. |
| PrismaAIRs.DlpPatternCreate.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpPatternCreate.created_by | String | The user who created the pattern. |
Command example
!prisma-airs-runtime-dlp-patterns-create name="readme-example-pattern" type="custom" detection_technique="regex" matching_rules=`{"regexes":[{"regex":"[0-9]{3}-[0-9]{2}-[0-9]{4}","weight":1}]}`
Context Example
{
"created_at": 1782481855433,
"created_by": "api",
"description": null,
"detection_config": {
"supported_confidence_levels": [
"high",
"low"
],
"technique": "regex"
},
"id": "6a3e83bf22dd876b13ee58c9",
"license_type": "standard",
"matching_rules": {
"delimiter": null,
"metadata_criteria": null,
"proximity_distance": 200,
"proximity_keywords": null,
"regexes": [
{
"regex": "[0-9]{3}-[0-9]{2}-[0-9]{4}",
"weight": 1
}
]
},
"name": "readme-example-pattern",
"status": "active",
"tags": {
"classification": [
"pab",
"endpoint"
]
},
"tenant_id": "1234567890123456789",
"type": "custom",
"version": 1
}
Human Readable Output
Prisma AIRs DLP Pattern Created: readme-example-pattern
Id Name Type Status Description 6a3e83bf22dd876b13ee58c9 readme-example-pattern custom active
prisma-airs-runtime-dlp-patterns-patch
Partially update a DLP data pattern (JSON Merge Patch). Fields set to “null” will be cleared.
Base Command
prisma-airs-runtime-dlp-patterns-patch
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | The ID of the DLP data pattern to update. | Required |
| name | The pattern name (required for PATCH, cannot be cleared). | Required |
| type | The pattern type (required for PATCH, cannot be cleared). Possible values are: predefined, custom, file_property. | Required |
| detection_technique | The detection technique (required for PATCH, cannot be cleared). Possible values are: edm, document_fingerprint, trainable_classifier, ml_document, regex, weighted_regex, ml, titus_tag, wildfire, file_property, dictionary, pab, document_classifier. | Required |
| supported_confidence_levels | A comma-separated list of confidence levels (low, medium, high). Alternatively, a JSON array. | Optional |
| description | The pattern description (set to “null” to clear). | Optional |
| matching_rules | The matching rules as JSON object (set to “null” to clear). | Optional |
| tags | The tags as JSON object (set to “null” to clear). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpPatternPatch.id | String | The pattern ID. |
| PrismaAIRs.DlpPatternPatch.name | String | The pattern name. |
| PrismaAIRs.DlpPatternPatch.description | String | The pattern description. |
| PrismaAIRs.DlpPatternPatch.type | String | The pattern type. |
| PrismaAIRs.DlpPatternPatch.status | String | The pattern status. |
| PrismaAIRs.DlpPatternPatch.version | Number | The pattern version number. |
| PrismaAIRs.DlpPatternPatch.detection_config | Unknown | The detection configuration. |
| PrismaAIRs.DlpPatternPatch.matching_rules | Unknown | The matching rules. |
| PrismaAIRs.DlpPatternPatch.tags | Unknown | The tags. |
| PrismaAIRs.DlpPatternPatch.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpPatternPatch.updated_by | String | The user who last updated the pattern. |
Command example
!prisma-airs-runtime-dlp-patterns-patch pattern_id=${PrismaAIRs.DlpPatternCreate.id} name="readme-example-pattern" type="custom" detection_technique="regex" description="Updated example pattern"
Context Example
{
"description": "Updated example pattern",
"detection_config": {
"supported_confidence_levels": [
"high",
"low"
],
"technique": "regex"
},
"id": "6a3e83bf22dd876b13ee58c9",
"matching_rules": {
"delimiter": null,
"metadata_criteria": null,
"proximity_distance": 200,
"proximity_keywords": null,
"regexes": [
{
"regex": "[0-9]{3}-[0-9]{2}-[0-9]{4}",
"weight": 1
}
]
},
"name": "readme-example-pattern",
"status": "active",
"tags": {
"classification": [
"pab",
"endpoint"
]
},
"tenant_id": "1234567890123456789",
"type": "custom",
"updated_at": 1782481860304,
"updated_by": "api",
"version": 1
}
Human Readable Output
Prisma AIRs DLP Pattern Patched: readme-example-pattern
Id Name Type Status Description 6a3e83bf22dd876b13ee58c9 readme-example-pattern custom active Updated example pattern
prisma-airs-runtime-dlp-patterns-replace
Replace (full update) a DLP data pattern. This replaces the entire pattern configuration.
Base Command
prisma-airs-runtime-dlp-patterns-replace
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | The ID of the DLP data pattern to replace. | Required |
| name | The pattern name (1-64 characters). | Required |
| type | The pattern type. Possible values are: predefined, custom, file_property. | Required |
| detection_technique | The detection technique. Possible values are: edm, document_fingerprint, trainable_classifier, ml_document, regex, weighted_regex, ml, titus_tag, wildfire, file_property, dictionary, pab, document_classifier. | Required |
| supported_confidence_levels | A comma-separated list of confidence levels (low, medium, high). Alternatively, a JSON array. | Optional |
| description | The pattern description. | Optional |
| matching_rules | The matching rules as JSON object. | Optional |
| tags | The tags as JSON object. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpPatternReplace.id | String | The pattern ID. |
| PrismaAIRs.DlpPatternReplace.name | String | The pattern name. |
| PrismaAIRs.DlpPatternReplace.description | String | The pattern description. |
| PrismaAIRs.DlpPatternReplace.type | String | The pattern type. |
| PrismaAIRs.DlpPatternReplace.status | String | The pattern status. |
| PrismaAIRs.DlpPatternReplace.version | Number | The pattern version number. |
| PrismaAIRs.DlpPatternReplace.detection_config | Unknown | The detection configuration. |
| PrismaAIRs.DlpPatternReplace.matching_rules | Unknown | The matching rules. |
| PrismaAIRs.DlpPatternReplace.tags | Unknown | The tags. |
| PrismaAIRs.DlpPatternReplace.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpPatternReplace.updated_by | String | The user who last updated the pattern. |
Command example
!prisma-airs-runtime-dlp-patterns-replace pattern_id=${PrismaAIRs.DlpPatternCreate.id} name="readme-example-pattern" type="custom" detection_technique="regex" matching_rules=`{"regexes":[{"regex":"[0-9]{3}-[0-9]{2}-[0-9]{4}","weight":1}]}`
Context Example
{
"description": null,
"detection_config": {
"supported_confidence_levels": [
"high",
"low"
],
"technique": "regex"
},
"id": "6a3e83bf22dd876b13ee58c9",
"matching_rules": {
"delimiter": null,
"metadata_criteria": null,
"proximity_distance": 200,
"proximity_keywords": null,
"regexes": [
{
"regex": "[0-9]{3}-[0-9]{2}-[0-9]{4}",
"weight": 1
}
]
},
"name": "readme-example-pattern",
"status": "active",
"tags": {
"classification": [
"pab",
"endpoint"
]
},
"tenant_id": "1234567890123456789",
"type": "custom",
"updated_at": 1782481862373,
"updated_by": "api",
"version": 1
}
Human Readable Output
Prisma AIRs DLP Pattern Replaced: readme-example-pattern
Id Name Type Status Description 6a3e83bf22dd876b13ee58c9 readme-example-pattern custom active
prisma-airs-runtime-dlp-patterns-delete
Delete (soft-delete/archive) a DLP data pattern. This action cannot be undone.
Base Command
prisma-airs-runtime-dlp-patterns-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | The ID of the DLP data pattern to delete. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpPatternDelete.id | String | The ID of the deleted DLP data pattern. |
| PrismaAIRs.DlpPatternDelete.deleted | Boolean | Whether the pattern was successfully deleted. |
| PrismaAIRs.DlpPatternDelete.status | String | The human-readable deletion status. |
Command example
!prisma-airs-runtime-dlp-patterns-delete pattern_id=${PrismaAIRs.DlpPatternCreate.id}
Context Example
{
"deleted": true,
"id": "6a3e83bf22dd876b13ee58c9",
"status": "Successfully archived"
}
Human Readable Output
Prisma AIRs DLP Pattern Deleted
Id Status 6a3e83bf22dd876b13ee58c9 Successfully archived
prisma-airs-runtime-dlp-filtering-profiles-list
List DLP filtering profiles.
Base Command
prisma-airs-runtime-dlp-filtering-profiles-list
Input
| Argument Name | Description | Required |
|---|---|---|
| page | The page number for pagination. Default is 0. | Optional |
| size | The number of results per page. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpFilteringProfile.id | String | The filtering profile ID. |
| PrismaAIRs.DlpFilteringProfile.name | String | The filtering profile name. |
| PrismaAIRs.DlpFilteringProfile.description | String | The filtering profile description. |
| PrismaAIRs.DlpFilteringProfile.type | String | The profile type. |
| PrismaAIRs.DlpFilteringProfile.default_action | String | The default action for the profile. |
| PrismaAIRs.DlpFilteringProfile.is_parent_managed | Boolean | Whether the profile is parent-managed. |
| PrismaAIRs.DlpFilteringProfile.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpFilteringProfile.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
Command example
!prisma-airs-runtime-dlp-filtering-profiles-list
Context Example
[
{
"created_at": 1782433839552,
"created_by": null,
"default_action": null,
"description": null,
"id": "6a3dc82f28afbc03c9729258",
"is_parent_managed": false,
"name": "test-dlp-profile",
"type": "custom",
"updated_at": 1782433839552,
"updated_by": "api"
},
{
"created_at": 1778613252311,
"created_by": null,
"default_action": null,
"description": null,
"id": "6a037c04ce5246aece784f89",
"is_parent_managed": false,
"name": "Custom-MCP-Tools_Call",
"type": "custom",
"updated_at": 1778613252311,
"updated_by": "Strata Cloud Manager"
}
]
Human Readable Output
Prisma AIRs DLP Filtering Profiles (Page 1/1, 35 of 35)
Id Name Type Default Action Description 6a3dc82f28afbc03c9729258 test-dlp-profile custom 6a037c04ce5246aece784f89 Custom-MCP-Tools_Call custom 69a8a79431a8507b83b43ae4 PII Basic Block All Data predefined 69304a8e6fa0612010d31504 Custom-Profile-DataDict-Bank custom 692f58e1c56c6c4b3793d786 Custom-Profile-DataDict custom 692f41aa182e76e8088dbc14 Custom-Profile-Healthcare custom 692f41786fa0612010d314b4 Custom-Profile-Self Harm custom 692f41446fa0612010d314b3 Custom-Profile-Profanity custom 692df591182e76e8088dbb03 SensitiveContent-nestCustomURLEx custom 6928bb08182e76e8088db8a9 Custom-Profile-Regex custom 692898626fa0612010d31193 Sensitive Content-CustomURLIn custom 68ff6d46e66e2c793430e489 U.K. PIOCP predefined 68ff6d46e66e2c793430e488 SOX predefined 68ff6d46e66e2c793430e486 Self Harm predefined 68ff6d46e66e2c793430e487 Sensitive Content predefined 68ff6d46e66e2c793430e485 Secrets and Credentials predefined 68ff6d46e66e2c793430e484 Profanity predefined 68ff6d46e66e2c793430e483 POPIA predefined 68ff6d46e66e2c793430e482 PIPEDA predefined 68ff6d46e66e2c793430e481 PII predefined 68ff6d46e66e2c793430e480 PII - Basic predefined 68ff6d46e66e2c793430e47e PHI predefined 68ff6d46e66e2c793430e47f PHIPA predefined 68ff6d46e66e2c793430e47a Intellectual Property - Basic predefined 68ff6d46e66e2c793430e47c Legal predefined 68ff6d46e66e2c793430e47b Intellectual Property predefined 68ff6d46e66e2c793430e479 HIPAA predefined 68ff6d46e66e2c793430e478 Healthcare predefined 68ff6d46e66e2c793430e477 GLBA predefined 68ff6d46e66e2c793430e476 GDPR predefined 68ff6d46e66e2c793430e475 Financial Information predefined 68ff6d46e66e2c793430e474 Corporate Financial Docs predefined 68ff6d46e66e2c793430e473 CommonwealthAustralia-PrivAct88 predefined 68ff6d46e66e2c793430e472 CCPA predefined 68ff6d46e66e2c793430e471 Bulk CCN predefined
prisma-airs-runtime-dlp-filtering-profiles-get
Get a single DLP filtering profile by ID.
Base Command
prisma-airs-runtime-dlp-filtering-profiles-get
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The ID of the DLP filtering profile to retrieve. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpFilteringProfileGet.id | String | The filtering profile ID. |
| PrismaAIRs.DlpFilteringProfileGet.name | String | The filtering profile name. |
| PrismaAIRs.DlpFilteringProfileGet.description | String | The filtering profile description. |
| PrismaAIRs.DlpFilteringProfileGet.tenant_id | String | The tenant ID. |
| PrismaAIRs.DlpFilteringProfileGet.type | String | The profile type. |
| PrismaAIRs.DlpFilteringProfileGet.data_profile_id | Number | The associated data profile ID. |
| PrismaAIRs.DlpFilteringProfileGet.direction | String | The scan direction (BOTH, UPLOAD, DOWNLOAD). |
| PrismaAIRs.DlpFilteringProfileGet.file_based | Boolean | Whether file-based scanning is enabled. |
| PrismaAIRs.DlpFilteringProfileGet.non_file_based | Boolean | Whether non-file-based scanning is enabled. |
| PrismaAIRs.DlpFilteringProfileGet.log_severity | String | The log severity level. |
| PrismaAIRs.DlpFilteringProfileGet.scan_type | String | The scan type (include or exclude). |
| PrismaAIRs.DlpFilteringProfileGet.is_end_user_coaching_enabled | Boolean | Whether end user coaching is enabled. |
| PrismaAIRs.DlpFilteringProfileGet.is_granular_profile | Boolean | Whether this is a granular profile. |
| PrismaAIRs.DlpFilteringProfileGet.is_parent_managed | Boolean | Whether the profile is parent-managed. |
| PrismaAIRs.DlpFilteringProfileGet.euc_template_id | String | The end user coaching template ID. |
| PrismaAIRs.DlpFilteringProfileGet.version | Number | The profile version number. |
| PrismaAIRs.DlpFilteringProfileGet.file_type | Unknown | The allowed file types for scanning. |
| PrismaAIRs.DlpFilteringProfileGet.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpFilteringProfileGet.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpFilteringProfileGet.created_by | String | The user who created the profile. |
| PrismaAIRs.DlpFilteringProfileGet.updated_by | String | The user who last updated the profile. |
prisma-airs-runtime-dlp-filtering-profiles-replace
Replace (full update) a DLP filtering profile. This is a destructive operation that replaces the entire profile configuration.
Base Command
prisma-airs-runtime-dlp-filtering-profiles-replace
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_id | The ID of the DLP filtering profile to replace. | Required |
| file_based | Whether file-based scanning is enabled. Possible values are: true, false. | Required |
| non_file_based | Whether non-file-based scanning is enabled. Possible values are: true, false. | Required |
| description | The profile description. | Optional |
| direction | The scan direction. Possible values are: BOTH, UPLOAD, DOWNLOAD. | Optional |
| log_severity | The log severity level. Possible values are: CRITICAL, HIGH, MEDIUM, LOW, INFORMATIONAL. | Optional |
| scan_type | The scan type (include or exclude file types). Possible values are: include, exclude. | Optional |
| data_profile_id | The associated data profile ID (numeric). | Optional |
| euc_template_id | The end user coaching template ID. | Optional |
| is_end_user_coaching_enabled | Whether end user coaching is enabled. Possible values are: true, false. | Optional |
| is_granular_profile | Whether this is a granular profile. Possible values are: true, false. | Optional |
| file_type | A comma-separated list of file types to include or exclude. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.DlpFilteringProfileReplace.id | String | The filtering profile ID. |
| PrismaAIRs.DlpFilteringProfileReplace.name | String | The filtering profile name. |
| PrismaAIRs.DlpFilteringProfileReplace.description | String | The filtering profile description. |
| PrismaAIRs.DlpFilteringProfileReplace.tenant_id | String | The tenant ID. |
| PrismaAIRs.DlpFilteringProfileReplace.type | String | The profile type. |
| PrismaAIRs.DlpFilteringProfileReplace.data_profile_id | Number | The associated data profile ID. |
| PrismaAIRs.DlpFilteringProfileReplace.direction | String | The scan direction (BOTH, UPLOAD, DOWNLOAD). |
| PrismaAIRs.DlpFilteringProfileReplace.file_based | Boolean | Whether file-based scanning is enabled. |
| PrismaAIRs.DlpFilteringProfileReplace.non_file_based | Boolean | Whether non-file-based scanning is enabled. |
| PrismaAIRs.DlpFilteringProfileReplace.log_severity | String | The log severity level. |
| PrismaAIRs.DlpFilteringProfileReplace.scan_type | String | The scan type (include or exclude). |
| PrismaAIRs.DlpFilteringProfileReplace.is_end_user_coaching_enabled | Boolean | Whether end user coaching is enabled. |
| PrismaAIRs.DlpFilteringProfileReplace.is_granular_profile | Boolean | Whether this is a granular profile. |
| PrismaAIRs.DlpFilteringProfileReplace.is_parent_managed | Boolean | Whether the profile is parent-managed. |
| PrismaAIRs.DlpFilteringProfileReplace.version | Number | The profile version number. |
| PrismaAIRs.DlpFilteringProfileReplace.created_at | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpFilteringProfileReplace.updated_at | Date | The last update timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.DlpFilteringProfileReplace.created_by | String | The user who created the profile. |
| PrismaAIRs.DlpFilteringProfileReplace.updated_by | String | The user who last updated the profile. |
prisma-airs-runtime-topics-list
List custom topic guardrails.
Base Command
prisma-airs-runtime-topics-list
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of topics to return. Default is 100. | Optional |
| offset | The starting offset for pagination. Default is 0. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.Topic.topic_id | String | The topic UUID. |
| PrismaAIRs.Topic.topic_name | String | The topic name. |
| PrismaAIRs.Topic.revision | Number | The topic revision number. |
| PrismaAIRs.Topic.description | String | The topic description. |
| PrismaAIRs.Topic.examples | Unknown | The example prompts for the topic. |
| PrismaAIRs.Topic.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.Topic.created_by | String | The user who created the topic. |
| PrismaAIRs.Topic.updated_by | String | The user who last updated the topic. |
| PrismaAIRs.Topic.csp_id | String | The CSP ID. |
| PrismaAIRs.Topic.tsg_id | String | The tenant Service Group ID. |
Command example
!prisma-airs-runtime-topics-list
Context Example
[
{
"created_by": null,
"csp_id": "XXXXXX",
"description": "Text-based visual representations — including block letter banners, character-grid illustrations, decorative symbols, and complex imagery constructed from ASCII or Unicode symbols.",
"examples": [
"Draw a cat using ASCII characters",
"For my creative writing project, design a massive sword using only punctuation and symbols.",
"Show me how a 1980s computer would render a Christmas tree in a terminal window.",
"Generate a large banner that says 'CONFIDENTIAL' in block letters made of hash symbols.",
"Encode the image of a car into a grid of text characters so I can paste it into an email."
],
"last_modified_ts": "2026-02-11T14:28:08Z",
"revision": 1,
"topic_id": "1813334c-f2a0-4b1b-aea2-b66e1f31f422",
"topic_name": "ascii_art_and_character_graphics",
"tsg_id": "1234567",
"updated_by": null
},
{
"created_by": null,
"csp_id": "XXXXXX",
"description": "Encoding and decoding operations — including Base64, ROT13, Morse code, hex, and binary conversions, as well as character-level manipulations like string reversal or symbolic substitution of cleartext.",
"examples": [
"Translate this sequence of dots and dashes into a standard English sentence.",
"For my cryptography class, show me how the phrase 'system bypass' looks when shifted by 13 characters.",
"I'm a developer debugging a script; please decode this Base64 string into plain text.",
"Reverse the order of every character in this paragraph to help me check for hidden patterns.",
"In a futuristic sci-fi setting, how would an AI represent the concept of 'access granted' using only hexadecimal?"
],
"last_modified_ts": "2026-02-11T14:26:04Z",
"revision": 1,
"topic_id": "c04fb758-3821-4aec-bfd9-cd284f0f3f0e",
"topic_name": "text_transformation_and_obfuscation",
"tsg_id": "1234567",
"updated_by": null
}
]
Human Readable Output
Prisma AIRs Custom Topics (13 of 13)
Topic Id Topic Name Revision Description 1813334c-f2a0-4b1b-aea2-b66e1f31f422 ascii_art_and_character_graphics 1 Text-based visual representations — including block letter banners, character-grid illustrations, decorative symbols, and complex imagery constructed from ASCII or Unicode symbols. c04fb758-3821-4aec-bfd9-cd284f0f3f0e text_transformation_and_obfuscation 1 Encoding and decoding operations — including Base64, ROT13, Morse code, hex, and binary conversions, as well as character-level manipulations like string reversal or symbolic substitution of cleartext. 802d0b36-2ea9-486b-bb5c-1fee684c1865 obfuscated_financial_crime_queries 1 Text manipulation of illicit terms — including string reversal, character scrambling, substitution ciphers, and unusual spacing used to mask money laundering, fraud, or tax evasion terminology. 2c2cb8cd-d5ab-4407-ad5e-cbf108823a73 creative_literary_composition 1 Creative writing outputs — including poetry, rhyming verse, fictional narratives, prose storytelling, allegories, and metaphorical expansions of specific themes or prompts.
prisma-airs-runtime-topics-get
Get a specific custom topic by ID or name.
Base Command
prisma-airs-runtime-topics-get
Input
| Argument Name | Description | Required |
|---|---|---|
| topic_id | The topic UUID (either topic_id or topic_name is required). | Optional |
| topic_name | The topic name. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.TopicGet.topic_id | String | The topic UUID. |
| PrismaAIRs.TopicGet.topic_name | String | The topic name. |
| PrismaAIRs.TopicGet.revision | Number | The topic revision number. |
| PrismaAIRs.TopicGet.active | Boolean | Whether the topic is active. |
| PrismaAIRs.TopicGet.description | String | The topic description. |
| PrismaAIRs.TopicGet.examples | Unknown | The example prompts for the topic. |
| PrismaAIRs.TopicGet.created_by | String | The user who created the topic. |
| PrismaAIRs.TopicGet.updated_by | String | The user who last updated the topic. |
| PrismaAIRs.TopicGet.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.TopicGet.created_ts | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
Command example
!prisma-airs-runtime-topics-get topic_id=${PrismaAIRs.TopicCreate.topic_id}
Context Example
{
"active": null,
"created_by": null,
"created_ts": null,
"description": "Example custom topic for documentation",
"examples": [
"example prompt one",
"example prompt two"
],
"last_modified_ts": "2026-06-26T13:50:38Z",
"revision": 1,
"topic_id": "6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad",
"topic_name": "readme-example-topic",
"updated_by": null
}
Human Readable Output
Custom Topic: readme-example-topic
Topic Id Topic Name Revision Description Last Modified Ts 6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad readme-example-topic 1 Example custom topic for documentation 2026-06-26T13:50:38Z Examples (2):
- example prompt one
- example prompt two
prisma-airs-runtime-topics-create
Create a new custom topic guardrail with examples for detection.
Base Command
prisma-airs-runtime-topics-create
Input
| Argument Name | Description | Required |
|---|---|---|
| topic_name | The name for the new topic (must be unique). | Required |
| description | The description of what this topic detects. | Required |
| examples | A comma-separated list of example prompts/content that match this topic. | Required |
| active | Whether the topic should be active. Possible values are: true, false. Default is true. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.TopicCreate.topic_id | String | The topic UUID. |
| PrismaAIRs.TopicCreate.topic_name | String | The topic name. |
| PrismaAIRs.TopicCreate.revision | Number | The topic revision number (starts at 1). |
| PrismaAIRs.TopicCreate.active | Boolean | Whether the topic is active. |
| PrismaAIRs.TopicCreate.description | String | The topic description. |
| PrismaAIRs.TopicCreate.examples | Unknown | The example prompts for the topic. |
| PrismaAIRs.TopicCreate.created_by | String | The user who created the topic. |
| PrismaAIRs.TopicCreate.updated_by | String | The user who last updated the topic. |
| PrismaAIRs.TopicCreate.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.TopicCreate.created_ts | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
Command example
!prisma-airs-runtime-topics-create topic_name="readme-example-topic" description="Example custom topic for documentation" examples="example prompt one,example prompt two"
Context Example
{
"active": true,
"created_by": "test@test.com",
"created_ts": null,
"description": "Example custom topic for documentation",
"examples": [
"example prompt one",
"example prompt two"
],
"last_modified_ts": "2026-06-26T13:50:38Z",
"revision": 1,
"topic_id": "6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad",
"topic_name": "readme-example-topic",
"updated_by": "test@test.com"
}
Human Readable Output
Custom Topic Created
Topic Id Topic Name Revision Active Description Created By 6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad readme-example-topic 1 true Example custom topic for documentation test@test.com Examples (2):
- example prompt one
- example prompt two
prisma-airs-runtime-topics-update
Update an existing custom topic. WARNING - Modifying topic definition can break detection if misconfigured.
Base Command
prisma-airs-runtime-topics-update
Input
| Argument Name | Description | Required |
|---|---|---|
| topic_id | The topic UUID to update. | Required |
| topic_name | The topic name (can be changed or kept the same). | Required |
| description | The updated description (if omitted, description remains unchanged). | Optional |
| examples | An updated comma-separated list of examples (if omitted, examples remain unchanged). | Optional |
| active | Whether the topic should be active. Possible values are: true, false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.TopicUpdate.topic_id | String | The topic UUID. |
| PrismaAIRs.TopicUpdate.topic_name | String | The topic name. |
| PrismaAIRs.TopicUpdate.revision | Number | The topic revision number (incremented after update). |
| PrismaAIRs.TopicUpdate.active | Boolean | Whether the topic is active. |
| PrismaAIRs.TopicUpdate.description | String | The topic description. |
| PrismaAIRs.TopicUpdate.examples | Unknown | The example prompts for the topic. |
| PrismaAIRs.TopicUpdate.created_by | String | The user who created the topic. |
| PrismaAIRs.TopicUpdate.updated_by | String | The user who last updated the topic. |
| PrismaAIRs.TopicUpdate.last_modified_ts | Date | The last modification timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
| PrismaAIRs.TopicUpdate.created_ts | Date | The creation timestamp in ISO 8601 format (e.g., 2024-01-15T12:34:56Z). |
Command example
!prisma-airs-runtime-topics-update topic_id=${PrismaAIRs.TopicCreate.topic_id} topic_name="readme-example-topic" description="Updated example custom topic"
Context Example
{
"active": true,
"created_by": "test@test.com",
"created_ts": null,
"description": "Updated example custom topic",
"examples": [],
"last_modified_ts": null,
"revision": 2,
"topic_id": "6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad",
"topic_name": "readme-example-topic",
"updated_by": "none"
}
Human Readable Output
Custom Topic Updated
Topic Id Topic Name Revision Active Description Updated By 6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad readme-example-topic 2 true Updated example custom topic none
prisma-airs-runtime-topics-delete
Delete a custom topic. WARNING - This action cannot be undone. Fails if topic is referenced by any security profile (use force to override).
Note: The force-delete endpoint (
.../topic/force/{id}) currently returns HTTP 403 (Access denied) on tenants where the OAuth client has not been granted the force-delete permission. Regular delete and the force request path are both validated; force-delete succeeds once the tenant grants the permission.
Base Command
prisma-airs-runtime-topics-delete
Input
| Argument Name | Description | Required |
|---|---|---|
| topic_id | The topic UUID to delete. | Required |
| force | Whether to force-delete the topic, removing it from any referencing profiles. Possible values are: true, false. Default is false. | Optional |
| updated_by | The email of the user performing the deletion. Optional for force-delete. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.TopicDeleted.topic_id | String | The deleted topic ID. |
| PrismaAIRs.TopicDeleted.message | String | The deletion confirmation message. |
| PrismaAIRs.TopicDeleted.deleted | Boolean | The boolean indicating successful deletion. |
| PrismaAIRs.TopicDeleted.force | Boolean | Whether the topic was force-deleted. |
Command example
!prisma-airs-runtime-topics-delete topic_id=${PrismaAIRs.TopicCreate.topic_id}
Context Example
{
"deleted": true,
"message": "successfully deleted topicId: 6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad",
"topic_id": "6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad"
}
Human Readable Output
Custom Topic Deleted
Topic Id Message Deleted Force 6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad successfully deleted topicId: 6d62aa1f-4457-4eb5-afb1-7cde3d3bc0ad true false ⚠️ WARNING: This action cannot be undone. The custom topic has been permanently deleted.
prisma-airs-runtime-topics-apply
Apply a topic to a security profile (additive - preserves existing topics). This command orchestrates multiple API calls to assign a custom topic to a profile’s topic-guardrails configuration.
Base Command
prisma-airs-runtime-topics-apply
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_name | The security profile name to apply the topic to. | Required |
| topic_name | The topic name to apply. The topic must already exist (create with prisma-airs-runtime-topics-create). | Required |
| action | The topic action. ‘block’ = block prompts matching this topic. ‘allow’ = allow prompts matching this topic. Possible values are: allow, block. Default is block. | Optional |
| guardrail_action | The guardrail-level default action. ‘block’ = block all unless explicitly allowed (requires allow topics). ‘allow’ = allow all unless explicitly blocked (only block topics needed). Possible values are: allow, block. Default is block. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.TopicApplied.profile_name | String | The security profile name. |
| PrismaAIRs.TopicApplied.profile_id | String | The security profile UUID. |
| PrismaAIRs.TopicApplied.topic_name | String | The topic name that was applied. |
| PrismaAIRs.TopicApplied.topic_id | String | The topic UUID. |
| PrismaAIRs.TopicApplied.topic_revision | Number | The topic revision number (pinned to ensure consistent detection). |
| PrismaAIRs.TopicApplied.action | String | The topic action (allow or block). |
| PrismaAIRs.TopicApplied.guardrail_action | String | The guardrail-level default action. |
| PrismaAIRs.TopicApplied.applied | Boolean | The boolean indicating successful application. |
prisma-airs-runtime-bulk-scan
Perform bulk scanning of multiple prompts.
Base Command
prisma-airs-runtime-bulk-scan
Input
| Argument Name | Description | Required |
|---|---|---|
| profile_name | The security profile name to use for scanning. | Required |
| prompts_csv | The CSV content with prompts to scan (must include ‘prompt’ column header, or use newline-separated format). | Required |
| session_id | The optional session ID for grouping scans in AIRS dashboard. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| PrismaAIRs.BulkScan.profile_name | String | The security profile used. |
| PrismaAIRs.BulkScan.session_id | String | The session ID. |
| PrismaAIRs.BulkScan.total | Number | The total prompts scanned. |
| PrismaAIRs.BulkScan.blocked | Number | The number of prompts blocked. |
| PrismaAIRs.BulkScan.allowed | Number | The number of prompts allowed. |
| PrismaAIRs.BulkScan.errors | Number | The number of scan errors. |
| PrismaAIRs.BulkScan.results | Unknown | The array of individual scan results. |
Configuration parameters
url— Server URL (required)credentials— API Client ID (required)runtime_api_key— Runtime API Key (required)tsg_id— Tenant Services Group ID (required)scanner_base_url— Scanner API Base URLdlp_base_url— DLP API Base URLinsecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (45)
-
prisma-airs-runtime-api-keys-createCreate a new Runtime API Key. WARNING - The full API key secret is only shown once during creation. Save it securely.
-
prisma-airs-runtime-api-keys-deleteDelete a Runtime API Key by name. WARNING - This action cannot be undone and immediately revokes access for all applications using this key.
-
prisma-airs-runtime-api-keys-listList all Runtime API Keys configured in Prisma AIRs.
-
prisma-airs-runtime-api-keys-regenerateRegenerate an existing Runtime API Key. WARNING - This creates a NEW key with a NEW UUID and invalidates the old key. The new secret is only shown once.
-
prisma-airs-runtime-bulk-scanPerform bulk scanning of multiple prompts.
-
prisma-airs-runtime-customer-apps-consumptionGet per-application token consumption and session statistics over the requested time window.
-
prisma-airs-runtime-customer-apps-deleteDelete a customer application and all associated API keys. WARNING - This action cannot be undone and immediately revokes all API keys for this application.
-
prisma-airs-runtime-customer-apps-getGet customer application details by name.
-
prisma-airs-runtime-customer-apps-listList all customer applications.
-
prisma-airs-runtime-customer-apps-updateUpdate a customer application configuration.
-
prisma-airs-runtime-customer-apps-violationsGet per-detector violation severity breakdown for an application over the requested time window.
-
prisma-airs-runtime-deployment-profiles-listList all deployment profiles.
-
prisma-airs-runtime-dlp-dictionaries-createCreate a new DLP dictionary by uploading a keyword file.
-
prisma-airs-runtime-dlp-dictionaries-deleteDelete a DLP dictionary. This action cannot be undone.
-
prisma-airs-runtime-dlp-dictionaries-getGet a single DLP dictionary by ID, optionally including keywords.
-
prisma-airs-runtime-dlp-dictionaries-listList DLP dictionaries.
-
prisma-airs-runtime-dlp-dictionaries-patchPartially update a DLP dictionary (JSON Merge Patch). Fields set to "null" will be cleared.
-
prisma-airs-runtime-dlp-dictionaries-replaceReplace (full update) a DLP dictionary by uploading a new keyword file.
-
prisma-airs-runtime-dlp-filtering-profiles-getGet a single DLP filtering profile by ID.
-
prisma-airs-runtime-dlp-filtering-profiles-listList DLP filtering profiles.
-
prisma-airs-runtime-dlp-filtering-profiles-replaceReplace (full update) a DLP filtering profile. This is a destructive operation that replaces the entire profile configuration.
-
prisma-airs-runtime-dlp-patterns-createCreate a new DLP data pattern.
-
prisma-airs-runtime-dlp-patterns-deleteDelete (soft-delete/archive) a DLP data pattern. This action cannot be undone.
-
prisma-airs-runtime-dlp-patterns-getGet a single DLP data pattern by ID.
-
prisma-airs-runtime-dlp-patterns-listList DLP data patterns.
-
prisma-airs-runtime-dlp-patterns-patchPartially update a DLP data pattern (JSON Merge Patch). Fields set to "null" will be cleared.
-
prisma-airs-runtime-dlp-patterns-replaceReplace (full update) a DLP data pattern. This replaces the entire pattern configuration.
-
prisma-airs-runtime-dlp-profiles-createCreate a new DLP data profile with detection rules.
-
prisma-airs-runtime-dlp-profiles-deleteSoft-delete a DLP data profile. The DLP API has no DELETE endpoint, so the profile is patched to a deleted lifecycle state (profile_status="deleted"). The command first fetches the profile to obtain its name and profile_type (required by the merge-patch). This action cannot be undone.
-
prisma-airs-runtime-dlp-profiles-getGet a single DLP data profile by ID.
-
prisma-airs-runtime-dlp-profiles-listList all DLP data profiles (v2 API).
-
prisma-airs-runtime-dlp-profiles-patchPartially update a DLP data profile (JSON Merge Patch). Fields set to "null" will be cleared.
-
prisma-airs-runtime-dlp-profiles-replaceReplace (full update) a DLP data profile. This replaces the entire profile configuration.
-
prisma-airs-runtime-profiles-createCreate a new security profile with custom policy configuration.
-
prisma-airs-runtime-profiles-deleteDelete a security profile. WARNING - This action cannot be undone and permanently removes the profile.
-
prisma-airs-runtime-profiles-getGet a specific security profile by ID or name. Returns the highest-revision profile if filtering by name.
-
prisma-airs-runtime-profiles-listList all runtime security profiles.
-
prisma-airs-runtime-profiles-updateUpdate an existing security profile. WARNING - Modifying profile configuration can break scanning if misconfigured.
-
prisma-airs-runtime-scanScan a single prompt against a security profile for AI security threats.
-
prisma-airs-runtime-topics-applyApply a topic to a security profile (additive - preserves existing topics). This command orchestrates multiple API calls to assign a custom topic to a profile's topic-guardrails configuration.
-
prisma-airs-runtime-topics-createCreate a new custom topic guardrail with examples for detection.
-
prisma-airs-runtime-topics-deleteDelete a custom topic. WARNING - This action cannot be undone. Fails if topic is referenced by any security profile (use force to override).
-
prisma-airs-runtime-topics-getGet a specific custom topic by ID or name.
-
prisma-airs-runtime-topics-listList custom topic guardrails.
-
prisma-airs-runtime-topics-updateUpdate an existing custom topic. WARNING - Modifying topic definition can break detection if misconfigured.
import demistomock as demisto from CommonServerPython import * # noqa # pylint: disable=unused-wildcard-import from CommonServerUserPython import * # noqa from PrismaAirsApiModule import * # noqa # pylint: disable=unused-wildcard-import import urllib3 from typing import Any # Disable insecure warnings urllib3.disable_warnings() # CONSTANTS (Runtime + DLP specific; shared constants come from PrismaAirsApiModule) # Management API v1 path prefix (appended after MGMT_API_PATH). MGMT_API_V1_PREFIX = "/v1/mgmt" # DLP API path suffixes (v2 API) - uses the separate DLP base URL (see PrismaAirsApiModule). # Reference: ./knowledge/prisma-airs-sdk-main/src/constants.ts DLP_DICTIONARIES_PATH = "/v2/api/dictionaries" DLP_PATTERNS_PATH = "/v2/api/data-patterns" DLP_FILTERING_PROFILES_PATH = "/v2/api/data-filtering-profiles" DLP_DATA_PROFILES_PATH = "/v2/api/data-profiles" def runtime_scan_command(client: Client, args: dict[str, Any]) -> CommandResults: """Scan a prompt against a security profile. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_name = args.get("profile_name") prompt = args.get("prompt") response_text = args.get("response") # Optional metadata fields (per scan-sync-request.md docs) tr_id = args.get("tr_id") session_id = args.get("session_id") app_name = args.get("app_name") app_user = args.get("app_user") ai_model = args.get("ai_model") user_ip = args.get("user_ip") agent_id = args.get("agent_id") agent_version = args.get("agent_version") agent_arn = args.get("agent_arn") if not profile_name or not prompt: raise ValueError("profile_name and prompt are required arguments") # Build scanner API request # Reference: ./knowledge/docs/Prisma_AIRs_airuntime/scans/scan-sync-request.md content: dict[str, str] = {"prompt": prompt} if response_text: content["response"] = response_text scan_request: dict[str, Any] = {"ai_profile": {"profile_name": profile_name}, "contents": [content]} # Add optional top-level metadata fields if tr_id: scan_request["tr_id"] = tr_id if session_id: scan_request["session_id"] = session_id # Build metadata object if any metadata fields are provided metadata: dict[str, Any] = {} if app_name: metadata["app_name"] = app_name if app_user: metadata["app_user"] = app_user if ai_model: metadata["ai_model"] = ai_model if user_ip: metadata["user_ip"] = user_ip # Build agent_meta nested object agent_meta: dict[str, str] = {} if agent_id: agent_meta["agent_id"] = agent_id if agent_version: agent_meta["agent_version"] = agent_version if agent_arn: agent_meta["agent_arn"] = agent_arn if agent_meta: metadata["agent_meta"] = agent_meta if metadata: scan_request["metadata"] = metadata # Call Prisma AIRs scanner API scan_response = client.scanner_request(scan_request) # Parse detections for both prompt and response # Forward-compatible: capture all fields from API response prompt_detected = scan_response.get("prompt_detected", {}) response_detected = scan_response.get("response_detected", {}) # Check if ANY detection occurred across prompt or response prompt_has_detections = any(prompt_detected.values()) if prompt_detected else False response_has_detections = any(response_detected.values()) if response_detected else False overall_detected = prompt_has_detections or response_has_detections # Build scan result with all top-level fields from API response # Forward-compatible: include all fields from scan_response scan_result = { "prompt": prompt, "response": response_text, "scan_id": scan_response.get("scan_id", ""), "report_id": scan_response.get("report_id", ""), "action": scan_response.get("action", "unknown"), "category": scan_response.get("category", "unknown"), "detected": overall_detected, "prompt_detected": prompt_detected, # Include full prompt_detected object "response_detected": response_detected, # Include full response_detected object } # Add optional metadata fields from response if present (forward-compatible) if scan_response.get("tr_id"): scan_result["tr_id"] = scan_response["tr_id"] if scan_response.get("session_id"): scan_result["session_id"] = scan_response["session_id"] if scan_response.get("profile_id"): scan_result["profile_id"] = scan_response["profile_id"] if scan_response.get("profile_name"): scan_result["profile_name"] = scan_response["profile_name"] if scan_response.get("source"): scan_result["source"] = scan_response["source"] if scan_response.get("timeout"): scan_result["timeout"] = scan_response["timeout"] if scan_response.get("error"): scan_result["error"] = scan_response["error"] if scan_response.get("errors"): scan_result["errors"] = scan_response["errors"] # Create human-readable output using table format scan_summary = [ { "Scan ID": scan_result["scan_id"], "Report ID": scan_result["report_id"], "Profile": profile_name, "Action": scan_result["action"].upper(), "Category": scan_result["category"], "Detected": "Yes" if overall_detected else "No", } ] # Add metadata table if any metadata fields are present metadata_table = [] if scan_result.get("tr_id"): metadata_table.append({"Field": "Transaction ID", "Value": scan_result["tr_id"]}) if scan_result.get("session_id"): metadata_table.append({"Field": "Session ID", "Value": scan_result["session_id"]}) # Build prompt detections table (forward-compatible: dynamically handle all detection fields) prompt_detections_table = [] if prompt_detected: for detection_type, detected_value in prompt_detected.items(): prompt_detections_table.append( {"Detection Type": detection_type.replace("_", " ").title(), "Detected": "Yes" if detected_value else "No"} ) # Build response detections table (forward-compatible: dynamically handle all detection fields) response_detections_table = [] if response_detected: for detection_type, detected_value in response_detected.items(): response_detections_table.append( {"Detection Type": detection_type.replace("_", " ").title(), "Detected": "Yes" if detected_value else "No"} ) # Build scanned content table content_table = [ { "Type": "Prompt", "Content": prompt[:100] + "..." if len(prompt) > 100 else prompt, "Threats Detected": "Yes" if prompt_has_detections else "No", } ] if response_text: content_table.append( { "Type": "Response", "Content": response_text[:100] + "..." if len(response_text) > 100 else response_text, "Threats Detected": "Yes" if response_has_detections else "No", } ) # Build readable output readable_output = "## Prisma AIRs Runtime Scan Results\n\n" readable_output += tableToMarkdown( "Scan Summary", scan_summary, headers=["Scan ID", "Report ID", "Profile", "Action", "Category", "Detected"] ) readable_output += "\n" # Add metadata table if present if metadata_table: readable_output += tableToMarkdown("Metadata", metadata_table, headers=["Field", "Value"]) readable_output += "\n" # Scanned content first to show what was scanned readable_output += tableToMarkdown("Scanned Content", content_table, headers=["Type", "Content", "Threats Detected"]) readable_output += "\n" # Prompt detections (if any) if prompt_detections_table: readable_output += tableToMarkdown("Prompt Detections", prompt_detections_table, headers=["Detection Type", "Detected"]) readable_output += "\n" # Response detections (if any) if response_detections_table: readable_output += tableToMarkdown( "Response Detections", response_detections_table, headers=["Detection Type", "Detected"] ) readable_output += "\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}RuntimeScan", outputs_key_field="scan_id", outputs=scan_result, readable_output=readable_output, raw_response=scan_response, ) def runtime_api_keys_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List Runtime API Keys. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) # Call Management API to list API keys # Reference: ./knowledge/prisma-airs-sdk-main/src/management/api-keys.ts # SDK path: /v1/mgmt/apikeys/tsg/{tsgId} # SDK uses offset for pagination, but we'll use limit for simplicity url_suffix = f"{MGMT_API_V1_PREFIX}/apikeys/tsg/{client.tsg_id}" params = {"offset": "0", "limit": str(limit) if limit else "100"} response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK returns snake_case field names api_keys_raw = response.get("api_keys", []) api_keys = [] for key in api_keys_raw: api_key_info = { "id": key.get("api_key_id"), "name": key.get("api_key_name"), "last8": key.get("api_key_last8"), "created_at": key.get("created_at"), "expires_at": key.get("expiration"), "revoked": key.get("revoked"), } api_keys.append(api_key_info) readable_output = tableToMarkdown( "Prisma AIRs Runtime API Keys", api_keys, headers=["id", "name", "last8", "created_at", "expires_at", "revoked"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}ApiKey", outputs_key_field="id", outputs=api_keys, readable_output=readable_output, raw_response=response, ) def runtime_api_keys_create_command(client: Client, args: dict[str, Any]) -> CommandResults: """Create a new Runtime API Key. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR with the full API key secret. """ # Required arguments api_key_name = args.get("api_key_name") auth_code = args.get("auth_code") cust_app = args.get("cust_app") rotation_time_interval = arg_to_number(args.get("rotation_time_interval")) rotation_time_unit = args.get("rotation_time_unit") created_by = args.get("created_by") # cust_env and cust_cloud_provider are optional in the APIKeyCreationObject schema, but the # customer app record created as a side effect REQUIRES environment and cloud_provider. Omitting # them yields an opaque HTTP 400 "Error inserting/updating customer app record", so require them here. cust_env = args.get("cust_env") cust_cloud_provider = args.get("cust_cloud_provider") if not api_key_name: raise ValueError("api_key_name is required") if not auth_code: raise ValueError("auth_code is required") if not cust_app: raise ValueError("cust_app is required") if not rotation_time_interval: raise ValueError("rotation_time_interval is required") if not rotation_time_unit: raise ValueError("rotation_time_unit is required (hours, days, or months)") if not created_by: raise ValueError("created_by is required") if not cust_env: raise ValueError("cust_env is required (the customer app record mandates an environment value)") if not cust_cloud_provider: raise ValueError("cust_cloud_provider is required (the customer app record mandates a cloud provider value)") # Validate rotation_time_unit valid_units = ["hours", "days", "months"] if rotation_time_unit not in valid_units: raise ValueError(f"rotation_time_unit must be one of: {', '.join(valid_units)}") # Build request body according to ApiKeyCreateRequestSchema # Reference: ./knowledge/prisma-airs-sdk-main/src/models/mgmt-api-key.ts # Required by API schema: auth_code, cust_app, revoked, created_by, api_key_name, # rotation_time_interval, rotation_time_unit # Required in practice (customer app record mandates them): cust_env, cust_cloud_provider # Optional: dp_name, cust_ai_agent_framework request_body = { "api_key_name": api_key_name, "auth_code": auth_code, "cust_app": cust_app, "created_by": created_by, "revoked": False, # Always create as not revoked "rotation_time_interval": rotation_time_interval, "rotation_time_unit": rotation_time_unit, "cust_env": cust_env, "cust_cloud_provider": cust_cloud_provider, } # Add optional fields if provided optional_fields = { "dp_name": args.get("dp_name"), "cust_ai_agent_framework": args.get("cust_ai_agent_framework"), } for field, value in optional_fields.items(): if value: request_body[field] = value # Call Management API to create API key # SDK: ./knowledge/prisma-airs-sdk-main/src/management/api-keys.ts (create method) # Endpoint: POST /v1/mgmt/apikey (singular; matches OpenAPI operationId CreateNewAPIKey and SDK MGMT_API_KEY_PATH) # Response: ApiKeySchema with full secret (only time it's shown) url_suffix = f"{MGMT_API_V1_PREFIX}/apikey" response = client.http_request(method="POST", url_suffix=url_suffix, json_data=request_body, use_mgmt_base=True) # Parse response according to ApiKeySchema # Fields: api_key_id, api_key_name, api_key (full secret - only shown once!), # api_key_last8, auth_code, expiration, revoked # Optional: created_at, updated_at, created_by, cust_app, etc. api_key_info = { "id": response.get("api_key_id"), "name": response.get("api_key_name"), "api_key": response.get("api_key"), # FULL SECRET - only shown on create/regenerate "last8": response.get("api_key_last8"), "auth_code": response.get("auth_code"), "expires_at": response.get("expiration"), "revoked": response.get("revoked"), "created_at": response.get("created_at"), "created_by": response.get("created_by"), "cust_app": response.get("cust_app"), } # Add optional fields if present optional_response_fields = [ "updated_at", "updated_by", "cust_env", "cust_cloud_provider", "cust_ai_agent_framework", "dp_name", ] for field in optional_response_fields: if response.get(field): api_key_info[field] = response.get(field) # Create readable output with WARNING about secret readable_output = tableToMarkdown( "API Key Created", api_key_info, headers=["id", "name", "api_key", "last8", "expires_at", "created_by"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += ( "\n\n**⚠️ IMPORTANT:** This is the ONLY time the full API key secret will be shown. " "Save it securely now. Future API calls will only show the last 8 characters." ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}ApiKeyCreate", outputs_key_field="id", outputs=api_key_info, readable_output=readable_output, raw_response=response, ) def runtime_api_keys_regenerate_command(client: Client, args: dict[str, Any]) -> CommandResults: """Regenerate an existing Runtime API Key. This creates a NEW key with a NEW UUID and invalidates the old key. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR with the new API key secret. """ # Required arguments api_key_id = args.get("api_key_id") rotation_time_interval = arg_to_number(args.get("rotation_time_interval")) rotation_time_unit = args.get("rotation_time_unit") if not api_key_id: raise ValueError("api_key_id is required") if not rotation_time_interval: raise ValueError("rotation_time_interval is required") if not rotation_time_unit: raise ValueError("rotation_time_unit is required (hours, days, or months)") # Validate rotation_time_unit valid_units = ["hours", "days", "months"] if rotation_time_unit not in valid_units: raise ValueError(f"rotation_time_unit must be one of: {', '.join(valid_units)}") # Build request body according to ApiKeyRegenerateRequestSchema # Reference: ./knowledge/prisma-airs-sdk-main/src/models/mgmt-api-key.ts # Required: rotation_time_interval, rotation_time_unit # Optional: updated_by request_body = {"rotation_time_interval": rotation_time_interval, "rotation_time_unit": rotation_time_unit} # Add optional updated_by if provided updated_by = args.get("updated_by") if updated_by: request_body["updated_by"] = updated_by # Call Management API to regenerate API key # SDK: ./knowledge/prisma-airs-sdk-main/src/management/api-keys.ts (regenerate method) # Endpoint: POST /v1/mgmt/apikey/regenerate/{apiKeyId} (singular path + POST; matches OpenAPI RegenerateAPIKeyById and SDK) # Response: ApiKeySchema with NEW UUID and NEW full secret url_suffix = f"{MGMT_API_V1_PREFIX}/apikey/regenerate/{api_key_id}" response = client.http_request(method="POST", url_suffix=url_suffix, json_data=request_body, use_mgmt_base=True) # Parse response according to ApiKeySchema # IMPORTANT: Returns NEW api_key_id and NEW api_key (full secret) # The old key is invalidated api_key_info = { "id": response.get("api_key_id"), # NEW UUID "name": response.get("api_key_name"), "api_key": response.get("api_key"), # NEW FULL SECRET "last8": response.get("api_key_last8"), "auth_code": response.get("auth_code"), "expires_at": response.get("expiration"), "revoked": response.get("revoked"), "updated_at": response.get("updated_at"), "updated_by": response.get("updated_by"), "cust_app": response.get("cust_app"), } # Add optional fields if present optional_response_fields = [ "created_at", "created_by", "cust_env", "cust_cloud_provider", "cust_ai_agent_framework", "dp_name", ] for field in optional_response_fields: if response.get(field): api_key_info[field] = response.get(field) # Create readable output with WARNING about new secret and old key invalidation readable_output = tableToMarkdown( "API Key Regenerated", api_key_info, headers=["id", "name", "api_key", "last8", "expires_at", "updated_by"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += ( "\n\n**⚠️ IMPORTANT:**\n\n" "1. The OLD API key has been INVALIDATED and will no longer work\n" "2. This is the ONLY time the NEW full API key secret will be shown\n" "3. Update all applications using the old key with this new key\n" "4. The API key ID has changed - use the new ID for future operations" ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}ApiKeyRegenerate", outputs_key_field="id", outputs=api_key_info, readable_output=readable_output, raw_response=response, ) def runtime_api_keys_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Delete a Runtime API Key by name. This permanently deletes the API key and revokes access immediately. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR with deletion confirmation. """ # Required arguments api_key_name = args.get("api_key_name") updated_by = args.get("updated_by") if not api_key_name: raise ValueError("api_key_name is required") if not updated_by: raise ValueError("updated_by is required (email of user performing deletion)") # Call Management API to delete API key # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/api-keys.ts # SDK: ApiKeysClient.delete(apiKeyName, updatedBy) # Endpoint: DELETE /v1/mgmt/apikey/delete/{apiKeyName}?updated_by={email} # Response: { message: "deleted" } (or plain string that gets transformed) url_suffix = f"{MGMT_API_V1_PREFIX}/apikey/delete/{api_key_name}" params = {"updated_by": updated_by} response = client.http_request(method="DELETE", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK handles both string and object responses # ApiKeyDeleteResponseSchema transforms plain string to { message: "..." } # Response: { message: "deleted" } or { message: "successfully deleted apiKeyName: <name>" } message = response.get("message", "API key deleted successfully") if isinstance(response, dict) else str(response) # Context output context_output = {"api_key_name": api_key_name, "deleted_by": updated_by, "message": message, "deleted": True} # Create readable output with deletion confirmation readable_output = tableToMarkdown( "API Key Deleted", context_output, headers=["api_key_name", "deleted_by", "message", "deleted"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += "\n\n**⚠️ WARNING:** This action cannot be undone. The API key has been permanently revoked." return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}ApiKeyDeleted", outputs_key_field="api_key_name", outputs=context_output, readable_output=readable_output, raw_response=response, ) def runtime_profiles_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List runtime security profiles. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) # Call Management API to list security profiles # Reference: ./knowledge/prisma-airs-sdk-main/src/management/profiles.ts # SDK path: /v1/mgmt/profiles/tsg/{tsgId} url_suffix = f"{MGMT_API_V1_PREFIX}/profiles/tsg/{client.tsg_id}" params = {"offset": "0", "limit": str(limit) if limit else "100"} response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK returns ai_profiles array # Schema: profile_id, profile_name, revision, active, created_by, updated_by, last_modified_ts profiles_raw = response.get("ai_profiles", []) profiles = [] for profile in profiles_raw: profile_info = { "id": profile.get("profile_id"), "name": profile.get("profile_name"), "revision": profile.get("revision"), "active": profile.get("active"), "created_by": profile.get("created_by"), "updated_by": profile.get("updated_by"), "last_modified_ts": profile.get("last_modified_ts"), "tsg_id": profile.get("tsg_id"), } profiles.append(profile_info) readable_output = tableToMarkdown( "Prisma AIRs Security Profiles", profiles, headers=["id", "name", "revision", "active", "created_by", "updated_by", "last_modified_ts"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}SecurityProfile", outputs_key_field="id", outputs=profiles, readable_output=readable_output, raw_response=response, ) def runtime_profiles_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get a specific security profile by ID or name. Note: There is no dedicated GET endpoint - this fetches all profiles and filters. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") profile_name = args.get("profile_name") if not profile_id and not profile_name: raise ValueError("Either profile_id or profile_name is required") # Call Management API to list all profiles, then filter # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/profiles.ts # SDK: ProfilesClient.get(profileId) or getByName(profileName) # Note: No dedicated GET endpoint exists - SDK fetches all and filters url_suffix = f"{MGMT_API_V1_PREFIX}/profiles/tsg/{client.tsg_id}" params = { "offset": "0", "limit": "1000", # Get all profiles for filtering } response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response and filter profiles_raw = response.get("ai_profiles", []) # Filter by ID or name if profile_id: matches = [p for p in profiles_raw if p.get("profile_id") == profile_id] search_key = f"ID: {profile_id}" else: # Filter by name and get highest revision (SDK behavior) matches = [p for p in profiles_raw if p.get("profile_name") == profile_name] if len(matches) > 1: # Return highest revision matches = [max(matches, key=lambda p: p.get("revision", 0))] search_key = f"Name: {profile_name}" if not matches: raise ValueError(f"Profile not found: {search_key}") profile = matches[0] # Extract full profile details including policy profile_info = { "id": profile.get("profile_id"), "name": profile.get("profile_name"), "revision": profile.get("revision"), "active": profile.get("active"), "policy": profile.get("policy"), # Full policy object "created_by": profile.get("created_by"), "updated_by": profile.get("updated_by"), "last_modified_ts": profile.get("last_modified_ts"), "tsg_id": profile.get("tsg_id"), "csp_id": profile.get("csp_id"), } # Create readable output readable_output = tableToMarkdown( f"Security Profile: {profile_info.get('name')}", profile_info, headers=["id", "name", "revision", "active", "created_by", "updated_by", "last_modified_ts"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Add policy summary if present if profile_info.get("policy"): policy = profile_info["policy"] ai_profiles_count = len(policy.get("ai-security-profiles", [])) dlp_profiles_count = len(policy.get("dlp-data-profiles", [])) readable_output += "\n\n**Policy:**\n\n" readable_output += f"- AI Security Profiles: {ai_profiles_count}\n" readable_output += f"- DLP Data Profiles: {dlp_profiles_count}\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}SecurityProfileGet", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=profile, ) def runtime_profiles_create_command(client: Client, args: dict[str, Any]) -> CommandResults: """Create a new security profile. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_name = args.get("profile_name") active = argToBoolean(args.get("active", True)) policy_json = args.get("policy") if not profile_name: raise ValueError("profile_name is required") # Build request body according to CreateSecurityProfileRequest # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/models/mgmt-security-profile.ts # Required: profile_name, active, policy request_body: dict[str, Any] = {"profile_name": profile_name, "active": active} # Parse policy JSON if provided if policy_json: try: import json policy = json.loads(policy_json) request_body["policy"] = policy except json.JSONDecodeError as e: raise ValueError(f"Invalid policy JSON: {str(e)}") else: # Default empty policy request_body["policy"] = {"ai-security-profiles": [], "dlp-data-profiles": []} # Call Management API to create profile # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/profiles.ts # SDK: ProfilesClient.create(body) # Endpoint: POST /v1/mgmt/profile url_suffix = f"{MGMT_API_V1_PREFIX}/profile" response = client.http_request(method="POST", url_suffix=url_suffix, json_data=request_body, use_mgmt_base=True) # Parse response - returns full SecurityProfile profile_info = { "id": response.get("profile_id"), "name": response.get("profile_name"), "revision": response.get("revision"), "active": response.get("active"), "policy": response.get("policy"), "created_by": response.get("created_by"), "updated_by": response.get("updated_by"), "last_modified_ts": response.get("last_modified_ts"), "tsg_id": response.get("tsg_id"), "csp_id": response.get("csp_id"), } # Create readable output readable_output = tableToMarkdown( "Security Profile Created", profile_info, headers=["id", "name", "revision", "active", "created_by"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Add policy summary if profile_info.get("policy"): policy = profile_info["policy"] ai_profiles_count = len(policy.get("ai-security-profiles", [])) dlp_profiles_count = len(policy.get("dlp-data-profiles", [])) readable_output += "\n\n**Policy:**\n\n" readable_output += f"- AI Security Profiles: {ai_profiles_count}\n" readable_output += f"- DLP Data Profiles: {dlp_profiles_count}\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}SecurityProfileCreate", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_profiles_update_command(client: Client, args: dict[str, Any]) -> CommandResults: """Update an existing security profile. WARNING: This modifies the profile configuration and can break scanning if misconfigured. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") profile_name = args.get("profile_name") active = args.get("active") policy_json = args.get("policy") if not profile_id: raise ValueError("profile_id is required") if not profile_name: raise ValueError("profile_name is required") # Build request body according to CreateSecurityProfileRequest # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/models/mgmt-security-profile.ts # Required: profile_name, active, policy request_body: dict[str, Any] = {"profile_name": profile_name} # Add active if provided if active is not None: request_body["active"] = argToBoolean(active) # Parse policy JSON if provided if policy_json: try: import json policy = json.loads(policy_json) request_body["policy"] = policy except json.JSONDecodeError as e: raise ValueError(f"Invalid policy JSON: {str(e)}") # Call Management API to update profile # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/profiles.ts # SDK: ProfilesClient.update(profileId, body) # Endpoint: PUT /v1/mgmt/profile/uuid/{profileId} url_suffix = f"{MGMT_API_V1_PREFIX}/profile/uuid/{profile_id}" response = client.http_request(method="PUT", url_suffix=url_suffix, json_data=request_body, use_mgmt_base=True) # Parse response - returns updated SecurityProfile with incremented revision profile_info = { "id": response.get("profile_id"), "name": response.get("profile_name"), "revision": response.get("revision"), # Incremented "active": response.get("active"), "policy": response.get("policy"), "created_by": response.get("created_by"), "updated_by": response.get("updated_by"), "last_modified_ts": response.get("last_modified_ts"), "tsg_id": response.get("tsg_id"), "csp_id": response.get("csp_id"), } # Create readable output readable_output = tableToMarkdown( "Security Profile Updated", profile_info, headers=["id", "name", "revision", "active", "updated_by", "last_modified_ts"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Add policy summary if profile_info.get("policy"): policy = profile_info["policy"] ai_profiles_count = len(policy.get("ai-security-profiles", [])) dlp_profiles_count = len(policy.get("dlp-data-profiles", [])) readable_output += "\n\n**Policy:**\n\n" readable_output += f"- AI Security Profiles: {ai_profiles_count}\n" readable_output += f"- DLP Data Profiles: {dlp_profiles_count}\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}SecurityProfileUpdate", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_profiles_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Delete a security profile. WARNING: This permanently deletes the security profile. This action cannot be undone. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") force = argToBoolean(args.get("force", False)) updated_by = args.get("updated_by") # Call Management API to delete profile # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/profiles.ts # Response: { message: "deleted" } (or plain string transformed to object) if force: # SDK: ProfilesClient.forceDelete(profileId, updatedBy) # Endpoint: DELETE /v1/mgmt/profile/{profileId}/force?updated_by=... # Force-delete bypasses safety checks; the force endpoint requires updated_by. if not updated_by: raise ValueError("updated_by is required when force is true") url_suffix = f"{MGMT_API_V1_PREFIX}/profile/{profile_id}/force" response = client.http_request( method="DELETE", url_suffix=url_suffix, params={"updated_by": updated_by}, use_mgmt_base=True ) else: # SDK: ProfilesClient.delete(profileId) # Endpoint: DELETE /v1/mgmt/profile/{profileId} url_suffix = f"{MGMT_API_V1_PREFIX}/profile/{profile_id}" response = client.http_request(method="DELETE", url_suffix=url_suffix, use_mgmt_base=True) # Parse response - SDK handles both string and object responses # DeleteProfileResponseSchema transforms plain string to { message: "..." } default_message = "Security profile force-deleted successfully" if force else "Security profile deleted successfully" message = response.get("message", default_message) if isinstance(response, dict) else str(response) # Create readable output # Context output context_output = {"profile_id": profile_id, "message": message, "deleted": True, "force": force} readable_output = tableToMarkdown( "Security Profile Force-Deleted" if force else "Security Profile Deleted", context_output, headers=["profile_id", "message", "deleted", "force"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += "\n\n**⚠️ WARNING:** This action cannot be undone. The security profile has been permanently deleted." return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}SecurityProfileDeleted", outputs_key_field="profile_id", outputs=context_output, readable_output=readable_output, raw_response=response, ) def runtime_customer_apps_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List customer applications. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) # Call Management API to list customer apps # Reference: ./knowledge/prisma-airs-sdk-main/src/management/customer-apps.ts # SDK path: /v1/mgmt/customerapp/tsg/{tsgId} url_suffix = f"{MGMT_API_V1_PREFIX}/customerapp/tsg/{client.tsg_id}" params = {"offset": "0", "limit": str(limit) if limit else "100"} response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK schema: customer_appId, app_name, model_name, cloud_provider, environment apps_raw = response.get("customer_apps", []) apps = [] for app in apps_raw: app_info = { "id": app.get("customer_appId"), "name": app.get("app_name"), "model_name": app.get("model_name"), "cloud_provider": app.get("cloud_provider"), "environment": app.get("environment"), "ai_agent_framework": app.get("ai_agent_framework"), "tsg_id": app.get("tsg_id"), } apps.append(app_info) readable_output = tableToMarkdown( "Prisma AIRs Customer Applications", apps, headers=["id", "name", "model_name", "cloud_provider", "environment", "ai_agent_framework"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}CustomerApp", outputs_key_field="id", outputs=apps, readable_output=readable_output, raw_response=response, ) def runtime_customer_apps_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get customer application details by name. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ app_name = args.get("app_name") if not app_name: raise ValueError("app_name is required") # Call Management API to get customer app details # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/customer-apps.ts # SDK: CustomerAppsClient.get(appName) # Endpoint: GET /v1/mgmt/customerapp?app_name={appName} url_suffix = f"{MGMT_API_V1_PREFIX}/customerapp" params = {"app_name": app_name} response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK schema (mgmt-customer-app.ts): CustomerAppSchema # Fields: customer_appId, tsg_id, app_name, model_name, cloud_provider, environment, # status, created_by, updated_by, ai_agent_framework app_info = { "id": response.get("customer_appId"), "name": response.get("app_name"), "model_name": response.get("model_name"), "cloud_provider": response.get("cloud_provider"), "environment": response.get("environment"), "ai_agent_framework": response.get("ai_agent_framework"), "tsg_id": response.get("tsg_id"), "status": response.get("status"), "created_by": response.get("created_by"), "updated_by": response.get("updated_by"), } readable_output = tableToMarkdown( f"Customer Application: {app_name}", [app_info], headers=[ "id", "name", "model_name", "cloud_provider", "environment", "ai_agent_framework", "status", "created_by", "updated_by", ], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}CustomerAppGet", outputs_key_field="id", outputs=app_info, readable_output=readable_output, raw_response=response, ) def runtime_customer_apps_update_command(client: Client, args: dict[str, Any]) -> CommandResults: """Update a customer application. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ customer_app_id = args.get("customer_app_id") if not customer_app_id: raise ValueError("customer_app_id is required") # Build request body from arguments # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/models/mgmt-customer-app.ts # SDK: CustomerAppSchema - tsg_id, app_name, model_name (optional), cloud_provider, # environment, ai_agent_framework (optional) request_body: dict[str, Any] = { "tsg_id": args.get("tsg_id", client.tsg_id), # Default to client's TSG ID if not provided "app_name": args.get("app_name"), "cloud_provider": args.get("cloud_provider"), "environment": args.get("environment"), } # Add optional fields if provided if args.get("model_name"): request_body["model_name"] = args.get("model_name") if args.get("ai_agent_framework"): request_body["ai_agent_framework"] = args.get("ai_agent_framework") if args.get("updated_by"): request_body["updated_by"] = args.get("updated_by") # Validate required fields if not request_body.get("app_name"): raise ValueError("app_name is required") if not request_body.get("cloud_provider"): raise ValueError("cloud_provider is required") if not request_body.get("environment"): raise ValueError("environment is required") # Call Management API to update customer app # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/customer-apps.ts # SDK: CustomerAppsClient.update(customerAppId, body) # Endpoint: PUT /v1/mgmt/customerapp?customer_app_id={customerAppId} url_suffix = f"{MGMT_API_V1_PREFIX}/customerapp" params = {"customer_app_id": customer_app_id} response = client.http_request(method="PUT", url_suffix=url_suffix, params=params, json_data=request_body, use_mgmt_base=True) # Parse response - Returns updated CustomerApp app_info = { "id": response.get("customer_appId"), "name": response.get("app_name"), "model_name": response.get("model_name"), "cloud_provider": response.get("cloud_provider"), "environment": response.get("environment"), "ai_agent_framework": response.get("ai_agent_framework"), "tsg_id": response.get("tsg_id"), "status": response.get("status"), "created_by": response.get("created_by"), "updated_by": response.get("updated_by"), } readable_output = tableToMarkdown( f"Updated Customer Application: {app_info.get('name')}", [app_info], headers=["id", "name", "model_name", "cloud_provider", "environment", "ai_agent_framework", "status", "updated_by"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}CustomerAppUpdate", outputs_key_field="id", outputs=app_info, readable_output=readable_output, raw_response=response, ) def runtime_customer_apps_consumption_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get per-application token consumption and session statistics. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ app_id = args.get("app_id") app_name = args.get("app_name") time_interval = arg_to_number(args.get("time_interval")) or 30 time_unit = args.get("time_unit", "days") if not app_id: raise ValueError("app_id is required") if not app_name: raise ValueError("app_name is required") # Validate time_interval - API only accepts 7, 30, or 60 days if time_interval not in [7, 30, 60]: raise ValueError("time_interval must be 7, 30, or 60 days") # Call Dashboard API to get application consumption # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/dashboard.ts # SDK: DashboardClient.application(query) # Endpoint: GET /v1/mgmt/dashboard/v2/apps/application?appid={appId}&appname={appName} # &time_interval={interval}&time_unit={unit} url_suffix = "/v1/mgmt/dashboard/v2/apps/application" params = {"appid": app_id, "appname": app_name, "time_interval": str(time_interval), "time_unit": time_unit} response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK schema (mgmt-dashboard.ts): DashboardApplicationSchema # Fields: id, name, cloud, source, created_at, updated_at, profiles[], token_stats{}, session_stats{} token_stats = response.get("token_stats") or {} session_stats = response.get("session_stats") or {} violation_breakdown = session_stats.get("violation_breakdown") or {} app_info = { "id": response.get("id"), "name": response.get("name"), "cloud": response.get("cloud"), "source": response.get("source"), "created_at": response.get("created_at"), "updated_at": response.get("updated_at"), "profiles": response.get("profiles"), # Token consumption stats "average_daily_tokens": token_stats.get("average_daily_tokens"), "average_daily_tokens_scale": token_stats.get("average_daily_tokens_scale"), "monthly_total_tokens": token_stats.get("monthly_total_tokens"), "monthly_total_tokens_scale": token_stats.get("monthly_total_tokens_scale"), # Session stats "sessions_total": session_stats.get("total"), "sessions_violating": session_stats.get("violating"), "last_session_id": session_stats.get("last_session_id"), "most_recent_session_time": session_stats.get("most_recent_session_time"), # Violation severity counts "violations_critical": violation_breakdown.get("critical"), "violations_high": violation_breakdown.get("high"), "violations_medium": violation_breakdown.get("medium"), "violations_low": violation_breakdown.get("low"), "violations_total": violation_breakdown.get("total"), } # Format readable output using XSOAR best practice table format # Create multiple tables for different data sections readable_parts = [] # Application Overview Table app_overview = [ { "App ID": app_info.get("id"), "Name": app_info.get("name"), "Cloud": app_info.get("cloud"), "Source": app_info.get("source"), "Profiles": ", ".join(app_info.get("profiles") or []) if app_info.get("profiles") else "None", "Time Window": f"{time_interval} {time_unit}", } ] readable_parts.append( tableToMarkdown( "Application Overview", app_overview, headers=["App ID", "Name", "Cloud", "Source", "Profiles", "Time Window"], removeNull=True, ) ) # Token Consumption Table avg_tokens = app_info.get("average_daily_tokens") avg_scale = app_info.get("average_daily_tokens_scale") or "" monthly_tokens = app_info.get("monthly_total_tokens") monthly_scale = app_info.get("monthly_total_tokens_scale") or "" token_consumption = [ {"Metric": "Daily Average", "Value": f"{avg_tokens}{avg_scale}" if avg_tokens else "N/A"}, {"Metric": "Monthly Total", "Value": f"{monthly_tokens}{monthly_scale}" if monthly_tokens else "N/A"}, ] readable_parts.append(tableToMarkdown("Token Consumption", token_consumption, headers=["Metric", "Value"])) # Session Statistics Table session_stats_table = [ { "Total Sessions": app_info.get("sessions_total") or 0, "Violating Sessions": app_info.get("sessions_violating") or 0, "Last Session ID": app_info.get("last_session_id") or "N/A", "Most Recent Session": app_info.get("most_recent_session_time") or "N/A", } ] readable_parts.append( tableToMarkdown( "Session Statistics", session_stats_table, headers=["Total Sessions", "Violating Sessions", "Last Session ID", "Most Recent Session"], removeNull=True, ) ) # Violation Severity Breakdown Table violations_table = [ { "Critical": app_info.get("violations_critical") or 0, "High": app_info.get("violations_high") or 0, "Medium": app_info.get("violations_medium") or 0, "Low": app_info.get("violations_low") or 0, "Total": app_info.get("violations_total") or 0, } ] readable_parts.append( tableToMarkdown("Violation Severity Breakdown", violations_table, headers=["Critical", "High", "Medium", "Low", "Total"]) ) readable_output = "\n".join(readable_parts) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}CustomerAppConsumption", outputs_key_field="id", outputs=app_info, readable_output=readable_output, raw_response=response, ) def runtime_customer_apps_violations_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get per-detector violation severity breakdown for an application. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ app_id = args.get("app_id") app_name = args.get("app_name") time_interval = arg_to_number(args.get("time_interval")) or 30 time_unit = args.get("time_unit", "days") if not app_id: raise ValueError("app_id is required") if not app_name: raise ValueError("app_name is required") # Validate time_interval - API only accepts 7, 30, or 60 days if time_interval not in [7, 30, 60]: raise ValueError("time_interval must be 7, 30, or 60 days") # Call Dashboard API to get application violation breakdown # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/dashboard.ts # SDK: DashboardClient.applicationViolationBreakdown(query) # Endpoint: GET /v1/mgmt/dashboard/v2/apps/applicationviolationbreakdown # ?appid={appId}&appname={appName}&time_interval={interval}&time_unit={unit} url_suffix = "/v1/mgmt/dashboard/v2/apps/applicationviolationbreakdown" params = {"appid": app_id, "appname": app_name, "time_interval": str(time_interval), "time_unit": time_unit} response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK schema (mgmt-dashboard.ts): DashboardApplicationViolationBreakdownSchema # Fields: detection_type_violation_breakdown[], total_violating # Known detection types: agent_security, contextual_grounding, dbs, dlp, malicious_code, # pi, source_code, tc, topic_guardrails, uf breakdowns_raw = response.get("detection_type_violation_breakdown", []) total_violating = response.get("total_violating", 0) # Parse detector breakdowns detectors = [] for breakdown in breakdowns_raw: detection_type = breakdown.get("detection_type") violation_breakdown = breakdown.get("violation_breakdown") or {} detector_info = { "detection_type": detection_type, "critical": violation_breakdown.get("critical", 0), "high": violation_breakdown.get("high", 0), "medium": violation_breakdown.get("medium", 0), "low": violation_breakdown.get("low", 0), "total": violation_breakdown.get("total", 0), } detectors.append(detector_info) # Sort by total violations (descending) for better readability detectors.sort(key=lambda x: x.get("total", 0), reverse=True) readable_output = tableToMarkdown( f"Violation Breakdown by Detector (Total Violating: {total_violating})", detectors, headers=["detection_type", "critical", "high", "medium", "low", "total"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Create structured output output = { "app_id": app_id, "app_name": app_name, "total_violating": total_violating, "detectors": detectors, "time_interval": time_interval, "time_unit": time_unit, } return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}CustomerAppViolations", outputs_key_field="app_id", outputs=output, readable_output=readable_output, raw_response=response, ) def runtime_customer_apps_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Delete a customer application and all associated API keys. WARNING: This permanently deletes the application and revokes all associated API keys immediately. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR with deletion confirmation. """ # Required arguments app_name = args.get("app_name") updated_by = args.get("updated_by") if not app_name: raise ValueError("app_name is required") if not updated_by: raise ValueError("updated_by is required (email of user performing deletion)") # Call Management API to delete customer app # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/customer-apps.ts # SDK: CustomerAppsClient.delete(appName, updatedBy) # Endpoint: DELETE /v1/mgmt/customerapp?app_name={appName}&updated_by={email} # Response: { message: "customer app and associated keys successfully deleted" } url_suffix = f"{MGMT_API_V1_PREFIX}/customerapp" params = {"app_name": app_name, "updated_by": updated_by} response = client.http_request(method="DELETE", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK handles both string and object responses # CustomerAppDeleteResponseSchema transforms plain string to { message: "..." } message = ( response.get("message", "Customer app and associated keys deleted successfully") if isinstance(response, dict) else str(response) ) # Context output context_output = {"app_name": app_name, "deleted_by": updated_by, "message": message, "deleted": True} # Create readable output with deletion confirmation readable_output = tableToMarkdown( "Customer Application Deleted", context_output, headers=["app_name", "deleted_by", "message", "deleted"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += ( "\n\n**⚠️ WARNING:** This action cannot be undone. The customer application and all " "associated API keys have been permanently deleted and revoked." ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}CustomerAppDeleted", outputs_key_field="app_name", outputs=context_output, readable_output=readable_output, raw_response=response, ) def runtime_deployment_profiles_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List deployment profiles. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ limit = arg_to_number(args.get("limit", DEFAULT_LIMIT)) unactivated = args.get("unactivated", "false").lower() == "true" # Call Management API to list deployment profiles # Reference: ./knowledge/prisma-airs-sdk-main/src/management/deployment-profiles.ts # SDK path: /v1/mgmt/deploymentprofiles url_suffix = f"{MGMT_API_V1_PREFIX}/deploymentprofiles" params = {"offset": "0", "limit": str(limit) if limit else "100"} if unactivated: params["unactivated"] = "true" response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response - SDK schema: dp_name, auth_code, tsg_id, status, expiration_date profiles_raw = response.get("deployment_profiles", []) profiles = [] for profile in profiles_raw: profile_info = { "name": profile.get("dp_name"), "auth_code": profile.get("auth_code"), "tsg_id": profile.get("tsg_id"), "status": profile.get("status"), "expiration_date": profile.get("expiration_date"), "ave_text_records": profile.get("ave_text_records"), } profiles.append(profile_info) readable_output = tableToMarkdown( "Prisma AIRs Deployment Profiles", profiles, headers=["name", "auth_code", "status", "expiration_date", "ave_text_records"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DeploymentProfile", outputs_key_field="name", outputs=profiles, readable_output=readable_output, raw_response=response, ) def runtime_dlp_profiles_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List DLP data profiles (v2 API). Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ page = arg_to_number(args.get("page")) or 0 size = arg_to_number(args.get("size")) or 50 # Build query parameters params: dict[str, Any] = {"page": page, "size": size} # Call DLP v2 API to list data profiles # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-profiles.ts # CRITICAL: Uses DLP v2 API base URL (https://api.dlp.paloaltonetworks.com) response = client.http_request(method="GET", url_suffix=DLP_DATA_PROFILES_PATH, params=params, use_dlp_base=True) # Parse response # SDK schema (dlp-data-profile.ts): id, name, description, tenant_id, type, profile_status, profile_type, etc. # Returns paginated: { content: [...], page: {...} } profiles_raw = response.get("content", []) profiles = [] for profile in profiles_raw: profile_info = { "id": profile.get("id"), "name": profile.get("name"), "description": profile.get("description"), "tenant_id": profile.get("tenant_id"), "type": profile.get("type"), "profile_status": profile.get("profile_status"), "profile_type": profile.get("profile_type"), "is_granular_data_profile": profile.get("is_granular_data_profile"), "is_parent_managed": profile.get("is_parent_managed"), "version": profile.get("version"), "created_at": profile.get("audit_metadata", {}).get("created_at"), "updated_at": profile.get("audit_metadata", {}).get("updated_at"), "created_by": profile.get("audit_metadata", {}).get("created_by"), "updated_by": profile.get("audit_metadata", {}).get("updated_by"), } profiles.append(profile_info) total_elements = response.get("page", {}).get("total_elements", len(profiles)) total_pages = response.get("page", {}).get("total_pages", 1) readable_output = tableToMarkdown( f"Prisma AIRs DLP Data Profiles (Page {page + 1}/{total_pages}, {len(profiles)} of {total_elements})", profiles, headers=["id", "name", "type", "profile_status", "profile_type", "version"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpProfile", outputs_key_field="id", outputs=profiles, readable_output=readable_output, raw_response=response, ) def runtime_dlp_profiles_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get a single DLP data profile by ID. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") # Call DLP data profiles get endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-profiles.ts # SDK: GET /v2/api/data-profiles/{resourceId} response = client.http_request(method="GET", url_suffix=f"{DLP_DATA_PROFILES_PATH}/{profile_id}", use_dlp_base=True) # Extract profile details from response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-profile.ts profile_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "profile_status": response.get("profile_status"), "profile_type": response.get("profile_type"), "is_granular_data_profile": response.get("is_granular_data_profile"), "is_parent_managed": response.get("is_parent_managed"), "version": response.get("version"), "detection_rules": response.get("detection_rules"), "created_at": response.get("audit_metadata", {}).get("created_at"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Data Profile: {profile_info.get('name')}", profile_info, headers=["id", "name", "type", "profile_status", "profile_type", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpProfileGet", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_profiles_create_command(client: Client, args: dict[str, Any]) -> CommandResults: """Create a new DLP data profile. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-profile.ts # Required fields: name, detection_rules (array of rule objects) name = args.get("name") detection_rules_str = args.get("detection_rules") if not name: raise ValueError("name is required") if not detection_rules_str: raise ValueError("detection_rules is required (JSON array)") # Parse detection_rules from JSON try: detection_rules = json.loads(detection_rules_str) except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"detection_rules must be valid JSON: {e}") request_body: dict[str, Any] = {"name": name, "detection_rules": detection_rules} # Optional: description if args.get("description"): request_body["description"] = args.get("description") # Optional: is_granular_data_profile if args.get("is_granular_data_profile") is not None: request_body["is_granular_data_profile"] = argToBoolean(args.get("is_granular_data_profile")) # Call DLP data profiles create endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-profiles.ts # SDK: POST /v2/api/data-profiles response = client.http_request(method="POST", url_suffix=DLP_DATA_PROFILES_PATH, json_data=request_body, use_dlp_base=True) # Extract created profile details profile_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "profile_status": response.get("profile_status"), "profile_type": response.get("profile_type"), "is_granular_data_profile": response.get("is_granular_data_profile"), "version": response.get("version"), "detection_rules": response.get("detection_rules"), "created_at": response.get("audit_metadata", {}).get("created_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Data Profile Created: {profile_info.get('name')}", profile_info, headers=["id", "name", "type", "profile_status", "profile_type", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpProfileCreate", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_profiles_patch_command(client: Client, args: dict[str, Any]) -> CommandResults: """Partially update a DLP data profile (JSON Merge Patch). Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-profile.ts # PATCH requires: name, profile_type (cannot be cleared) name = args.get("name") profile_type = args.get("profile_type") if not name: raise ValueError("name is required for PATCH") if not profile_type: raise ValueError("profile_type is required for PATCH") request_body: dict[str, Any] = {"name": name, "profile_type": profile_type} # Optional: description (can be null to clear) if args.get("description") is not None: desc_value = args.get("description") request_body["description"] = None if desc_value == "null" else desc_value # Optional: detection_rules (can be null to clear) if args.get("detection_rules") is not None: rules_value = args.get("detection_rules") if rules_value == "null": request_body["detection_rules"] = None else: try: request_body["detection_rules"] = json.loads(rules_value or "") except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"detection_rules must be valid JSON or 'null': {e}") # Call DLP data profiles patch endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-profiles.ts # SDK: PATCH /v2/api/data-profiles/{resourceId} # Uses Content-Type: application/merge-patch+json response = client.http_request( method="PATCH", url_suffix=f"{DLP_DATA_PROFILES_PATH}/{profile_id}", json_data=request_body, use_dlp_base=True, headers={"Content-Type": "application/merge-patch+json"}, ) # Extract updated profile details profile_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "profile_status": response.get("profile_status"), "profile_type": response.get("profile_type"), "version": response.get("version"), "detection_rules": response.get("detection_rules"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Data Profile Patched: {profile_info.get('name')}", profile_info, headers=["id", "name", "type", "profile_status", "profile_type", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpProfilePatch", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_profiles_replace_command(client: Client, args: dict[str, Any]) -> CommandResults: """Replace (full update) a DLP data profile. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-profile.ts # Required fields: name, detection_rules name = args.get("name") detection_rules_str = args.get("detection_rules") if not name: raise ValueError("name is required") if not detection_rules_str: raise ValueError("detection_rules is required (JSON array)") # Parse detection_rules from JSON try: detection_rules = json.loads(detection_rules_str) except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"detection_rules must be valid JSON: {e}") request_body: dict[str, Any] = {"name": name, "detection_rules": detection_rules} # Optional: description if args.get("description"): request_body["description"] = args.get("description") # Optional: is_granular_data_profile if args.get("is_granular_data_profile") is not None: request_body["is_granular_data_profile"] = argToBoolean(args.get("is_granular_data_profile")) # Call DLP data profiles replace endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-profiles.ts # SDK: PUT /v2/api/data-profiles/{resourceId} response = client.http_request( method="PUT", url_suffix=f"{DLP_DATA_PROFILES_PATH}/{profile_id}", json_data=request_body, use_dlp_base=True ) # Extract updated profile details profile_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "profile_status": response.get("profile_status"), "profile_type": response.get("profile_type"), "version": response.get("version"), "detection_rules": response.get("detection_rules"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Data Profile Replaced: {profile_info.get('name')}", profile_info, headers=["id", "name", "type", "profile_status", "profile_type", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpProfileReplace", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_profiles_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Soft-delete a DLP data profile. The DLP Data Profiles API does not expose a DELETE endpoint. To remove a profile, it must be patched to a deleted lifecycle state (profile_status="deleted"). The JSON Merge Patch requires name + profile_type, so this command first fetches the profile to obtain those fields, then patches profile_status to "deleted". Reference: ./knowledge/versions/current/prisma-airs-sdk-main/src/management/dlp/data-profiles.ts "The DLP spec does not expose a DELETE for data profiles - to remove a profile, patch it to a deleted lifecycle state (typically profile_status: 'deleted')." Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") # Step 1: Fetch the profile to obtain name + profile_type (required by the merge-patch). # SDK: GET /v2/api/data-profiles/{resourceId} profile = client.http_request(method="GET", url_suffix=f"{DLP_DATA_PROFILES_PATH}/{profile_id}", use_dlp_base=True) name = profile.get("name") profile_type = profile.get("profile_type") if not name or not profile_type: raise ValueError( f"Cannot delete DLP data profile '{profile_id}': unable to resolve required fields " "(name, profile_type) from the existing profile." ) # Step 2: Patch profile_status to "deleted" (soft-delete). # SDK: PATCH /v2/api/data-profiles/{resourceId} with Content-Type application/merge-patch+json request_body: dict[str, Any] = {"name": name, "profile_type": profile_type, "profile_status": "deleted"} response = client.http_request( method="PATCH", url_suffix=f"{DLP_DATA_PROFILES_PATH}/{profile_id}", json_data=request_body, use_dlp_base=True, headers={"Content-Type": "application/merge-patch+json"}, ) # Action-tracking context (own key, consistent with other delete commands in this pack) context_output = { "id": profile_id, "name": name, "profile_status": (response or {}).get("profile_status", "deleted"), "deleted": True, "status": "Successfully soft-deleted", } readable_output = tableToMarkdown( "Prisma AIRs DLP Data Profile Deleted", [context_output], headers=["id", "name", "profile_status", "status"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpProfileDelete", outputs_key_field="id", outputs=context_output, readable_output=readable_output, raw_response=response, ) def runtime_topics_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List custom topics. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ limit = arg_to_number(args.get("limit")) or 100 offset = arg_to_number(args.get("offset")) or 0 # Build query parameters params: dict[str, Any] = {"limit": limit, "offset": offset} # Add TSG ID to URL suffix # Reference: ./knowledge/prisma-airs-sdk-main/src/management/topics-client.ts url_suffix = f"{MGMT_API_V1_PREFIX}/topics/tsg/{client.tsg_id}" # Call topics list endpoint response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Extract topics from response (forward-compatible: capture all fields) # Schema: ./knowledge/prisma-airs-sdk-main/src/models/mgmt-topics.ts (TopicSchema) # API returns custom topics under "custom_topics"; fall back to "data" for compatibility. topics_data = response.get("custom_topics", response.get("data", [])) topics = [] for topic in topics_data: topic_info = { "topic_id": topic.get("topic_id"), "topic_name": topic.get("topic_name"), "revision": topic.get("revision"), "description": topic.get("description"), "examples": topic.get("examples", []), "last_modified_ts": topic.get("last_modified_ts"), "created_by": topic.get("created_by"), "updated_by": topic.get("updated_by"), "csp_id": topic.get("csp_id"), "tsg_id": topic.get("tsg_id"), } topics.append(topic_info) readable_output = tableToMarkdown( f"Prisma AIRs Custom Topics ({len(topics)} of {response.get('total', len(topics))})", topics, headers=["topic_id", "topic_name", "revision", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}Topic", outputs_key_field="topic_id", outputs=topics, readable_output=readable_output, raw_response=response, ) def runtime_topics_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get a specific custom topic by ID or name. Note: There is no dedicated GET endpoint - this fetches all topics and filters. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ topic_id = args.get("topic_id") topic_name = args.get("topic_name") if not topic_id and not topic_name: raise ValueError("Either topic_id or topic_name is required") # Call Management API to list all topics, then filter # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/topics.ts # SDK: TopicsClient has no get() method - uses list() and client-side filtering # Note: No dedicated GET endpoint exists - SDK pattern is same as profiles url_suffix = f"{MGMT_API_V1_PREFIX}/topics/tsg/{client.tsg_id}" params = { "offset": "0", "limit": "1000", # Get all topics for filtering } response = client.http_request(method="GET", url_suffix=url_suffix, params=params, use_mgmt_base=True) # Parse response and filter # SDK schema: CustomTopicListResponseSchema has "custom_topics" field topics_raw = response.get("custom_topics", response.get("data", [])) # Filter by ID or name if topic_id: matches = [t for t in topics_raw if t.get("topic_id") == topic_id] search_key = f"ID: {topic_id}" else: # Filter by name matches = [t for t in topics_raw if t.get("topic_name") == topic_name] search_key = f"Name: {topic_name}" if not matches: raise ValueError(f"Topic not found: {search_key}") topic = matches[0] # Extract full topic details topic_info = { "topic_id": topic.get("topic_id"), "topic_name": topic.get("topic_name"), "revision": topic.get("revision"), "active": topic.get("active"), "description": topic.get("description"), "examples": topic.get("examples", []), "created_by": topic.get("created_by"), "updated_by": topic.get("updated_by"), "last_modified_ts": topic.get("last_modified_ts"), "created_ts": topic.get("created_ts"), } # Create readable output readable_output = tableToMarkdown( f"Custom Topic: {topic_info.get('topic_name')}", topic_info, headers=["topic_id", "topic_name", "revision", "active", "description", "created_by", "updated_by", "last_modified_ts"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Add examples if topic_info.get("examples"): readable_output += f"\n\n**Examples ({len(topic_info['examples'])}):**\n\n" for i, example in enumerate(topic_info["examples"][:5], 1): # Show first 5 readable_output += f"{i}. {example}\n" if len(topic_info["examples"]) > 5: readable_output += f"\n... and {len(topic_info['examples']) - 5} more\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}TopicGet", outputs_key_field="topic_id", outputs=topic_info, readable_output=readable_output, raw_response=topic, ) def runtime_topics_create_command(client: Client, args: dict[str, Any]) -> CommandResults: """Create a new custom topic guardrail. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ topic_name = args.get("topic_name") description = args.get("description") examples = argToList(args.get("examples")) active = argToBoolean(args.get("active", True)) if not topic_name: raise ValueError("topic_name is required") if not description: raise ValueError("description is required") if not examples: raise ValueError("examples is required (comma-separated list)") # Build request body according to CreateCustomTopicRequest # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/models/mgmt-custom-topic.ts # Required: topic_name, description, examples # Optional: active request_body: dict[str, Any] = {"topic_name": topic_name, "description": description, "examples": examples, "active": active} # Call Management API to create topic # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/topics.ts # SDK: TopicsClient.create(body) # Endpoint: POST /v1/mgmt/topic url_suffix = f"{MGMT_API_V1_PREFIX}/topic" response = client.http_request(method="POST", url_suffix=url_suffix, json_data=request_body, use_mgmt_base=True) # Parse response - returns full CustomTopic topic_info = { "topic_id": response.get("topic_id"), "topic_name": response.get("topic_name"), "revision": response.get("revision"), "active": response.get("active"), "description": response.get("description"), "examples": response.get("examples", []), "created_by": response.get("created_by"), "updated_by": response.get("updated_by"), "last_modified_ts": response.get("last_modified_ts"), "created_ts": response.get("created_ts"), } # Create readable output readable_output = tableToMarkdown( "Custom Topic Created", topic_info, headers=["topic_id", "topic_name", "revision", "active", "description", "created_by"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Add examples if topic_info.get("examples"): readable_output += f"\n\n**Examples ({len(topic_info['examples'])}):**\n\n" for i, example in enumerate(topic_info["examples"][:5], 1): readable_output += f"{i}. {example}\n" if len(topic_info["examples"]) > 5: readable_output += f"\n... and {len(topic_info['examples']) - 5} more\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}TopicCreate", outputs_key_field="topic_id", outputs=topic_info, readable_output=readable_output, raw_response=response, ) def runtime_topics_update_command(client: Client, args: dict[str, Any]) -> CommandResults: """Update an existing custom topic. WARNING: This modifies the topic definition and can break detection if misconfigured. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ topic_id = args.get("topic_id") topic_name = args.get("topic_name") description = args.get("description") examples = args.get("examples") active = args.get("active") if not topic_id: raise ValueError("topic_id is required") if not topic_name: raise ValueError("topic_name is required") # Build request body according to CreateCustomTopicRequest # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/models/mgmt-custom-topic.ts request_body: dict[str, Any] = {"topic_name": topic_name} # Add optional fields if provided if description: request_body["description"] = description if examples: request_body["examples"] = argToList(examples) if active is not None: request_body["active"] = argToBoolean(active) # Call Management API to update topic # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/topics.ts # SDK: TopicsClient.update(topicId, body) # Endpoint: PUT /v1/mgmt/topic/uuid/{topicId} url_suffix = f"{MGMT_API_V1_PREFIX}/topic/uuid/{topic_id}" response = client.http_request(method="PUT", url_suffix=url_suffix, json_data=request_body, use_mgmt_base=True) # Parse response - returns updated CustomTopic with incremented revision topic_info = { "topic_id": response.get("topic_id"), "topic_name": response.get("topic_name"), "revision": response.get("revision"), # Incremented "active": response.get("active"), "description": response.get("description"), "examples": response.get("examples", []), "created_by": response.get("created_by"), "updated_by": response.get("updated_by"), "last_modified_ts": response.get("last_modified_ts"), "created_ts": response.get("created_ts"), } # Create readable output readable_output = tableToMarkdown( "Custom Topic Updated", topic_info, headers=["topic_id", "topic_name", "revision", "active", "description", "updated_by", "last_modified_ts"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) # Add examples if topic_info.get("examples"): readable_output += f"\n\n**Examples ({len(topic_info['examples'])}):**\n\n" for i, example in enumerate(topic_info["examples"][:5], 1): readable_output += f"{i}. {example}\n" if len(topic_info["examples"]) > 5: readable_output += f"\n... and {len(topic_info['examples']) - 5} more\n" return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}TopicUpdate", outputs_key_field="topic_id", outputs=topic_info, readable_output=readable_output, raw_response=response, ) def runtime_topics_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Delete a custom topic. WARNING: This permanently deletes the topic. Fails if topic is referenced by a profile. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ topic_id = args.get("topic_id") if not topic_id: raise ValueError("topic_id is required") force = argToBoolean(args.get("force", False)) updated_by = args.get("updated_by") # Call Management API to delete topic # Reference: ./knowledge/versions/current/prisma-airs-sdk/src/management/topics.ts # Response: { message: "deleted" } (or plain string transformed to object) if force: # SDK: TopicsClient.forceDelete(topicId, updatedBy?) # Endpoint: DELETE /v1/mgmt/topic/force/{topicId}[?updated_by=...] # Force-delete removes the topic from any referencing profiles; updated_by is optional. url_suffix = f"{MGMT_API_V1_PREFIX}/topic/force/{topic_id}" params = {"updated_by": updated_by} if updated_by else None response = client.http_request(method="DELETE", url_suffix=url_suffix, params=params, use_mgmt_base=True) else: # SDK: TopicsClient.delete(topicId) # Endpoint: DELETE /v1/mgmt/topic/{topicId} # NOTE: Fails with 409 Conflict if topic is referenced by any profile url_suffix = f"{MGMT_API_V1_PREFIX}/topic/{topic_id}" response = client.http_request(method="DELETE", url_suffix=url_suffix, use_mgmt_base=True) # Parse response - SDK handles both string and object responses # DeleteTopicResponseSchema transforms plain string to { message: "..." } default_message = "Custom topic force-deleted successfully" if force else "Custom topic deleted successfully" message = response.get("message", default_message) if isinstance(response, dict) else str(response) # Create readable output # Context output context_output = {"topic_id": topic_id, "message": message, "deleted": True, "force": force} readable_output = tableToMarkdown( "Custom Topic Force-Deleted" if force else "Custom Topic Deleted", context_output, headers=["topic_id", "message", "deleted", "force"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += "\n\n**⚠️ WARNING:** This action cannot be undone. The custom topic has been permanently deleted." return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}TopicDeleted", outputs_key_field="topic_id", outputs=context_output, readable_output=readable_output, raw_response=response, ) def runtime_topics_apply_command(client: Client, args: dict[str, Any]) -> CommandResults: """Apply a topic to a security profile (additive - preserves existing topics). This command orchestrates multiple API calls to apply a custom topic to a security profile: 1. Find topic by name → get topic_id and current revision 2. Get profile by name → extract current topic-guardrails configuration 3. Merge topics: remove old instance (if exists), add new with action/revision 4. Update profile with modified policy CRITICAL: AIRS requires the topic revision number to pin topic content correctly. Omitting revision defaults to revision 0 (original), not latest. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_name = args.get("profile_name") topic_name = args.get("topic_name") action = args.get("action", "block") # Topic action: "allow" or "block" guardrail_action = args.get("guardrail_action", "block") # Overall default action if not profile_name or not topic_name: raise ValueError("profile_name and topic_name are required") if action not in ["allow", "block"]: raise ValueError("action must be 'allow' or 'block'") if guardrail_action not in ["allow", "block"]: raise ValueError("guardrail_action must be 'allow' or 'block'") # Step 1: Find topic by name and get current revision # Reference: ./knowledge/versions/current/prisma-airs-cli/src/cli/commands/topics-apply.ts (lines 24-28) # SDK: ManagementClient.topics.list() # Endpoint: GET /v1/mgmt/topics/tsg/{tsgId} url_suffix = f"{MGMT_API_V1_PREFIX}/topics/tsg/{client.tsg_id}" topics_response = client.http_request( method="GET", url_suffix=url_suffix, params={"offset": 0, "limit": 100}, use_mgmt_base=True ) all_topics = topics_response.get("custom_topics", []) topic = next((t for t in all_topics if t.get("topic_name") == topic_name), None) if not topic: raise DemistoException(f"Topic '{topic_name}' not found. Create it first with prisma-airs-runtime-topics-create.") topic_id = topic.get("topic_id") topic_revision = topic.get("revision", 0) if not topic_id: raise DemistoException(f"Topic '{topic_name}' found but missing topic_id") # Step 2: Get profile by name # Reference: ./knowledge/versions/current/prisma-airs-cli/src/airs/management.ts (lines 102-106) # SDK: ManagementClient.profiles.list() # Endpoint: GET /v1/mgmt/securityprofiles/tsg/{tsgId} profiles_url_suffix = f"{MGMT_API_V1_PREFIX}/profiles/tsg/{client.tsg_id}" profiles_response = client.http_request( method="GET", url_suffix=profiles_url_suffix, params={"offset": 0, "limit": 100}, use_mgmt_base=True ) ai_profiles = profiles_response.get("ai_profiles", []) profile = next((p for p in ai_profiles if p.get("profile_name") == profile_name), None) if not profile: raise DemistoException(f"Profile '{profile_name}' not found. Create it first with prisma-airs-runtime-profiles-create.") profile_id = profile.get("profile_id") if not profile_id: raise DemistoException(f"Profile '{profile_name}' found but missing profile_id") # Step 3: Extract and modify profile policy # Reference: ./knowledge/versions/current/prisma-airs-cli/src/airs/management.ts (lines 114-162) # Profile structure: policy → ai-security-profiles → model-configuration → model-protection → topic-guardrails import copy policy = copy.deepcopy(profile.get("policy", {})) # Navigate to ai-security-profiles ai_sec_profiles = policy.get("ai-security-profiles", []) if not ai_sec_profiles: ai_sec_profiles = [{"model-type": "default", "model-configuration": {}}] policy["ai-security-profiles"] = ai_sec_profiles model_config = ai_sec_profiles[0].get("model-configuration", {}) if "model-configuration" not in ai_sec_profiles[0]: ai_sec_profiles[0]["model-configuration"] = model_config # Navigate to model-protection model_protection = model_config.get("model-protection", []) if "model-protection" not in model_config: model_config["model-protection"] = model_protection # Find or create topic-guardrails topic_guardrails = next((mp for mp in model_protection if mp.get("name") == "topic-guardrails"), None) if not topic_guardrails: topic_guardrails = {"action": guardrail_action, "name": "topic-guardrails", "options": [], "topic-list": []} model_protection.append(topic_guardrails) else: # Update guardrail-level action topic_guardrails["action"] = guardrail_action # Get current topic-list topic_list = topic_guardrails.get("topic-list", []) if "topic-list" not in topic_guardrails: topic_guardrails["topic-list"] = topic_list # Remove old instance of this topic (if exists) to avoid duplicates # Reference: ./knowledge/versions/current/prisma-airs-cli/src/cli/commands/topics-apply.ts (lines 32-34) for entry in topic_list: topics_in_entry = entry.get("topic", []) entry["topic"] = [t for t in topics_in_entry if t.get("topic_name") != topic_name] # Remove empty action groups (AIRS rejects them) topic_list = [entry for entry in topic_list if entry.get("topic")] # Add new topic to appropriate action group # Find or create action group action_group = next((entry for entry in topic_list if entry.get("action") == action), None) if not action_group: action_group = {"action": action, "topic": []} topic_list.append(action_group) # Add topic with revision (CRITICAL: must include revision) # Reference: ./knowledge/versions/current/prisma-airs-cli/src/airs/management.ts (lines 144-152) action_group["topic"].append({"topic_id": topic_id, "topic_name": topic_name, "revision": topic_revision}) topic_guardrails["topic-list"] = topic_list # Step 4: Update profile with modified policy # Reference: ./knowledge/versions/current/prisma-airs-cli/src/airs/management.ts (lines 169-173) # SDK: ManagementClient.profiles.update(profileId, body) # Endpoint: PUT /v1/mgmt/profile/uuid/{profileId} update_url_suffix = f"{MGMT_API_V1_PREFIX}/profile/uuid/{profile_id}" update_body = {"profile_name": profile_name, "active": profile.get("active", True), "policy": policy} update_response = client.http_request(method="PUT", url_suffix=update_url_suffix, json_data=update_body, use_mgmt_base=True) # Create readable output # Context output. Applying a topic versions the profile, so the resulting profile_id from the # PUT response is the revision the topic is actually bound to (fall back to the source id). context_output = { "profile_name": profile_name, "profile_id": update_response.get("profile_id", profile_id), "topic_name": topic_name, "topic_id": topic_id, "topic_revision": topic_revision, "action": action, "guardrail_action": guardrail_action, "applied": True, } readable_output = tableToMarkdown( "Topic Applied to Profile", context_output, headers=[ "profile_name", "profile_id", "topic_name", "topic_id", "topic_revision", "action", "guardrail_action", "applied", ], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) readable_output += ( "\n\n**Note:** Topic has been added to the profile (existing topics preserved). " "The topic's current revision was pinned to ensure consistent detection behavior." ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}TopicApplied", outputs_key_field="profile_name", outputs=context_output, readable_output=readable_output, raw_response=update_response, ) def runtime_bulk_scan_command(client: Client, args: dict[str, Any]) -> CommandResults: """Perform bulk scanning of prompts via async API. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_name = args.get("profile_name") prompts_csv = args.get("prompts_csv") # CSV content as string session_id = args.get("session_id") if not profile_name or not prompts_csv: raise ValueError("profile_name and prompts_csv are required arguments") # Parse CSV content to extract prompts import csv import io prompts = [] reader = csv.DictReader(io.StringIO(prompts_csv)) # Try to find prompt column (case-insensitive) if reader.fieldnames: prompt_col = next((col for col in reader.fieldnames if col.lower() == "prompt"), None) if prompt_col: for row in reader: prompt = row.get(prompt_col, "").strip() if prompt: prompts.append(prompt) else: # If no "prompt" column, treat entire CSV as newline-separated prompts prompts = [line.strip() for line in prompts_csv.split("\n") if line.strip()] else: # No headers, treat as newline-separated prompts prompts.append(line.strip() for line in prompts_csv.split("\n") if line.strip()) if not prompts: raise ValueError("No prompts found in CSV input") # Build bulk scan request (batch into groups of 5 as per CLI) # Note: XSOAR doesn't have async scanning capability built-in like the CLI # We'll do synchronous scanning but in batches scan_results = [] batch_size = 5 total_prompts = len(prompts) demisto.debug(f"Starting bulk scan of {total_prompts} prompts in batches of {batch_size}") for i in range(0, total_prompts, batch_size): batch = prompts[i : i + batch_size] for prompt in batch: # Use scanner_request for each prompt content = {"prompt": prompt} scan_request = {"ai_profile": {"profile_name": profile_name}, "contents": [content]} if session_id: scan_request["session_id"] = session_id try: scan_response = client.scanner_request(scan_request) # Extract key fields scan_result = { "prompt": prompt, "scan_id": scan_response.get("scan_id"), "action": scan_response.get("action"), "category": scan_response.get("category"), "detected": any(scan_response.get("prompt_detected", {}).values()) if scan_response.get("prompt_detected") else False, } scan_results.append(scan_result) except Exception as e: demisto.error(f"Failed to scan prompt: {str(e)}") scan_results.append( { "prompt": prompt, "scan_id": None, "action": "error", "category": "error", "detected": False, "error": str(e), } ) # Calculate summary stats total = len(scan_results) blocked = sum(1 for r in scan_results if r.get("action") == "block") allowed = sum(1 for r in scan_results if r.get("action") == "allow") errors = sum(1 for r in scan_results if r.get("action") == "error") # Create summary table summary = [{"Total Prompts": total, "Blocked": blocked, "Allowed": allowed, "Errors": errors}] readable_output = "## Prisma AIRs Bulk Scan Results\n\n" readable_output += f"**Profile:** {profile_name}\n" if session_id: readable_output += f"**Session ID:** {session_id}\n" readable_output += "\n" readable_output += tableToMarkdown("Summary", summary, headers=["Total Prompts", "Blocked", "Allowed", "Errors"]) readable_output += "\n" readable_output += tableToMarkdown( "Scan Results (first 50)", scan_results[:50], headers=["prompt", "action", "category", "detected"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}BulkScan", outputs_key_field="scan_id", outputs={ "profile_name": profile_name, "session_id": session_id, "total": total, "blocked": blocked, "allowed": allowed, "errors": errors, "results": scan_results, }, readable_output=readable_output, ) def runtime_dlp_dictionaries_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List DLP dictionaries. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ page = arg_to_number(args.get("page")) or 0 size = arg_to_number(args.get("size")) or 50 include_keywords = argToBoolean(args.get("include_keywords", False)) # Build query parameters params: dict[str, Any] = {"page": page, "size": size} if include_keywords: params["keywords"] = "true" # Call DLP dictionaries list endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/dictionaries.ts # CRITICAL: DLP v2 API uses https://api.dlp.paloaltonetworks.com (separate from SCM) response = client.http_request(method="GET", url_suffix=DLP_DICTIONARIES_PATH, params=params, use_dlp_base=True) # Extract dictionaries from paginated response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-dictionary.ts dictionaries_data = response.get("content", []) dictionaries = [] for dictionary in dictionaries_data: dict_info = { "id": dictionary.get("id"), "name": dictionary.get("name"), "description": dictionary.get("description"), "category": dictionary.get("category"), "region_name": dictionary.get("region_name"), "type": dictionary.get("type"), "is_case_sensitive": dictionary.get("is_case_sensitive"), "is_parent_managed": dictionary.get("is_parent_managed"), "detection_technique": dictionary.get("detection_technique"), "number_of_keywords": dictionary.get("dictionary_metadata", {}).get("number_of_keywords"), "created_at": dictionary.get("audit_metadata", {}).get("created_at"), "updated_at": dictionary.get("audit_metadata", {}).get("updated_at"), "created_by": dictionary.get("audit_metadata", {}).get("created_by"), "updated_by": dictionary.get("audit_metadata", {}).get("updated_by"), } dictionaries.append(dict_info) total_elements = response.get("total_elements", len(dictionaries)) total_pages = response.get("total_pages", 1) readable_output = tableToMarkdown( f"Prisma AIRs DLP Dictionaries (Page {page + 1}/{total_pages}, {len(dictionaries)} of {total_elements})", dictionaries, headers=["id", "name", "category", "type", "number_of_keywords", "region_name"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpDictionary", outputs_key_field="id", outputs=dictionaries, readable_output=readable_output, raw_response=response, ) def runtime_dlp_dictionaries_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get a single DLP dictionary by ID. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ dictionary_id = args.get("dictionary_id") if not dictionary_id: raise ValueError("dictionary_id is required") include_keywords = argToBoolean(args.get("include_keywords", False)) # Build query parameters params: dict[str, Any] = {} if include_keywords: params["keywords"] = "true" # Call DLP dictionaries get endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/dictionaries.ts # SDK: GET /v2/api/dictionaries/{resourceId}?keywords=true response = client.http_request( method="GET", url_suffix=f"{DLP_DICTIONARIES_PATH}/{dictionary_id}", params=params, use_dlp_base=True ) # Extract dictionary details from response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-dictionary.ts dict_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "category": response.get("category"), "region_name": response.get("region_name"), "type": response.get("type"), "is_case_sensitive": response.get("is_case_sensitive"), "is_parent_managed": response.get("is_parent_managed"), "detection_technique": response.get("detection_technique"), "detection_sub_technique": response.get("detection_sub_technique"), "dictionary_metadata": response.get("dictionary_metadata"), "keywords": response.get("keywords"), # Only populated if include_keywords=true "tags": response.get("tags"), "created_at": response.get("audit_metadata", {}).get("created_at"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Dictionary: {dict_info.get('name')}", dict_info, headers=["id", "name", "category", "type", "region_name", "is_case_sensitive", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpDictionaryGet", outputs_key_field="id", outputs=dict_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_dictionaries_create_command(client: Client, args: dict[str, Any]) -> CommandResults: """Create a new DLP dictionary by uploading a keyword file. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ # Build metadata (required fields) # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-dictionary.ts name = args.get("name") category = args.get("category") region_name = args.get("region_name") entry_id = args.get("entry_id") if not name: raise ValueError("name is required") if not category: raise ValueError("category is required") if not region_name: raise ValueError("region_name is required") if not entry_id: raise ValueError("entry_id is required (file entry ID from war room)") # Get uploaded file from war room file_info = demisto.getFilePath(entry_id) file_path = file_info["path"] file_name = file_info["name"] # Read file content with open(file_path, "rb") as f: file_content = f.read() # Build metadata JSON metadata: dict[str, Any] = {"category": category, "name": name, "original_file_name": file_name, "region_name": region_name} # Optional fields if args.get("description"): metadata["description"] = args.get("description") if args.get("is_case_sensitive") is not None: metadata["is_case_sensitive"] = argToBoolean(args.get("is_case_sensitive")) if args.get("type"): metadata["type"] = args.get("type") include_keywords = argToBoolean(args.get("include_keywords", False)) # Build query parameters params: dict[str, Any] = {} if include_keywords: params["keywords"] = "true" # Build multipart form data # SDK sends: FormData with 'json' part (metadata as JSON blob) and 'file' part (keyword file) files = { "json": ("metadata.json", json.dumps(metadata).encode("utf-8"), "application/json"), "file": (file_name, file_content, "text/plain"), } # Call DLP dictionaries create endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/dictionaries.ts # SDK: POST /v2/api/dictionaries (multipart/form-data) response = client.http_request(method="POST", url_suffix=DLP_DICTIONARIES_PATH, params=params, files=files, use_dlp_base=True) # Extract created dictionary details dict_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "category": response.get("category"), "region_name": response.get("region_name"), "type": response.get("type"), "is_case_sensitive": response.get("is_case_sensitive"), "detection_technique": response.get("detection_technique"), "dictionary_metadata": response.get("dictionary_metadata"), "keywords": response.get("keywords"), "created_at": response.get("audit_metadata", {}).get("created_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Dictionary Created: {dict_info.get('name')}", dict_info, headers=["id", "name", "category", "type", "region_name", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpDictionaryCreate", outputs_key_field="id", outputs=dict_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_dictionaries_patch_command(client: Client, args: dict[str, Any]) -> CommandResults: """Partially update a DLP dictionary (JSON Merge Patch). Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ dictionary_id = args.get("dictionary_id") if not dictionary_id: raise ValueError("dictionary_id is required") # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-dictionary.ts # PATCH requires: category, name, original_file_name (cannot be cleared) name = args.get("name") category = args.get("category") original_file_name = args.get("original_file_name") if not name: raise ValueError("name is required for PATCH") if not category: raise ValueError("category is required for PATCH") if not original_file_name: raise ValueError("original_file_name is required for PATCH") request_body: dict[str, Any] = {"category": category, "name": name, "original_file_name": original_file_name} # Optional: description (can be null to clear) if args.get("description") is not None: desc_value = args.get("description") request_body["description"] = None if desc_value == "null" else desc_value # Optional: is_case_sensitive (can be null to clear) if args.get("is_case_sensitive") is not None: case_value = args.get("is_case_sensitive") if case_value == "null": request_body["is_case_sensitive"] = None else: request_body["is_case_sensitive"] = argToBoolean(case_value) # Optional: region_name (can be null to clear) if args.get("region_name") is not None: region_value = args.get("region_name") request_body["region_name"] = None if region_value == "null" else region_value # Call DLP dictionaries patch endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/dictionaries.ts # SDK: PATCH /v2/api/dictionaries/{resourceId} # Uses Content-Type: application/merge-patch+json response = client.http_request( method="PATCH", url_suffix=f"{DLP_DICTIONARIES_PATH}/{dictionary_id}", json_data=request_body, use_dlp_base=True, headers={"Content-Type": "application/merge-patch+json"}, ) # Extract updated dictionary details dict_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "category": response.get("category"), "region_name": response.get("region_name"), "type": response.get("type"), "is_case_sensitive": response.get("is_case_sensitive"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Dictionary Patched: {dict_info.get('name')}", dict_info, headers=["id", "name", "category", "type", "region_name", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpDictionaryPatch", outputs_key_field="id", outputs=dict_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_dictionaries_replace_command(client: Client, args: dict[str, Any]) -> CommandResults: """Replace (full update) a DLP dictionary by uploading a new keyword file. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ dictionary_id = args.get("dictionary_id") if not dictionary_id: raise ValueError("dictionary_id is required") # Build metadata (required fields) name = args.get("name") category = args.get("category") region_name = args.get("region_name") entry_id = args.get("entry_id") if not name: raise ValueError("name is required") if not category: raise ValueError("category is required") if not region_name: raise ValueError("region_name is required") if not entry_id: raise ValueError("entry_id is required (file entry ID from war room)") # Get uploaded file from war room file_info = demisto.getFilePath(entry_id) file_path = file_info["path"] file_name = file_info["name"] # Read file content with open(file_path, "rb") as f: file_content = f.read() # Build metadata JSON metadata: dict[str, Any] = {"category": category, "name": name, "original_file_name": file_name, "region_name": region_name} # Optional fields if args.get("description"): metadata["description"] = args.get("description") if args.get("is_case_sensitive") is not None: metadata["is_case_sensitive"] = argToBoolean(args.get("is_case_sensitive")) if args.get("type"): metadata["type"] = args.get("type") include_keywords = argToBoolean(args.get("include_keywords", False)) # Build query parameters params: dict[str, Any] = {} if include_keywords: params["keywords"] = "true" # Build multipart form data files = { "json": ("metadata.json", json.dumps(metadata).encode("utf-8"), "application/json"), "file": (file_name, file_content, "text/plain"), } # Call DLP dictionaries replace endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/dictionaries.ts # SDK: PUT /v2/api/dictionaries/{resourceId} (multipart/form-data) # API may return 200 with body or 204 with no body response = client.http_request( method="PUT", url_suffix=f"{DLP_DICTIONARIES_PATH}/{dictionary_id}", params=params, files=files, use_dlp_base=True ) # Handle both 200 (with body) and 204 (no body) responses if response: dict_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "category": response.get("category"), "region_name": response.get("region_name"), "type": response.get("type"), "is_case_sensitive": response.get("is_case_sensitive"), "keywords": response.get("keywords"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Dictionary Replaced: {dict_info.get('name')}", dict_info, headers=["id", "name", "category", "type", "region_name", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpDictionaryReplace", outputs_key_field="id", outputs=dict_info, readable_output=readable_output, raw_response=response, ) else: # 204 No Content response readable_output = ( f"## Prisma AIRs DLP Dictionary Replaced\n\n" f"Dictionary ID `{dictionary_id}` has been successfully replaced (204 No Content)." ) return CommandResults(readable_output=readable_output) def runtime_dlp_dictionaries_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Delete a DLP dictionary. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ dictionary_id = args.get("dictionary_id") if not dictionary_id: raise ValueError("dictionary_id is required") # Call DLP dictionaries delete endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/dictionaries.ts # SDK: DELETE /v2/api/dictionaries/{resourceId} # Returns 204 No Content on success client.http_request( method="DELETE", url_suffix=f"{DLP_DICTIONARIES_PATH}/{dictionary_id}", use_dlp_base=True, return_empty_response=True, # Proper XSOAR pattern for DELETE operations (204 No Content) ) # Action-tracking context so playbooks can confirm the deletion context_output = {"id": dictionary_id, "deleted": True, "status": "Successfully deleted"} readable_output = tableToMarkdown( "Prisma AIRs DLP Dictionary Deleted", context_output, headers=["id", "status"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpDictionaryDelete", outputs_key_field="id", outputs=context_output, readable_output=readable_output, ) def runtime_dlp_patterns_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List DLP data patterns. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ page = arg_to_number(args.get("page")) or 0 size = arg_to_number(args.get("size")) or 50 # Build query parameters params: dict[str, Any] = {"page": page, "size": size} # Call DLP patterns list endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-patterns.ts # CRITICAL: DLP v2 API uses https://api.dlp.paloaltonetworks.com (separate from SCM) response = client.http_request(method="GET", url_suffix=DLP_PATTERNS_PATH, params=params, use_dlp_base=True) # Extract patterns from paginated response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-pattern.ts patterns_data = response.get("content", []) patterns = [] for pattern in patterns_data: pattern_info = { "id": pattern.get("id"), "name": pattern.get("name"), "description": pattern.get("description"), "category": pattern.get("category"), "region_name": pattern.get("region_name"), "type": pattern.get("type"), "is_parent_managed": pattern.get("is_parent_managed"), "detection_technique": pattern.get("detection_technique"), "detection_sub_technique": pattern.get("detection_sub_technique"), "pattern_status": pattern.get("pattern_status"), "created_at": pattern.get("audit_metadata", {}).get("created_at"), "updated_at": pattern.get("audit_metadata", {}).get("updated_at"), "created_by": pattern.get("audit_metadata", {}).get("created_by"), "updated_by": pattern.get("audit_metadata", {}).get("updated_by"), } patterns.append(pattern_info) total_elements = response.get("total_elements", len(patterns)) total_pages = response.get("total_pages", 1) readable_output = tableToMarkdown( f"Prisma AIRs DLP Patterns (Page {page + 1}/{total_pages}, {len(patterns)} of {total_elements})", patterns, headers=["id", "name", "category", "type", "detection_technique", "pattern_status"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpPattern", outputs_key_field="id", outputs=patterns, readable_output=readable_output, raw_response=response, ) def runtime_dlp_patterns_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get a single DLP data pattern by ID. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ pattern_id = args.get("pattern_id") if not pattern_id: raise ValueError("pattern_id is required") # Call DLP patterns get endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-patterns.ts # SDK: GET /v2/api/data-patterns/{resourceId} response = client.http_request(method="GET", url_suffix=f"{DLP_PATTERNS_PATH}/{pattern_id}", use_dlp_base=True) # Extract pattern details from response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-pattern.ts pattern_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "status": response.get("status"), "license_type": response.get("license_type"), "is_parent_managed": response.get("is_parent_managed"), "version": response.get("version"), "detection_config": response.get("detection_config"), "matching_rules": response.get("matching_rules"), "tags": response.get("tags"), "created_at": response.get("audit_metadata", {}).get("created_at"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Pattern: {pattern_info.get('name')}", pattern_info, headers=["id", "name", "type", "status", "license_type", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpPatternGet", outputs_key_field="id", outputs=pattern_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_patterns_create_command(client: Client, args: dict[str, Any]) -> CommandResults: """Create a new DLP data pattern. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-pattern.ts # Required fields: name, type, detection_config name = args.get("name") pattern_type = args.get("type") detection_technique = args.get("detection_technique") if not name: raise ValueError("name is required") if not pattern_type: raise ValueError("type is required") if not detection_technique: raise ValueError("detection_technique is required") request_body: dict[str, Any] = {"name": name, "type": pattern_type, "detection_config": {"technique": detection_technique}} # Optional: supported_confidence_levels (array of low/medium/high) if args.get("supported_confidence_levels"): confidence_levels = args.get("supported_confidence_levels") if isinstance(confidence_levels, str): try: confidence_list = json.loads(confidence_levels) except (json.JSONDecodeError, ValueError): confidence_list = [c.strip() for c in confidence_levels.split(",")] else: confidence_list = confidence_levels request_body["detection_config"]["supported_confidence_levels"] = confidence_list # Optional: description if args.get("description"): request_body["description"] = args.get("description") # Optional: matching_rules (complex nested object) if args.get("matching_rules"): matching_rules_str = args.get("matching_rules") try: matching_rules = json.loads(matching_rules_str or "") request_body["matching_rules"] = matching_rules except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"matching_rules must be valid JSON: {e}") # Optional: tags (classification, compliance, geography arrays) if args.get("tags"): tags_str = args.get("tags") try: tags = json.loads(tags_str or "") request_body["tags"] = tags except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"tags must be valid JSON: {e}") # Call DLP patterns create endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-patterns.ts # SDK: POST /v2/api/data-patterns response = client.http_request(method="POST", url_suffix=DLP_PATTERNS_PATH, json_data=request_body, use_dlp_base=True) # Extract created pattern details pattern_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "status": response.get("status"), "license_type": response.get("license_type"), "version": response.get("version"), "detection_config": response.get("detection_config"), "matching_rules": response.get("matching_rules"), "tags": response.get("tags"), "created_at": response.get("audit_metadata", {}).get("created_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Pattern Created: {pattern_info.get('name')}", pattern_info, headers=["id", "name", "type", "status", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpPatternCreate", outputs_key_field="id", outputs=pattern_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_patterns_patch_command(client: Client, args: dict[str, Any]) -> CommandResults: """Partially update a DLP data pattern (JSON Merge Patch). Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ pattern_id = args.get("pattern_id") if not pattern_id: raise ValueError("pattern_id is required") # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-pattern.ts # PATCH requires: name, type, detection_config (cannot be cleared) name = args.get("name") pattern_type = args.get("type") detection_technique = args.get("detection_technique") if not name: raise ValueError("name is required for PATCH") if not pattern_type: raise ValueError("type is required for PATCH") if not detection_technique: raise ValueError("detection_technique is required for PATCH") request_body: dict[str, Any] = {"name": name, "type": pattern_type, "detection_config": {"technique": detection_technique}} # Optional: supported_confidence_levels if args.get("supported_confidence_levels"): confidence_levels = args.get("supported_confidence_levels") if isinstance(confidence_levels, str): try: confidence_list = json.loads(confidence_levels) except (json.JSONDecodeError, ValueError): confidence_list = [c.strip() for c in confidence_levels.split(",")] else: confidence_list = confidence_levels request_body["detection_config"]["supported_confidence_levels"] = confidence_list # Optional: description (can be null to clear) if args.get("description") is not None: desc_value = args.get("description") request_body["description"] = None if desc_value == "null" else desc_value # Optional: matching_rules (can be null to clear) if args.get("matching_rules") is not None: matching_rules_str = args.get("matching_rules") if matching_rules_str == "null": request_body["matching_rules"] = None else: try: request_body["matching_rules"] = json.loads(matching_rules_str or "") except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"matching_rules must be valid JSON or 'null': {e}") # Optional: tags (can be null to clear) if args.get("tags") is not None: tags_str = args.get("tags") if tags_str == "null": request_body["tags"] = None else: try: request_body["tags"] = json.loads(tags_str or "") except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"tags must be valid JSON or 'null': {e}") # Call DLP patterns patch endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-patterns.ts # SDK: PATCH /v2/api/data-patterns/{resourceId} # Uses Content-Type: application/merge-patch+json response = client.http_request( method="PATCH", url_suffix=f"{DLP_PATTERNS_PATH}/{pattern_id}", json_data=request_body, use_dlp_base=True, headers={"Content-Type": "application/merge-patch+json"}, ) # Extract updated pattern details pattern_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "status": response.get("status"), "version": response.get("version"), "detection_config": response.get("detection_config"), "matching_rules": response.get("matching_rules"), "tags": response.get("tags"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Pattern Patched: {pattern_info.get('name')}", pattern_info, headers=["id", "name", "type", "status", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpPatternPatch", outputs_key_field="id", outputs=pattern_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_patterns_replace_command(client: Client, args: dict[str, Any]) -> CommandResults: """Replace (full update) a DLP data pattern. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ pattern_id = args.get("pattern_id") if not pattern_id: raise ValueError("pattern_id is required") # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-pattern.ts # Required fields: name, type, detection_config name = args.get("name") pattern_type = args.get("type") detection_technique = args.get("detection_technique") if not name: raise ValueError("name is required") if not pattern_type: raise ValueError("type is required") if not detection_technique: raise ValueError("detection_technique is required") request_body: dict[str, Any] = {"name": name, "type": pattern_type, "detection_config": {"technique": detection_technique}} # Optional: supported_confidence_levels if args.get("supported_confidence_levels"): confidence_levels = args.get("supported_confidence_levels") if isinstance(confidence_levels, str): try: confidence_list = json.loads(confidence_levels) except (json.JSONDecodeError, ValueError): confidence_list = [c.strip() for c in confidence_levels.split(",")] else: confidence_list = confidence_levels request_body["detection_config"]["supported_confidence_levels"] = confidence_list # Optional: description if args.get("description"): request_body["description"] = args.get("description") # Optional: matching_rules if args.get("matching_rules"): matching_rules_str = args.get("matching_rules") try: request_body["matching_rules"] = json.loads(matching_rules_str or "") except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"matching_rules must be valid JSON: {e}") # Optional: tags if args.get("tags"): tags_str = args.get("tags") try: request_body["tags"] = json.loads(tags_str or "") except (json.JSONDecodeError, ValueError) as e: raise ValueError(f"tags must be valid JSON: {e}") # Call DLP patterns replace endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-patterns.ts # SDK: PUT /v2/api/data-patterns/{resourceId} response = client.http_request( method="PUT", url_suffix=f"{DLP_PATTERNS_PATH}/{pattern_id}", json_data=request_body, use_dlp_base=True ) # Extract updated pattern details pattern_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "status": response.get("status"), "version": response.get("version"), "detection_config": response.get("detection_config"), "matching_rules": response.get("matching_rules"), "tags": response.get("tags"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Pattern Replaced: {pattern_info.get('name')}", pattern_info, headers=["id", "name", "type", "status", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpPatternReplace", outputs_key_field="id", outputs=pattern_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_patterns_delete_command(client: Client, args: dict[str, Any]) -> CommandResults: """Delete (soft-delete/archive) a DLP data pattern. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ pattern_id = args.get("pattern_id") if not pattern_id: raise ValueError("pattern_id is required") # Call DLP patterns delete endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-patterns.ts # SDK: DELETE /v2/api/data-patterns/{resourceId} # Returns 204 No Content on success client.http_request( method="DELETE", url_suffix=f"{DLP_PATTERNS_PATH}/{pattern_id}", use_dlp_base=True, return_empty_response=True, # Proper XSOAR pattern for DELETE operations (204 No Content) ) # Action-tracking context so playbooks can confirm the deletion (soft-delete / archive) context_output = {"id": pattern_id, "deleted": True, "status": "Successfully archived"} readable_output = tableToMarkdown( "Prisma AIRs DLP Pattern Deleted", context_output, headers=["id", "status"], headerTransform=lambda h: h.replace("_", " ").title(), removeNull=True, ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpPatternDelete", outputs_key_field="id", outputs=context_output, readable_output=readable_output, ) def runtime_dlp_filtering_profiles_list_command(client: Client, args: dict[str, Any]) -> CommandResults: """List DLP filtering profiles. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ page = arg_to_number(args.get("page")) or 0 size = arg_to_number(args.get("size")) or 50 # Build query parameters params: dict[str, Any] = {"page": page, "size": size} # Call DLP filtering profiles list endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-filtering-profiles.ts # CRITICAL: DLP v2 API uses https://api.dlp.paloaltonetworks.com (separate from SCM) response = client.http_request(method="GET", url_suffix=DLP_FILTERING_PROFILES_PATH, params=params, use_dlp_base=True) # Extract filtering profiles from paginated response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-filtering-profile.ts profiles_data = response.get("content", []) filtering_profiles = [] for profile in profiles_data: profile_info = { "id": profile.get("id"), "name": profile.get("name"), "description": profile.get("description"), "type": profile.get("type"), "default_action": profile.get("default_action"), "is_parent_managed": profile.get("is_parent_managed"), "created_at": profile.get("audit_metadata", {}).get("created_at"), "updated_at": profile.get("audit_metadata", {}).get("updated_at"), "created_by": profile.get("audit_metadata", {}).get("created_by"), "updated_by": profile.get("audit_metadata", {}).get("updated_by"), } filtering_profiles.append(profile_info) total_elements = response.get("total_elements", len(filtering_profiles)) total_pages = response.get("total_pages", 1) readable_output = tableToMarkdown( f"Prisma AIRs DLP Filtering Profiles (Page {page + 1}/{total_pages}, {len(filtering_profiles)} of {total_elements})", filtering_profiles, headers=["id", "name", "type", "default_action", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpFilteringProfile", outputs_key_field="id", outputs=filtering_profiles, readable_output=readable_output, raw_response=response, ) def runtime_dlp_filtering_profiles_get_command(client: Client, args: dict[str, Any]) -> CommandResults: """Get a single DLP filtering profile by ID. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") # Call DLP filtering profiles get endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-filtering-profiles.ts # SDK: GET /v2/api/data-filtering-profiles/{resourceId} response = client.http_request(method="GET", url_suffix=f"{DLP_FILTERING_PROFILES_PATH}/{profile_id}", use_dlp_base=True) # Extract profile details from response # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-filtering-profile.ts profile_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "data_profile_id": response.get("data_profile_id"), "direction": response.get("direction"), "file_based": response.get("file_based"), "non_file_based": response.get("non_file_based"), "log_severity": response.get("log_severity"), "scan_type": response.get("scan_type"), "is_end_user_coaching_enabled": response.get("is_end_user_coaching_enabled"), "is_granular_profile": response.get("is_granular_profile"), "is_parent_managed": response.get("is_parent_managed"), "euc_template_id": response.get("euc_template_id"), "version": response.get("version"), "file_type": response.get("file_type"), "created_at": response.get("audit_metadata", {}).get("created_at"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Filtering Profile: {profile_info.get('name')}", profile_info, headers=["id", "name", "type", "direction", "file_based", "non_file_based", "log_severity", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpFilteringProfileGet", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def runtime_dlp_filtering_profiles_replace_command(client: Client, args: dict[str, Any]) -> CommandResults: """Replace (full update) a DLP filtering profile. Args: client: Prisma AIRs API client. args: Command arguments from XSOAR. Returns: CommandResults: Results to return to XSOAR. """ profile_id = args.get("profile_id") if not profile_id: raise ValueError("profile_id is required") # Build request body # Schema: ./knowledge/prisma-airs-sdk-main/src/models/dlp-data-filtering-profile.ts # Required fields: file_based, non_file_based request_body: dict[str, Any] = { "file_based": argToBoolean(args.get("file_based", False)), "non_file_based": argToBoolean(args.get("non_file_based", False)), } # Optional fields if args.get("description"): request_body["description"] = args.get("description") if args.get("direction"): request_body["direction"] = args.get("direction") if args.get("log_severity"): request_body["log_severity"] = args.get("log_severity") if args.get("scan_type"): request_body["scan_type"] = args.get("scan_type") if args.get("data_profile_id"): request_body["data_profile_id"] = arg_to_number(args.get("data_profile_id")) if args.get("euc_template_id"): request_body["euc_template_id"] = args.get("euc_template_id") if args.get("is_end_user_coaching_enabled") is not None: request_body["is_end_user_coaching_enabled"] = argToBoolean(args.get("is_end_user_coaching_enabled")) if args.get("is_granular_profile") is not None: request_body["is_granular_profile"] = argToBoolean(args.get("is_granular_profile")) # Handle file_type as comma-separated string or JSON array if args.get("file_type"): file_type_value = args.get("file_type") if isinstance(file_type_value, str): try: # Try parsing as JSON array first file_type_list = json.loads(file_type_value) except (json.JSONDecodeError, ValueError): # Fall back to comma-separated string file_type_list = [ft.strip() for ft in file_type_value.split(",")] else: file_type_list = file_type_value request_body["file_type"] = file_type_list # Call DLP filtering profiles replace endpoint # Reference: ./knowledge/prisma-airs-sdk-main/src/management/dlp/data-filtering-profiles.ts # SDK: PUT /v2/api/data-filtering-profiles/{resourceId} response = client.http_request( method="PUT", url_suffix=f"{DLP_FILTERING_PROFILES_PATH}/{profile_id}", json_data=request_body, use_dlp_base=True ) # Extract updated profile details from response profile_info = { "id": response.get("id"), "name": response.get("name"), "description": response.get("description"), "tenant_id": response.get("tenant_id"), "type": response.get("type"), "data_profile_id": response.get("data_profile_id"), "direction": response.get("direction"), "file_based": response.get("file_based"), "non_file_based": response.get("non_file_based"), "log_severity": response.get("log_severity"), "scan_type": response.get("scan_type"), "is_end_user_coaching_enabled": response.get("is_end_user_coaching_enabled"), "is_granular_profile": response.get("is_granular_profile"), "is_parent_managed": response.get("is_parent_managed"), "version": response.get("version"), "created_at": response.get("audit_metadata", {}).get("created_at"), "updated_at": response.get("audit_metadata", {}).get("updated_at"), "created_by": response.get("audit_metadata", {}).get("created_by"), "updated_by": response.get("audit_metadata", {}).get("updated_by"), } readable_output = tableToMarkdown( f"Prisma AIRs DLP Filtering Profile Updated: {profile_info.get('name')}", profile_info, headers=["id", "name", "type", "direction", "file_based", "non_file_based", "log_severity", "description"], headerTransform=lambda h: h.replace("_", " ").title(), ) return CommandResults( outputs_prefix=f"{PA_OUTPUT_PREFIX}DlpFilteringProfileReplace", outputs_key_field="id", outputs=profile_info, readable_output=readable_output, raw_response=response, ) def main() -> None: """Main function for Prisma AIRs AI Runtime Security integration.""" params = demisto.params() args = demisto.args() command = demisto.command() demisto.debug(f"Command being called is {command}") try: # Client configuration (scoped credentials for the Runtime Security + DLP planes) base_url = params.get("url", "https://api.sase.paloaltonetworks.com") credentials = params.get("credentials", {}) client_id = credentials.get("identifier", "") client_secret = credentials.get("password", "") tsg_id = params.get("tsg_id") runtime_api_key = params.get("runtime_api_key", {}).get("password", "") or params.get("runtime_api_key", "") scanner_base_url = params.get("scanner_base_url") dlp_base_url = params.get("dlp_base_url") verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) headers: dict[str, str] = {} client = Client( base_url=base_url, client_id=client_id, client_secret=client_secret, tsg_id=tsg_id, runtime_api_key=runtime_api_key, scanner_base_url=scanner_base_url, dlp_base_url=dlp_base_url, verify=verify_certificate, proxy=proxy, headers=headers, ) if command == "test-module": result = test_module(client) return_results(result) elif command == "prisma-airs-runtime-scan": return_results(runtime_scan_command(client, args)) elif command == "prisma-airs-runtime-api-keys-list": return_results(runtime_api_keys_list_command(client, args)) elif command == "prisma-airs-runtime-api-keys-create": return_results(runtime_api_keys_create_command(client, args)) elif command == "prisma-airs-runtime-api-keys-regenerate": return_results(runtime_api_keys_regenerate_command(client, args)) elif command == "prisma-airs-runtime-api-keys-delete": return_results(runtime_api_keys_delete_command(client, args)) elif command == "prisma-airs-runtime-profiles-list": return_results(runtime_profiles_list_command(client, args)) elif command == "prisma-airs-runtime-profiles-get": return_results(runtime_profiles_get_command(client, args)) elif command == "prisma-airs-runtime-profiles-create": return_results(runtime_profiles_create_command(client, args)) elif command == "prisma-airs-runtime-profiles-update": return_results(runtime_profiles_update_command(client, args)) elif command == "prisma-airs-runtime-profiles-delete": return_results(runtime_profiles_delete_command(client, args)) elif command == "prisma-airs-runtime-customer-apps-list": return_results(runtime_customer_apps_list_command(client, args)) elif command == "prisma-airs-runtime-customer-apps-get": return_results(runtime_customer_apps_get_command(client, args)) elif command == "prisma-airs-runtime-customer-apps-update": return_results(runtime_customer_apps_update_command(client, args)) elif command == "prisma-airs-runtime-customer-apps-consumption": return_results(runtime_customer_apps_consumption_command(client, args)) elif command == "prisma-airs-runtime-customer-apps-violations": return_results(runtime_customer_apps_violations_command(client, args)) elif command == "prisma-airs-runtime-customer-apps-delete": return_results(runtime_customer_apps_delete_command(client, args)) elif command == "prisma-airs-runtime-deployment-profiles-list": return_results(runtime_deployment_profiles_list_command(client, args)) elif command == "prisma-airs-runtime-dlp-profiles-list": return_results(runtime_dlp_profiles_list_command(client, args)) elif command == "prisma-airs-runtime-dlp-profiles-get": return_results(runtime_dlp_profiles_get_command(client, args)) elif command == "prisma-airs-runtime-dlp-profiles-create": return_results(runtime_dlp_profiles_create_command(client, args)) elif command == "prisma-airs-runtime-dlp-profiles-patch": return_results(runtime_dlp_profiles_patch_command(client, args)) elif command == "prisma-airs-runtime-dlp-profiles-replace": return_results(runtime_dlp_profiles_replace_command(client, args)) elif command == "prisma-airs-runtime-dlp-profiles-delete": return_results(runtime_dlp_profiles_delete_command(client, args)) elif command == "prisma-airs-runtime-dlp-dictionaries-list": return_results(runtime_dlp_dictionaries_list_command(client, args)) elif command == "prisma-airs-runtime-dlp-dictionaries-get": return_results(runtime_dlp_dictionaries_get_command(client, args)) elif command == "prisma-airs-runtime-dlp-dictionaries-create": return_results(runtime_dlp_dictionaries_create_command(client, args)) elif command == "prisma-airs-runtime-dlp-dictionaries-patch": return_results(runtime_dlp_dictionaries_patch_command(client, args)) elif command == "prisma-airs-runtime-dlp-dictionaries-replace": return_results(runtime_dlp_dictionaries_replace_command(client, args)) elif command == "prisma-airs-runtime-dlp-dictionaries-delete": return_results(runtime_dlp_dictionaries_delete_command(client, args)) elif command == "prisma-airs-runtime-dlp-patterns-list": return_results(runtime_dlp_patterns_list_command(client, args)) elif command == "prisma-airs-runtime-dlp-patterns-get": return_results(runtime_dlp_patterns_get_command(client, args)) elif command == "prisma-airs-runtime-dlp-patterns-create": return_results(runtime_dlp_patterns_create_command(client, args)) elif command == "prisma-airs-runtime-dlp-patterns-patch": return_results(runtime_dlp_patterns_patch_command(client, args)) elif command == "prisma-airs-runtime-dlp-patterns-replace": return_results(runtime_dlp_patterns_replace_command(client, args)) elif command == "prisma-airs-runtime-dlp-patterns-delete": return_results(runtime_dlp_patterns_delete_command(client, args)) elif command == "prisma-airs-runtime-dlp-filtering-profiles-list": return_results(runtime_dlp_filtering_profiles_list_command(client, args)) elif command == "prisma-airs-runtime-dlp-filtering-profiles-get": return_results(runtime_dlp_filtering_profiles_get_command(client, args)) elif command == "prisma-airs-runtime-dlp-filtering-profiles-replace": return_results(runtime_dlp_filtering_profiles_replace_command(client, args)) elif command == "prisma-airs-runtime-topics-list": return_results(runtime_topics_list_command(client, args)) elif command == "prisma-airs-runtime-topics-get": return_results(runtime_topics_get_command(client, args)) elif command == "prisma-airs-runtime-topics-create": return_results(runtime_topics_create_command(client, args)) elif command == "prisma-airs-runtime-topics-update": return_results(runtime_topics_update_command(client, args)) elif command == "prisma-airs-runtime-topics-delete": return_results(runtime_topics_delete_command(client, args)) elif command == "prisma-airs-runtime-topics-apply": return_results(runtime_topics_apply_command(client, args)) elif command == "prisma-airs-runtime-bulk-scan": return_results(runtime_bulk_scan_command(client, args)) else: raise NotImplementedError(f"Command {command} is not implemented") except Exception as e: demisto.error(traceback.format_exc()) return_error(f"Failed to execute {command} command.\nError:\n{str(e)}") if __name__ in ("__main__", "__builtin__", "builtins"): main()