1+ <?xml version =" 1.0" encoding =" UTF-8" ?>
2+ <Workflow name =" Wiz" version =" 1.0" xmlns =" http://qradar.ibm.com/UniversalCloudRESTAPI/Workflow/V1" >
3+
4+ <Parameters >
5+ <Parameter name =" client_id" label =" Client ID" required =" true" />
6+ <Parameter name =" client_secret" label =" Client Secret" required =" true" secret =" true" />
7+ <Parameter name =" token_url_domain" label =" JWT Auth Endpoint" required =" true" />
8+ <Parameter name =" host" label =" API Endpoint" required =" true" />
9+ <Parameter name =" auth_type" label =" Authentication Type" required =" true" />
10+ <Parameter name =" detections_gql_query" label =" Detections GraphQL Query" required =" true" />
11+ <Parameter name =" audit_logs_gql_query" label =" GraphQL Query" required =" false" />
12+ <Parameter name =" gql_query" label =" GraphQL Query" required =" false" />
13+ </Parameters >
14+
15+
16+ <Actions >
17+ <Log type =" INFO" message =" WIZ: Workflow Actions started for Detections..." />
18+ <Initialize path =" /user_agent_header" value =" 127fb887-6a5e-99be-c1ef-5c62031e9614/qradar/2.0.4" />
19+ <If condition =" /detection_bookmark != null" >
20+ <!-- Format Date to be passed in fetching events -->
21+ <FormatDate pattern =" yyyy-MM-dd'T'HH:mm:ss'Z'" timeZone =" UTC" time =" ${/detection_bookmark}" savePath =" /detection_timestamp" />
22+ </If >
23+
24+
25+ <If condition =" /detection_timestamp != null" >
26+ <Log type =" INFO" message =" WIZ: Incremental Polling started for Detections. Pulling Detections from: ${/detection_timestamp}" />
27+ </If >
28+ <Else >
29+ <!-- Set the date for 14 days before Historical Polling -->
30+ <FormatDate pattern =" yyyy-MM-dd'T'HH:mm:ss'Z'" timeZone =" UTC" time =" ${time() - 14 * 86400000}" savePath =" /detection_timestamp" />
31+ <Log type =" INFO" message =" WIZ: Historical Polling started. Pulling all Detections from: ${/detection_timestamp}" />
32+ </Else >
33+ <Set path =" /detection_bookmark" value =" ${time()}" />
34+ <FormatDate pattern =" yyyy-MM-dd'T'HH:mm:ss'Z'" timeZone =" UTC" time =" ${/detection_bookmark}" savePath =" /before_time" />
35+ <!-- Updating the GraphQL query variable for Incremental/Historical Polling -->
36+ <Set
37+ path =" /detection_gql_query_variables"
38+ value =' {
39+ "first":500,
40+ "filterBy": {
41+ "createdAt":{
42+ "after": "${/detection_timestamp}"
43+ }
44+ },
45+ "orderBy": {
46+ "field": "CREATED_AT",
47+ "direction": "DESC"
48+ }
49+ }'
50+ />
51+
52+
53+ <!-- Initialize the Audience Parameter -->
54+ <Initialize path =" /audience_parameter" value =" wiz-api" />
55+
56+ <If condition =" '${/auth_type}' = 'auth0'" >
57+ <Set path =" /audience_parameter" value =" beyond-api" />
58+ </If >
59+
60+ <!-- Fetch API Token -->
61+ <CallEndpoint url =" https://${/token_url_domain}/oauth/token" method =" POST" savePath =" /get_access_token" >
62+ <RequestHeader name =" content-type" value =" application/x-www-form-urlencoded" />
63+ <RequestHeader name =" User-Agent" value =" ${/user_agent_header}" />
64+ <UrlEncodedFormRequestBody >
65+ <Parameter name =" grant_type" value =" client_credentials" />
66+ <Parameter name =" client_id" value =" ${/client_id}" />
67+ <Parameter name =" client_secret" value =" ${/client_secret}" />
68+ <Parameter name =" audience" value =" ${/audience_parameter}" />
69+ </UrlEncodedFormRequestBody >
70+ </CallEndpoint >
71+
72+ <Log type =" INFO" message =" WIZ: Auth Token API call status code:: ${/get_access_token/status_code}" />
73+
74+ <!-- Handle Errors -->
75+ <If condition =" /get_access_token/status_code != 200" >
76+ <Log type =" ERROR" message =" WIZ: Workflow Aborting.. API Token Failure. Error:: ${/get_access_token/body}" />
77+ <Abort reason =" Failed requesting API token. Error: ${/get_access_token/body}" />
78+ </If >
79+
80+ <!-- Extract the Access Token -->
81+ <Set path =" /access_token" value =" ${/get_access_token/body/access_token}" />
82+
83+ <Log type =" INFO" message =" WIZ: First API call for Detections: Using this GraphQL variable ${/detection_gql_query_variables}" />
84+
85+ <!-- Fetch Events -->
86+ <CallEndpoint url =" https://${/host}/graphql" method =" POST" savePath =" /get_detections" >
87+ <RequestHeader name =" Authorization" value =" Bearer ${/access_token}" />
88+ <RequestHeader name =" content-type" value =" application/json" />
89+ <RequestHeader name =" User-Agent" value =" ${/user_agent_header}" />
90+ <RequestBody type =" application/json" encoding =" UTF-8" >
91+ {
92+ "query": "${/detections_gql_query}",
93+ "variables": ${/detection_gql_query_variables}
94+ }
95+ </RequestBody >
96+ </CallEndpoint >
97+
98+ <Log type =" INFO" message =" WIZ: First API call for Detections status code:: ${/get_detections/status_code}" />
99+
100+ <!-- Handle Errors -->
101+ <If condition =" /get_detections/status_code != 200" >
102+ <Log type =" ERROR" message =" WIZ: Workflow Aborting.. Failure while fetching Detections. Error:: ${/get_detections/body}" />
103+ <Abort reason =" Failed while fetching Wiz Detections. Error:: ${/get_detections/body}" />
104+ </If >
105+
106+ <Log type =" INFO" message =" WIZ: First API call fetched ${count(/get_detections/body/data/detections/nodes)} Wiz Detections" />
107+
108+ <!-- Post Events, if any -->
109+ <If condition =" count(/get_detections/body/data/detections/nodes) > 0" >
110+ <PostEvents path =" /get_detections/body/data/detections/nodes" source =" ${/host}__Detection" />
111+ <Log type =" INFO" message =" WIZ: First API call for Detections is done. Sent ${count(/get_detections/body/data/detections/nodes)} Wiz Detection Events to QRadar" />
112+
113+ </If >
114+
115+
116+ <!-- Fetch remaining events -->
117+ <While condition =" /get_detections/body/data/detections/pageInfo/hasNextPage" >
118+
119+ <Set
120+ path =" /detection_gql_query_variables"
121+ value =' {
122+ "first":500,
123+ "filterBy": {
124+ "createdAt":{
125+ "after": "${/detection_timestamp}"
126+ }
127+ },
128+ "orderBy": {
129+ "field": "CREATED_AT",
130+ "direction": "DESC"
131+ },
132+ "after": "${/get_detections/body/data/detections/pageInfo/endCursor}"
133+ }'
134+ />
135+
136+
137+
138+ <Log type =" INFO" message =" WIZ: Paginated API call for Detections: Using this GraphQL variable : ${/detection_gql_query_variables}" />
139+
140+ <!-- Fetch events -->
141+ <CallEndpoint url =" https://${/host}/graphql" method =" POST" savePath =" /get_detections" >
142+ <RequestHeader name =" Authorization" value =" Bearer ${/access_token}" />
143+ <RequestHeader name =" content-type" value =" application/json" />
144+ <RequestHeader name =" User-Agent" value =" ${/user_agent_header}" />
145+ <RequestBody type =" application/json" encoding =" UTF-8" >
146+ {
147+ "query": "${/detections_gql_query}",
148+ "variables": ${/detection_gql_query_variables}
149+ }
150+ </RequestBody >
151+ </CallEndpoint >
152+
153+ <Log type =" INFO" message =" WIZ: Paginated API call for Detections status code: ${/get_detections/status_code}" />
154+
155+ <!-- Handle Errors -->
156+ <If condition =" /get_detections/status_code != 200" >
157+ <Log type =" ERROR" message =" WIZ: Workflow Aborting.. Failure while fetching Detections. Error:: ${/get_detections/body}" />
158+ <Abort reason =" Failed while fetching Wiz Detections. Error:: ${/get_detections/body}" />
159+ </If >
160+
161+ <Log type =" INFO" message =" WIZ: Paginated API call for Detections. Fetched ${count(/get_detections/body/data/detections/nodes)} Wiz Detections" />
162+
163+ <!-- Post Events, if any -->
164+ <If condition =" count(/get_detections/body/data/detections/nodes) > 0" >
165+ <PostEvents path =" /get_detections/body/data/detections/nodes" source =" ${/host}__Detection" />
166+ <Log type =" INFO" message =" WIZ: Paginated API call for Detections is done. Sent ${count(/get_detections/body/data/detections/nodes)} Wiz Detections to QRadar" />
167+ </If >
168+
169+
170+ </While >
171+ <Set path =" /detection_bookmark" value =" ${/detection_bookmark + 1000}" />
172+ <Log type =" INFO" message =" WIZ: Updated the bookmark for Detections ${/detection_bookmark}." />
173+ <Log type =" INFO" message =" WIZ: All Actions for Detections are completed." />
174+
175+
176+ </Actions >
177+
178+ <Tests >
179+ <DNSResolutionTest host =" ${/host}" />
180+ <TCPConnectionTest host =" ${/host}" />
181+ <SSLHandshakeTest host =" ${/host}" />
182+ <DNSResolutionTest host =" ${/token_url_domain}" />
183+ <TCPConnectionTest host =" ${/token_url_domain}" />
184+ <SSLHandshakeTest host =" ${/token_url_domain}" />
185+ </Tests >
186+
187+
188+ </Workflow >
0 commit comments