Skip to content

QA Fixes for GitSync in TIPCommon#667

Open
jayapradha-p wants to merge 22 commits intomainfrom
GitSync_QA_fixes_TC_changes
Open

QA Fixes for GitSync in TIPCommon#667
jayapradha-p wants to merge 22 commits intomainfrom
GitSync_QA_fixes_TC_changes

Conversation

@jayapradha-p
Copy link
Copy Markdown
Contributor

@jayapradha-p jayapradha-p commented Apr 7, 2026

QA Fixes for GitSync in TIPCommon

Examples:

  • Fix: Resolve issue with API endpoint returning 500 error
  • [Buganizer ID: 987654321] Feature: Add support for custom data types
  • Docs: Update README with installation instructions

Description

QA Fixes for GitSync in TIPCommon

What problem does this PR solve?
(e.g., "Fixes a bug where X was happening," "Implements feature Y to allow Z," "Improves performance of function A.")

How does this PR solve the problem?
(e.g., "Modified algorithm in src/foo.js," "Added new component Bar.vue," "Updated dependency baz to version 1.2.3.")

Any other relevant information (e.g., design choices, tradeoffs, known issues):
(e.g., "Chose approach A over B due to performance considerations," "This change might affect X in certain edge cases," "Requires manual migration steps for existing users.")


Checklist:

Please ensure you have completed the following items before submitting your PR.
This helps us review your contribution faster and more efficiently.

General Checks:

  • I have read and followed the project's contributing.md guide.
  • My code follows the project's coding style guidelines.
  • I have performed a self-review of my own code.
  • My changes do not introduce any new warnings.
  • My changes pass all existing tests.
  • I have added new tests where appropriate to cover my changes. (If applicable)
  • I have updated the documentation where necessary (e.g., README, API docs). (If applicable)

Open-Source Specific Checks:

  • My changes do not introduce any Personally Identifiable Information (PII) or sensitive customer data.
  • My changes do not expose any internal-only code examples, configurations, or URLs.
  • All code examples, comments, and messages are generic and suitable for a public repository.
  • I understand that any internal context or sensitive details related to this work are handled separately in internal systems (Buganizer for Google team members).

For Google Team Members and Reviewers Only:

  • I have included the Buganizer ID in the PR title or description (e.g., "Internal Buganizer ID: 123456789" or "Related Buganizer: go/buganizer/123456789").
  • I have ensured that all internal discussions and PII related to this work remain in Buganizer.
  • I have tagged the PR with one or more labels that reflect the pull request purpose.

Screenshots (If Applicable)

If your changes involve UI or visual elements, please include screenshots or GIFs here.
Ensure any sensitive data is redacted or generalized.


Further Comments / Questions

Any additional comments, questions, or areas where you'd like specific feedback.


Note

Medium Risk
Adds a large set of new Chronicle SOAR API wrappers and corresponding data models, plus request URL rewriting for 1P download endpoints; breadth of new endpoints and response-shape normalization increases integration/compat risk despite mostly additive changes.

Overview
Bumps TIPCommon version to 2.3.6 and significantly expands the SOAR REST surface with many new helper functions in rest/soar_api.py for managing templates, environments, integrations/packages, domains/networks/custom lists, blocklists/SLA, playbooks, IDE items, mapping rules, and simulated cases.

Adds multiple new/updated data models in data_models.py (e.g., Environment, IntegrationSetting, VisualFamily, OntologyRecord, CaseTag, Domain, Network, SlaDefinition, SimulatedCases) and makes existing parsers more defensive (e.g., InstalledIntegrationInstance, DynamicParameter).

Extends both legacy and 1P SOAR platform clients with the corresponding endpoints, includes several QA fix parameter/endpoint adjustments, and updates BaseSoarApi._make_request to rewrite certain /v1alpha/.../download/integrations/... URLs to the expected download path.

Reviewed by Cursor Bugbot for commit 8fc5a6e. Bugbot is set up for automated code reviews on this repo. Configure here.

@jayapradha-p jayapradha-p requested a review from a team as a code owner April 7, 2026 13:42
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces comprehensive updates to the TIPCommon package to improve its GitSync capabilities and overall platform interaction. The changes include the addition of several new data models to represent various platform entities, a significant expansion of the API client functionality to support a wider range of SOAR operations, and various robustness improvements such as better error handling and URL normalization. These updates ensure that the CLI tool is better equipped to handle complex synchronization tasks and platform configurations.

Highlights

  • Version Update: Updated the TIPCommon package version from 2.3.3 to 2.3.6.
  • Data Model Enhancements: Expanded data_models.py to include new classes like Environment, IntegrationSetting, VisualFamily, OntologyRecord, CaseTag, Domain, CaseStage, CaseCloseReasons, CustomList, Blacklist, Network, SlaDefinition, SoarBlockEntity, and SimulatedCases to better support GitSync operations.
  • API Client Expansion: Significantly extended soar_api.py and the corresponding API client factory to include numerous new methods for interacting with the SOAR platform, covering email templates, environment management, integration settings, and more.
  • Bug Fixes and Robustness: Added error handling for JSON decoding, improved URL handling for specific download endpoints, and implemented QA-driven fixes for dynamic environment parameters and connector updates.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the TIPCommon package to version 2.3.6, significantly expanding the data models and REST API wrappers to support both legacy and One Platform (1P) SOAR environments. Key changes include the addition of numerous dataclasses for data normalization and a wide array of new API methods for managing integrations, cases, and system settings. Feedback identifies several typos in function names, a logic error in the bulk tag addition method, and opportunities to improve robustness by catching specific exceptions and using safe dictionary access. Additionally, suggestions were provided to enhance type safety and adhere to library logging best practices.

Comment on lines +787 to +800
"""Add tags to case in bulk"""
endpoint = "/cases:executeBulkAddTag"
payload = {
"propertiesStatus": {
"additionalProp1": 0,
"additionalProp2": 0,
"additionalProp3": 0,
},
"displayName": self.params.name,
"parameterType": self.params.type,
"defaultValue": self.params.default_value,
"optionalValuesJson": str(self.params.optional_json),
}
return self._make_request(HttpMethod.PATCH, endpoint, json_payload=payload)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This function appears to have a copy-paste error.

  1. The function name add_tags_to_case_in_bulks has a typo and should likely be add_tags_to_case_in_bulk.
  2. The payload being constructed uses parameters (self.params.name, self.params.type, etc.) that seem to belong to adding a dynamic environment parameter, not adding tags to cases. This will cause the API call to fail or have unintended consequences.

Please correct the payload to match the requirements for the /cases:executeBulkAddTag endpoint.

environments: list[str]

@classmethod
def from_legacy_or_1p(cls, data: SingleJson) -> "Entity":
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The return type hint for this class method is "Entity", but the method is part of the BlockRecord class and returns an instance of it. This is misleading and can cause issues with static analysis tools. The return type should be "BlockRecord".

Suggested change
def from_legacy_or_1p(cls, data: SingleJson) -> "Entity":
def from_legacy_or_1p(cls, data: SingleJson) -> "BlockRecord":

Comment on lines +2570 to +2571
except Exception:
envs = []
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a broad except Exception: can hide bugs. It's better to catch specific exceptions you anticipate, such as json.JSONDecodeError or TypeError when parsing JSON.

Suggested change
except Exception:
envs = []
except (json.JSONDecodeError, TypeError):
envs = []

return response.json()


def attache_workflow_to_case(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a typo in the function name. It should be attach_workflow_to_case instead of attache_workflow_to_case.

Suggested change
def attache_workflow_to_case(
def attach_workflow_to_case(

Comment on lines +2067 to +2068
except Exception:
scopes = []
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The use of a broad except Exception: clause can mask unexpected errors and make debugging more difficult. It's better to catch more specific exceptions that you expect to handle.

Suggested change
except Exception:
scopes = []
except (json.JSONDecodeError, TypeError):
scopes = []

endpoint = (
"/system/settings/environments"
)
return self._make_request(HttpMethod.GET, endpoint).json()["environments"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Directly accessing a key with ...json()["environments"] is unsafe and will raise a KeyError if the key is not present in the response. It's safer to use the .get() method with a default value.

Suggested change
return self._make_request(HttpMethod.GET, endpoint).json()["environments"]
return self._make_request(HttpMethod.GET, endpoint).json().get("environments", [])

Comment on lines +923 to +924
except Exception:
return []
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a broad except Exception: can hide bugs. It's better to catch specific exceptions you anticipate, such as json.JSONDecodeError if the response body is not valid JSON.

Suggested change
except Exception:
return []
except json.JSONDecodeError:
return []

data["params"] = data["parameters"]
detailed_data_list.append(data)
else:
print(f"Failed to fetch details for {name}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using print() for logging in a library is not recommended as it writes directly to stdout and can't be controlled by the application's logging configuration. Please use the provided logger instance instead.

Suggested change
print(f"Failed to fetch details for {name}")
self.chronicle_soar.LOGGER.warning(f"Failed to fetch details for {name}")

payload = self.params.logo_data
return self._make_request(HttpMethod.PATCH, endpoint, json_payload=payload)

def attache_workflow_to_case(self) -> requests.Response:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's a typo in the function name. It should be attach_workflow_to_case instead of attache_workflow_to_case.

Suggested change
def attache_workflow_to_case(self) -> requests.Response:
def attach_workflow_to_case(self) -> requests.Response:

def get_installed_integrations(self) -> requests.Response:
"""Get installed integrations."""
endpoint: str = "/integrations"
return self._make_request(HttpMethod.GET, endpoint).json()["integrations"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Directly accessing a key with ...json()["integrations"] is unsafe and will raise a KeyError if the key is not present in the response. It's safer to use the .get() method with a default value.

Suggested change
return self._make_request(HttpMethod.GET, endpoint).json()["integrations"]
return self._make_request(HttpMethod.GET, endpoint).json().get("integrations", [])

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8fc5a6e. Configure here.

response = api_client.update_blocklist()
try:
response = validate_response(response, validate_json=False)
return response
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_response returns None, overwriting response object

High Severity

In update_blocklist, the result of validate_response() is assigned back to response, but validate_response returns None. This means response is overwritten with None and then returned, so update_blocklist always returns None on success instead of the actual response data.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8fc5a6e. Configure here.

) -> SingleJson:
"""Add or update company logo."""
api_client = get_soar_client(chronicle_soar)
api_client.params.company_logo = company_logo
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attribute name mismatch: company_logo vs logo_data

High Severity

add_or_update_company_logo sets api_client.params.company_logo, but both LegacySoarApi and OnePlatformSoarApi implementations read self.params.logo_data. This mismatch means the payload will be None (or trigger an AttributeError depending on the Container implementation), so the logo data is never actually sent to the API.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8fc5a6e. Configure here.

def get_all_model_block_records(self) -> requests.Response:
"""Get all model block records."""
endpoint: str = "settings/GetAllModelBlockRecords"
return self.get_page_results(endpoint)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing leading slash in legacy API endpoints

High Severity

The endpoints "settings/GetAllModelBlockRecords" and "settings/GetCompanyLogo" are missing a leading /. Since _make_request constructs URLs via string concatenation (f"{base_uri}{endpoint}"), these will produce malformed URLs like https://host/external/v1settings/... instead of https://host/external/v1/settings/..., causing all requests to these endpoints to fail.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8fc5a6e. Configure here.

except (ValueError, InternalJSONDecoderError):
return []

return []
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_sla_records dead code after .json() call

Low Severity

In get_sla_records, response is already the parsed JSON result (from .json() at line 2429), so the hasattr(response, "json") check at line 2441 is dead code — a parsed dict/list will never have a .json() method. More importantly, if .json() raises a JSONDecodeError, the outer try/except catches ValueError but not JSONDecodeError directly from the requests library, which may not be an InternalJSONDecoderError.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8fc5a6e. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants