-
Notifications
You must be signed in to change notification settings - Fork 1
feat(sites): implement Site Management API module #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Implements comprehensive site management operations including: - Full CRUD operations (list, get, create, update, delete) - Smart filtering by name patterns (starts_with, ends_with, contains) - Filter by site IDs - Filter empty sites (no assets) - Mass delete operations with dry-run mode and validation - Site asset and scan engine/template operations - Integration with InsightVMClient as client.sites Relates to #49
Added detailed documentation for Site Management module including: - Quick start and basic operations - Smart filtering examples - Mass operations with safety features - Common use cases and best practices - Error handling patterns Relates to #49
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a comprehensive Site Management API module for InsightVM v2.0, adding full CRUD operations and advanced site management capabilities with safety features.
- Implements a new SiteAPI class with comprehensive site management operations including filtering, mass operations, and asset management
- Adds smart filtering capabilities for sites by name patterns, IDs, and empty sites detection
- Integrates the SiteAPI module into the main InsightVMClient for seamless access
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/rapid7/client.py | Integrates SiteAPI module into InsightVMClient with import and initialization |
| src/rapid7/api/sites.py | New comprehensive SiteAPI class with CRUD operations, smart filtering, mass operations, and safety features |
| docs/SITE_MANAGEMENT.md | Complete usage guide and documentation for the Site Management module with examples and best practices |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
|
||
| for site in all_sites: | ||
| name = site.get('name', '') | ||
|
|
||
| if not case_sensitive: | ||
| name_lower = name.lower() | ||
| starts_lower = starts_with.lower() if starts_with else None | ||
| ends_lower = ends_with.lower() if ends_with else None | ||
| contains_lower = contains.lower() if contains else None | ||
| else: | ||
| name_lower = name | ||
| starts_lower = starts_with | ||
| ends_lower = ends_with | ||
| contains_lower = contains | ||
|
|
||
| # Check all conditions | ||
| matches = True | ||
|
|
||
| if starts_with and not name_lower.startswith(starts_lower): | ||
| matches = False | ||
| if ends_with and not name_lower.endswith(ends_lower): | ||
| matches = False | ||
| if contains and contains_lower not in name_lower: | ||
| matches = False | ||
|
|
||
| if matches: | ||
| filtered.append(site) | ||
|
|
Copilot
AI
Oct 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic for case-insensitive conversion is duplicated. Consider extracting it into a helper function or using a more concise approach.
| for site in all_sites: | |
| name = site.get('name', '') | |
| if not case_sensitive: | |
| name_lower = name.lower() | |
| starts_lower = starts_with.lower() if starts_with else None | |
| ends_lower = ends_with.lower() if ends_with else None | |
| contains_lower = contains.lower() if contains else None | |
| else: | |
| name_lower = name | |
| starts_lower = starts_with | |
| ends_lower = ends_with | |
| contains_lower = contains | |
| # Check all conditions | |
| matches = True | |
| if starts_with and not name_lower.startswith(starts_lower): | |
| matches = False | |
| if ends_with and not name_lower.endswith(ends_lower): | |
| matches = False | |
| if contains and contains_lower not in name_lower: | |
| matches = False | |
| if matches: | |
| filtered.append(site) | |
| def _case(val): | |
| return val if case_sensitive or val is None else val.lower() | |
| for site in all_sites: | |
| name = site.get('name', '') | |
| name_cmp = _case(name) | |
| starts_cmp = _case(starts_with) | |
| ends_cmp = _case(ends_with) | |
| contains_cmp = _case(contains) | |
| # Check all conditions | |
| matches = True | |
| if starts_with and not name_cmp.startswith(starts_cmp): | |
| matches = False | |
| if ends_with and not name_cmp.endswith(ends_cmp): | |
| matches = False | |
| if contains and (contains_cmp not in name_cmp): | |
| matches = False | |
| if matches: | |
| filtered.append(site) |
src/rapid7/api/sites.py
Outdated
| # Check all conditions | ||
| matches = True | ||
|
|
||
| if starts_with and not name_lower.startswith(starts_lower): | ||
| matches = False | ||
| if ends_with and not name_lower.endswith(ends_lower): | ||
| matches = False | ||
| if contains and contains_lower not in name_lower: | ||
| matches = False | ||
|
|
||
| if matches: |
Copilot
AI
Oct 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The multiple if statements can be simplified using early return or a single boolean expression to improve readability.
| # Check all conditions | |
| matches = True | |
| if starts_with and not name_lower.startswith(starts_lower): | |
| matches = False | |
| if ends_with and not name_lower.endswith(ends_lower): | |
| matches = False | |
| if contains and contains_lower not in name_lower: | |
| matches = False | |
| if matches: | |
| # Check all conditions in a single boolean expression | |
| if ( | |
| (not starts_with or name_lower.startswith(starts_lower)) and | |
| (not ends_with or name_lower.endswith(ends_lower)) and | |
| (not contains or contains_lower in name_lower) | |
| ): |
| filtered_sites = [ | ||
| s for s in filtered_sites | ||
| if name_pattern.lower() in s.get('name', '').lower() | ||
| ] |
Copilot
AI
Oct 7, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This filtering logic is inconsistent with the more comprehensive pattern matching in filter_by_name_pattern(). Consider using the same method for consistency.
| filtered_sites = [ | |
| s for s in filtered_sites | |
| if name_pattern.lower() in s.get('name', '').lower() | |
| ] | |
| # Use the same comprehensive pattern matching as filter_by_name_pattern | |
| name_pattern_sites = self.filter_by_name_pattern(name_pattern=name_pattern) | |
| name_pattern_site_ids = {s['id'] for s in name_pattern_sites} | |
| filtered_sites = [s for s in filtered_sites if s['id'] in name_pattern_site_ids] |
- Extract case conversion logic into helper function - Simplify boolean logic with compound expressions - Use filter_by_name_pattern for consistency in filter_sites Relates to #49
Description
Implements comprehensive Site Management module for InsightVM v2.0 API.
Changes
New Files
src/rapid7/api/sites.py (600+ lines)
docs/SITE_MANAGEMENT.md
Modified Files
Key Features
✅ CRUD Operations
list(),get_all(),get_site()- Retrieve sitescreate(),update(),delete_site()- Modify sites✅ Smart Filtering
filter_by_name_pattern()- Filter by starts_with/ends_with/containsfilter_by_ids()- Filter by list of site IDsfilter_empty_sites()- Find sites with no assets✅ Mass Operations
mass_delete()- Bulk delete with dry-run mode (safe by default)delete_by_pattern()- Delete sites matching name pattern✅ Asset & Scan Operations
get_assets(),get_asset_count()- Asset managementget_scan_template(),get_scan_engine()- Scan configuration✅ Safety Features
Architecture
Testing Performed
Breaking Changes
None - This is a new module addition.
Related Issues
Fixes #49
Checklist
Next Steps
After this PR is merged: