Skip to content

Conversation

@haggit-eliyahu
Copy link
Contributor

@haggit-eliyahu haggit-eliyahu commented Dec 29, 2025


Description

Migrate spy cloud integration to third-party repo and add missing EnvCommon version to packages.


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.

@haggit-eliyahu haggit-eliyahu requested review from a team as code owners December 29, 2025 11:39
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @haggit-eliyahu, 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 undertakes a significant refactoring of the SpyCloud integration by migrating its entire codebase to a new third-party repository. This strategic move aims to streamline maintenance and enhance modularity. Concurrently, the integration has been updated to ensure full compatibility with Python 3.11, aligning with modern development standards. The changes also introduce three new core functionalities: the ability to list available SpyCloud catalogs, retrieve entity-specific breach information, and perform a connectivity test, all supported by robust new data models and interactive UI widgets.

Highlights

  • Integration Relocation: The SpyCloud integration has been moved to a dedicated third-party repository, enhancing modularity and organization.
  • Python 3.11 Compatibility: The integration now officially supports Python 3.11, with the .python-version file updated to reflect this change.
  • New Actions Introduced: Three new actions have been added: List Catalogs for retrieving available catalogs, List Entity Breaches for finding breach information related to specific entities, and Ping for testing API connectivity.
  • Enhanced Data Models and Utilities: New data models for Catalog and Breach entities, along with utility functions for response validation, timestamp handling, and email validation, have been implemented to support the new functionalities.
  • Interactive Widgets: New HTML widgets have been introduced for List Catalogs and List Entity Breaches to provide interactive and searchable displays of results within the UI.

🧠 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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
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 migrates the SpyCloud integration. While it's a good starting point, there are several critical issues and style guide violations that need to be addressed. Most importantly, the pull request is missing unit tests, which are mandatory for new integrations in content/response_integrations/** according to the repository style guide. I've also identified a critical configuration bug that would prevent the integration from working, a security issue in password handling, and numerous violations of the style guide regarding type hinting, docstrings, and the use of synchronous libraries. Please review the detailed comments for suggestions on how to bring this integration up to the repository's standards for production-readiness.

name: SpyCloud
parameters:
- name: API Root
default_value: https:/{{api root}}
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

There appears to be a typo in the default_value for the API Root. It is missing a slash in https:/. This will cause connection errors for users configuring the integration.

    default_value: https://{{api root}}

Comment on lines +68 to +74
def to_json(self):
obfuscated_password = (
self.obfuscate_password(self.password) if self.password else self.password
)
self.raw_data["password"] = obfuscated_password
self.raw_data["password_plaintext"] = obfuscated_password
return self.raw_data
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This method writes the obfuscated password to both password and password_plaintext. Exposing a field named password_plaintext is misleading and a potential security risk, even if it contains obfuscated data. According to the style guide (line 23-24, 60-61), secrets should not persist in telemetry. It's best to remove the password_plaintext key entirely.

Suggested change
def to_json(self):
obfuscated_password = (
self.obfuscate_password(self.password) if self.password else self.password
)
self.raw_data["password"] = obfuscated_password
self.raw_data["password_plaintext"] = obfuscated_password
return self.raw_data
def to_json(self):
if self.password:
self.raw_data["password"] = self.obfuscate_password(self.password)
# The 'password_plaintext' key should not be exposed in JSON results.
self.raw_data.pop("password_plaintext", None)
return self.raw_data

Comment on lines +80 to +84
def obfuscate_password(self, password):
obfuscated = ""
for index in range(1, len(password) - 2):
obfuscated += password[index].replace(password[index], "*")
return password[0] + obfuscated + password[-2:]
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This password obfuscation logic is buggy for passwords with a length of 3 or less, and the implementation is inefficient. For example, a 2-character password ab would become aab. This version is more robust, handles edge cases correctly, and is more Pythonic. It also includes the required type hints.

Suggested change
def obfuscate_password(self, password):
obfuscated = ""
for index in range(1, len(password) - 2):
obfuscated += password[index].replace(password[index], "*")
return password[0] + obfuscated + password[-2:]
def obfuscate_password(self, password: str) -> str:
"""Obfuscates a password for safe display, handling edge cases."""
if not password:
return ""
length = len(password)
if length <= 2:
return password[0] + "*" * (length - 1)
if length == 3:
return f"{password[0]}*{password[-1]}"
# For passwords with 4 or more characters, keep the first and last two.
return f"{password[0]}{'*' * (length - 3)}{password[-2:]}"

)
params = {"source_id": catalog_id} if catalog_id else {}

results = self.session.get(url, params=params)
Copy link
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 the synchronous requests library for network calls can lead to performance bottlenecks. The repository style guide (lines 69-72) recommends using an asynchronous library like httpx or aiohttp to avoid blocking operations. Consider refactoring this manager to use async and await for all network requests to improve performance.

Comment on lines +13 to +18
def is_valid_email(user_name):
"""
Check if the user_name is valid email.
:param user_name: {str} User name
:return: {bool} True if valid email, else False
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function, and others in the file, are missing type hints and use a docstring format that doesn't align with the repository style guide (lines 80, 88). Please update all functions in this file to include type annotations and Google-style docstrings.

For example:

def is_valid_email(user_name: str) -> bool:
    """Checks if a string is a valid email address.

    Args:
        user_name: The string to validate.

    Returns:
        True if the string is a valid email, False otherwise.
    """


class Catalog(BaseModel):
def __init__(self, raw_data, title, type, num_records, site, id):
super(Catalog, self).__init__(raw_data)
Copy link
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 super(ClassName, self) is an older style. Modern Python 3 allows for a cleaner, argument-less super() call, which is less prone to errors.

Suggested change
super(Catalog, self).__init__(raw_data)
super().__init__(raw_data)


class Breach(BaseModel):
def __init__(self, raw_data, target_url, email, infected_time, sighting, severity, password):
super(Breach, self).__init__(raw_data)
Copy link
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 super(ClassName, self) is an older style. Modern Python 3 allows for a cleaner, argument-less super() call, which is less prone to errors.

Suggested change
super(Breach, self).__init__(raw_data)
super().__init__(raw_data)



@output_handler
def main():
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The main function is missing type hints and a docstring, which violates the repository style guide (lines 80, 88-90). All functions should have type annotations and a Google-style docstring.

Suggested change
def main():
def main() -> None:
"""Return information about breaches related to entities."""

description: 'Specify how many catalogs to return. Default: 50.'
is_mandatory: false
dynamic_results_metadata:
- result_example_path: resources/list_catalogs_JsonResult_example.json
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The result_example_path does not follow the naming convention specified in the repository style guide (line 158). For an action file named ListCatalogs.py, the example file should be named ListCatalogs_json_example.json.

Please update this path and rename the corresponding file in the resources/ directory.

-   result_example_path: resources/ListCatalogs_json_example.json


try:
if limit < 0:
raise Exception('"Max Catalogs To Return" should be a positive number.')
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Raising a generic Exception is not recommended. For invalid parameter values, it's better to use a more specific exception like ValueError to provide clearer error information.

Suggested change
raise Exception('"Max Catalogs To Return" should be a positive number.')
raise ValueError('"Max Catalogs To Return" should be a positive number.')

@github-actions
Copy link

github-actions bot commented Jan 4, 2026

Marketplace Validation Failed

Click to view the full report

Validation Report

🧩 Integrations
Pre-Build Stage

spycloud

Validation Name Details
⚠️ Uv Lock Error happened while executing a command: uv lock --check: Using CPython 3.11.14 interpreter at: /opt/hostedtoolcache/Python/3.11.14/x64/bin/python error: Failed to generate package metadata for environmentcommon==1.0.0 @ path+../../../../packages/envcommon/EnvironmentCommon-1.0.0/EnvironmentCommon-1.0.0-py3-none-any.whl Caused by: Failed to read from the distribution cache Caused by: failed to query metadata of file /home/runner/work/content-hub/content-hub/content/packages/envcommon/EnvironmentCommon-1.0.0/EnvironmentCommon-1.0.0-py3-none-any.whl: No such file or directory (os error 2)
⚠️ Integration Version Bump New integration project.toml and release_note.yaml version must be initialize to 1.0

@TalShafir1 TalShafir1 merged commit 8a01fe0 into main Jan 4, 2026
17 of 27 checks passed
@TalShafir1 TalShafir1 deleted the move-spycloud-to-third-party branch January 4, 2026 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants