RFPD-96030: add rf-alert-lookup command#12
Merged
aommm merged 1 commit intoMar 18, 2026
Merged
Conversation
0382e72 to
d395c91
Compare
d395c91 to
79f2dc4
Compare
d395cb2
into
pack_v3_rf_alert_images_command_error_handling
21 checks passed
hildenjohannes
pushed a commit
that referenced
this pull request
Jun 22, 2026
…and resource filters (demisto#44217) * Wiz content pack v2.0.3: bidirectional mirroring, null-safety fixes, and resource filters (demisto#43959) * Truncate issue notes to 1400 chars to prevent API errors (WZ-95550) The Wiz API rejects notes exceeding 1400 characters, causing a 4.41% error rate on createIssueNote. Add truncate_note() to both Wiz and WizDefend integrations, applied in set_issue_comment/set_issue_note and reject_or_resolve_issue. * Remove unsupported resolution reasons from XSOAR commands (WZ-100065) Remove system-assigned resolution reasons (DETECTION_EXPIRED, CONTROL_DISABLED, CONTROL_DELETED) that the updateIssue mutation does not accept from wiz-reject-issue and wiz-resolve-issue commands. Also remove OBJECT_DELETED and ISSUE_FIXED from wiz-reject-issue since they are only valid for resolve, not reject. Update WizDefend README to match its YAML definition. Bump integration versions (Wiz 1.5.0, WizDefend 1.1.0) and pack version to 2.0.2. * Remove deprecated runtimeExecutionDataId from evidence query (WZ-83470) The runtimeExecutionDataId field was removed from the CloudEventRuntimeDetails GraphQL type, causing wiz-get-issue-evidence to always fail with: "Cannot query field runtimeExecutionDataId on type CloudEventRuntimeDetails" * Add project_ids, native_types, and updatedAt filters to wiz-get-resources (WZ-51676) * Fix test_has_next_page missing getLastRun mock The test was failing because demisto.getLastRun() returned {} causing fetch_issues to call dateparser.parse which isn't available locally. * Add bidirectional mirroring to Wiz XSOAR integration (WZ-64007) Add incoming (Wiz → XSOAR) and outgoing (XSOAR → Wiz) mirroring support so XSOAR incidents stay in sync with Wiz issues. - Add mirror_direction, mirror_limit, comment_tag config params - Implement get-remote-data, get-modified-remote-data, update-remote-system, and get-mapping-fields commands - Add incoming mapper fields (dbotMirror*) and outgoing mapper - Use statusChangedAt filter for change detection (updatedAt not available in Wiz API) - Prevent mirror loops via XSOAR_MIRROR_MARKER in note text - Default mirror direction is None (preserves existing behavior) * Address review findings: update release notes, README, and mirror direction validation * Fix clearing due date not propagating to Wiz via mirror * Fix null detection descriptions and fetch window overlap in WizDefend (WZ-102115, WZ-103753) WZ-102115: Add build_fallback_description() to generate descriptions from severity, rule name, and detection ID when the API returns null. Sanitize null descriptions in get_filtered_detections() and map description to the XSOAR incident details field in build_incidents(). WZ-103753: Fix _save_pagination_context() saving BEFORE = stored_after instead of stored_before, which corrupted pagination windows. Change get_api_before_parameter() to use a lagged boundary (now - fetch_interval) for fresh runs instead of raw now, preventing fetch window overlap. * Extract _fetch_all_issue_nodes helper and fix missing pagination in get_modified_remote_data get_modified_remote_data_command was not paginating, silently dropping issues beyond the first page. Extracted the repeated pagination loop into a shared helper and applied it to all three callers. * Fix outgoing mirror status sync silently failing for resolve/reject Mirror was calling resolve_issue/reject_issue which (a) passed empty note strings that failed the falsy check in reject_or_resolve_issue, and (b) hit the THREAT_DETECTION type restriction in resolve_issue. Both failures returned error strings swallowed by try/except. Now calls reject_or_resolve_issue directly with a default note, bypassing the type restriction meant for the XSOAR command. * Fix incident close ignoring resolution reason and improve mirror config clarity - Pass delta resolutionReason to _handle_incident_closed instead of always using WONT_FIX default - Elevate _handle_incident_closed error log from debug to info - Clarify mirror_limit param is a page size, not a total cap - Prevent _fetch_all_issue_nodes from mutating caller's variables dict * Add unit tests for 11 coverage gaps in Wiz and WizDefend mirror/pagination/filter code Fill gaps identified in v2.0.2 test plan: - _fetch_all_issue_nodes multi-page cursor propagation and node concatenation - _mirror_status_to_wiz for in_progress and rejected statuses - _handle_field_changes with wizissueduedate fallback key and skip_status=True - update_remote_system_command full flow (delta+close+entries) - get_remote_data_command with service account [SA] note format - WizMirrorDirection.from_params() for Outgoing and invalid values - get_resources with updated_at_before filter and both filters combined - get_resources error message asserting new param names - reject_or_resolve_issue comment truncation at call site - get_filtered_detections null description fallback through integrated flow * Fix null-safety bugs in notes/ruleMatch handling and add missing resolutionReason to outgoing mapper - Fix _build_new_note_entries crash when API returns notes: null (.get("notes", []) → .get("notes") or []) - Fix clear_issue_note crash on notes: null and UnboundLocalError when no notes exist - Fix WizDefend clear_threat_comments crash on notes: null - Fix WizDefend build_fallback_description and build_incidents crash on ruleMatch: null - Add resolutionReason to outgoing mapper so XSOAR close reasons propagate to Wiz - Add unit tests for _build_new_note_entries, _attach_mirror_metadata, and null edge cases * Fix WizDefend null-safety bug for ruleMatch={"rule":None} and add reject/resolve payload-shape tests build_fallback_description (WizDefend.py:1638) and build_incidents (WizDefend.py:1654) crashed with `'NoneType' object has no attribute 'get'` when a detection's ruleMatch was {"rule": None}. The existing defense `(... or {}).get(RULE, {})` only catches RULE_MATCH=None — when the `rule` key is present with value None, .get(RULE, {}) returns None (default only fires for missing keys). Switched both call sites to `((... or {}).get(RULE) or {}).get(NAME)` to coerce None to {} after each chained get. Added regression test test_build_incidents_rulematch_rule_null covering the {"rule": None} case (the existing test_build_incidents_rulematch_null only covered ruleMatch=None). Also added two symmetric payload-shape tests for the Wiz reject/resolve path (test_reject_issue_sends_rejected_status_and_reason, test_resolve_issue_sends_resolved_status_and_reason) that capture the GraphQL mutation variables and assert status/resolutionReason/note are sent correctly. Closes a coverage gap where the existing reject/resolve tests only verified the API response was returned, not the request shape. * Address v2.0.2 documentation audit (Layer 7) Resolves 17 of 18 doc-audit items raised against the v2.0.2 changes. Item #12 (wiz-get-resources structured outputs schema) deferred — needs Wiz API response shape inspection. Wiz README: - Fix copy-paste descriptions: wiz-issue-in-progress, wiz-reopen-issue example arg name, wiz-reject-issue, wiz-get-project-team - Document 1400-char note truncation on reject_note, resolution_note, set-issue-note - Add Mirroring section: direction matrix, mirrored-fields table, loop prevention, truncation, and the 4 mirror-engine commands (get-remote-data, get-modified-remote-data, update-remote-system, get-mapping-fields) marked as not for manual use - Fix mirror_limit description (was "Maximum incidents", actually page size) and clarify intended usage - Generalize wiz-set-issue-due-date format hint (YYYY-MM-DD) - Broaden platform list intro (was AWS/Azure/GCP only) Wiz.yml: - Generalize wiz-resolve-issue description (was "Threat Detection Issue", applies to any Wiz Issue) - Replace terse "Agentless cloud security." with bidirectional-mirroring summary aligned with pack_metadata description WizDefend README: - Document 1400-char note truncation on resolve_threat resolution_note and set-threat-comment note - Document the auto-generated detection description fallback format (`<SEVERITY> severity detection triggered by rule '<rule>' (ID: <id>)`) - Fix First fetch maximum (was "5 days", YML says 2 days) ReleaseNotes/2_0_2.md: - Reconcile breaking change wording with 2_0_2.json — explicitly list the separate removals for wiz-reject-issue (DETECTION_EXPIRED, CONTROL_DISABLED, CONTROL_DELETED, OBJECT_DELETED, ISSUE_FIXED) vs wiz-resolve-issue (DETECTION_EXPIRED, CONTROL_DISABLED, CONTROL_DELETED). The previous wording lumped both commands together and disagreed with the JSON breakingChangesNotes field. OBJECT_DELETED stays in wiz-resolve-issue reasons (matches existing YML + JSON spec); only removed from wiz-reject-issue. * Fix mirror 5-min timeout + address v2.0.2 review findings Mirror timeout: get_modified_remote_data was Docker-killed at 5min on any backlog because _fetch_all_issue_nodes walked every page with the heavy PULL_ISSUES_QUERY. Now uses a slim MODIFIED_ISSUE_IDS_QUERY (id + statusChangedAt only), runs single-page-per-call, and persists a mirror_cursor in integration context so backlogs drain across cycles instead of dying in one giant call. _fetch_all_issue_nodes also gained a 240s deadline so wiz-get-issues / fetch_incidents return partial results instead of being killed. Review LOWs addressed: - _build_new_note_entries used lex string comparison on ISO timestamps; Wiz returns microsecond precision while XSOAR's lastUpdate is second-precision, so '.' (0x2E) < 'Z' (0x5A) silently dropped notes added in the sub-second window. Now parses both with datetime.fromisoformat before comparing. - _handle_outgoing_entries now re-checks comment_tag in entry.tags as defense-in-depth against tag-config drift. - Extracted _safe_rule_name helper in WizDefend; two prior commits had to harden successive null positions in the ruleMatch.rule.name chain. - Documented intentional first-sync empty-entries behavior in docstring and README Mirroring section. Tests: 226 Wiz + 445 WizDefend passing. demisto-sdk validate clean, xsoar-lint 9.99/10 unchanged on both files. * Fix mirror cursor lex compare for mixed-precision ISO timestamps XSOAR's lastUpdate is second-precision (`:00Z`) while saved_cursor is microsecond-precision from Wiz (`:00.500000Z`). Lex `max` would pick the bare-Z value because `Z` (0x5A) > `.` (0x2E), rewinding the cursor by up to 999ms and re-fetching the same half-second window each cycle. Switched both compare sites in get_modified_remote_data_command to use the existing _parse_iso_timestamp helper. Added regression test test_get_modified_remote_data_mixed_precision_cursor_wins. * Bump pack version to 2.0.3 (avoid in-place 2.0.2 marketplace overwrite) demisto/content master already shipped Wiz pack v2.0.2 via demisto#43569 ("chore: delete old supported modules - part 4/4") with placeholder release notes ("Documentation and metadata improvements"). To avoid republishing 2.0.2 with different content on the marketplace, bump this release to 2.0.3. - Rename ReleaseNotes/2_0_2.{md,json} -> 2_0_3.{md,json} - Bump pack_metadata.json currentVersion: 2.0.2 -> 2.0.3 * Clarify wiz-resolve-issue scope and improve error handling The v2.0.2/v2.0.3 generalisation of the YAML help text to "Resolve a Wiz Issue." over-promised: the command is only valid for Threat Detection issues — other types (Toxic Combination, Cloud Configuration, Attack Surface) are auto-resolved when the underlying problem is fixed and should be closed via wiz-reject-issue. - Wiz.yml: rewrite the wiz-resolve-issue description to make the scope explicit and direct users to wiz-reject-issue for other types. - Wiz.py: fix the resolve_issue docstring (was "Reject"); guard the _get_issue lookup so a missing issue returns "Issue not found: <id>" instead of crashing with IndexError; extend the gate error message with the actionable wiz-reject-issue redirect. - Wiz_test.py: add test_resolve_issue_non_threat_returns_friendly_error and test_resolve_issue_unknown_id_returns_not_found, both asserting the integration short-circuits before the update mutation. - ReleaseNotes/2_0_3.md: describe the clarified scope and the improved error handling. * Fix outgoing mirror losing analyst's chosen close reason The round-3 outgoing mapper added `resolutionReason <- resolutionReason` but no XSOAR incident field by that name exists on the Wiz Issue type. On close, the delta arrived without resolutionReason, code fell back to WONT_FIX, and Wiz silently dropped that on THREAT_DETECTION issues — so every closed XSOAR incident lost the analyst's chosen close reason. Discovered via live mirror cycle on incident 1360466 → Wiz dc8dbd62-...: Wiz received status=RESOLVED but resolutionReason=None. Fix: add `_resolve_wiz_reason(delta, data)` helper that prefers an explicit delta.resolutionReason (forward-compat for if/when an XSOAR custom field gets added) and falls back to translating XSOAR's built-in closeReason via XSOAR_CLOSE_REASON_TO_WIZ. Threading data through _handle_field_changes and _mirror_status_to_wiz so the status-flip paths benefit from the same fallback. Tests (Wiz_test.py: 226 → 236): - _resolve_wiz_reason precedence + translation + unknown-value handling - update_remote_system_command close path uses the fallback - update_remote_system_command explicit resolutionReason still wins - _mirror_status_to_wiz resolved-status branch uses the fallback May warrant a v2.0.4 bump or a 2_0_3.md RN entry depending on whether 2.0.3 has shipped to marketplace yet. * Add schema-consistency tests for mirror field declarations Guard against the v2.0.4 phantom-source bug class: declaring a mirror source field name (in WIZ_MIRRORED_FIELDS or in the outgoing mapper's `simple:` source) that does not exist as either an XSOAR system field or a pack-defined IncidentField. When that happens, XSOAR delivers nothing in the delta and the field silently defaults — invisible to unit tests that hand-build delta dicts. Three new tests in Wiz_test.py: - test_outgoing_mapper_sources_resolve_to_real_fields: walks classifier-mapper-outgoing-Wiz.json and asserts every `simple:` source is a known XSOAR built-in, a pack-defined cliName, or a documented exemption. Verified to fail on the original bug if the resolutionReason exemption is removed. - test_wiz_mirrored_fields_resolve_to_real_fields: same check on the WIZ_MIRRORED_FIELDS list advertised via get_mapping_fields_command. - test_known_phantom_exemptions_are_actually_referenced: hygiene check so the exemption set doesn't decay into a junk drawer. _KNOWN_PHANTOM_SOURCES documents the three legitimate edge cases (resolutionReason backstopped by closeReason translation, notes mirrored via entries, dueAt as a mapper destination name) with the specific runtime guard for each. Wiz_test.py: 239 → 242 tests, all passing. * Fold close-reason fix into 2.0.3 release notes; drop v2.0.4 markers The close-reason carry-through fix and schema-consistency tests are shipping as part of v2.0.3, not a separate v2.0.4 — the pack version hasn't been bumped and 2.0.3 has not yet been published to marketplace. - Add a 2_0_3.md bullet describing the user-facing close-reason fix (XSOAR closeReason → Wiz resolutionReason translation, prevents silent default to WONT_FIX on incident close). - Drop "v2.0.4" markers from test section headers and docstrings; rephrase as plain REGRESSION/topic markers since these tests are part of the 2.0.3 release. * Add closeReason to outgoing mapper so the runtime translation receives it Phase 6.12b live testing exposed that the previous-commit close-reason fix was incomplete. The runtime helper `_resolve_wiz_reason` reads `data.get('closeReason')` but XSOAR's outgoing mirror engine only delivers fields the OUTGOING MAPPER declares — and `closeReason` was never declared. Diagnostic log proved it: `data.keys=['status']`, `data.closeReason=None`, so `_resolve_wiz_reason` always returned None and the close fell back to `WONT_FIX`. Adding `closeReason -> closeReason` to classifier-mapper-outgoing-Wiz.json tells the mirror engine to include `closeReason` in the args sent to `update-remote-system`. After the change, the diag log shows: data.keys=['closeReason', 'status'] data.closeReason='Resolved' _handle_incident_closed: ... reason=ISSUE_FIXED GraphQL mutation sent to Wiz now carries the correct enum: patch={status: RESOLVED, resolutionReason: ISSUE_FIXED} Verified live with closeReason='Resolved' (-> ISSUE_FIXED) and closeReason='False Positive' (-> FALSE_POSITIVE). Wiz canary issues returned NOT_FOUND on apply (Failures Entry 15 — canary-only SA scope + purge), but the integration's outbound payload is correct. * Update Service Account scope list in integration setup docs Updated the Service Account scope list in the integration setup instructions to match the scopes required by the integration's commands. Added a release-notes bullet under 2.0.3. No code change. * Run demisto-sdk format + add classifier release notes (review) Addresses Benimanela's review comments on PR demisto#43959: - demisto-sdk format applied to all PR-scope files. Pure key-reordering in classifier-Wiz_Mapper.json (severity / Wiz Issue Resolution Recommendation moved before dbotMirror* entries) and Wiz.yml (defaultmapperout, ismappable, isremotesyncin/out moved to canonical positions). Semantically identical. - ReleaseNotes/2_0_3.md: added explicit "Wiz - Outgoing Mapper" and "Wiz Mapper" entries surfacing the user-facing classifier changes (new outgoing mapper for status/dueAt/closeReason/resolutionReason; incoming dbotMirror* mappings for mirror correlation). * Address Copilot review: parsed_args.last_update + list-typed empty results Two small mechanical hardenings flagged by the Copilot review on PR demisto#43959: - get_remote_data_command: read last_update from parsed_args.last_update (the GetRemoteDataArgs-parsed value) instead of the raw args dict, so XSOAR-version casing/normalization differences can't drift the cursor. - query_api: return [] instead of {} on no-results so callers can iterate without a per-call type guard. get_filtered_detections gains a defensive isinstance(list) check so a future non-list query result short-circuits cleanly instead of silently iterating dict keys. - Updates the existing test_query_api_empty_response assertion to match. 239 Wiz + 488 WizDefend = 727 unit tests pass. demisto-sdk validate clean. * Fix pre-commit errors * Update .pack-ignore * Update classifier-mapper-outgoing-Wiz.json * Cleanup demisto.args usages in Wiz.py --------- Co-authored-by: Ariel Tobiana <107474518+ariel-wiz@users.noreply.github.com> Co-authored-by: Kamal Qarain <kqarain@paloaltonetworks.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Status
Related Issues
Description
Add
rf-alert-lookupcommandMust have