Skip to content

feat: Add community plugin installer with git repository support#183

Open
finxo wants to merge 10 commits intomasterfrom
feat/plugin_from_repo
Open

feat: Add community plugin installer with git repository support#183
finxo wants to merge 10 commits intomasterfrom
feat/plugin_from_repo

Conversation

@finxo
Copy link
Collaborator

@finxo finxo commented Mar 13, 2026

Pull Request

📝 Summary

Adds a complete community plugin installation system that allows users to install Titan plugins from any git repository (GitHub, GitLab, Bitbucket) using pipx inject for isolation. Includes a 4-step installation wizard with preview functionality, version tracking, update notifications, and plugin-based workflow filtering capabilities.

🔧 Changes Made

  • Community Plugin Installer (titan_cli/core/plugins/community.py): Core business logic for URL validation, git host detection, pyproject.toml preview fetching, pipx install/uninstall, and tracking file management in ~/.titan/community_plugins.toml
  • 4-Step Install Wizard (titan_cli/ui/tui/screens/install_plugin_screen.py): Interactive wizard for URL input, metadata preview with security warnings, installation progress, and success/failure handling
  • Plugin Management UI Updates (titan_cli/ui/tui/screens/plugin_management.py): Added install button (i), uninstall button (u) for community plugins, and [community] badge to distinguish plugin sources
  • Shared Wizard Widgets (titan_cli/ui/tui/widgets/wizard.py): Reusable StepStatus, WizardStep, and StepIndicator components for multi-step workflows
  • Update Notification System (titan_cli/core/plugins/updates.py, titan_cli/ui/tui/screens/plugin_management.py): Checks for newer versions of community plugins and displays update badges with available versions
  • Plugin-Based Workflow Filtering (titan_cli/core/plugins/registry.py, titan_cli/core/workflow/workflow_manager.py): Workflows can now be filtered by active plugins through configuration, with support for nested plugin workflow directories
  • GitHub Token Authentication (titan_cli/core/plugins/community.py): Supports GITHUB_TOKEN environment variable for fetching from private repositories
  • Poetry Environment Detection (titan_cli/core/plugins/community.py): Automatically detects Poetry virtual environments and uses appropriate pip for plugin installation
  • Version Tracking (titan_cli/core/plugins/registry.py): Extracts and displays plugin versions from distribution metadata

🧪 Testing

  • Unit tests added/updated (poetry run pytest)
  • All tests passing (make test)
  • Manual testing with titan-dev

Unit tests cover:

  • URL validation (valid/invalid formats, version requirements)
  • Git host detection (GitHub, GitLab, Bitbucket, unknown)
  • Raw URL construction for pyproject.toml fetching
  • Git URL building with version tags
  • Community plugin tracking file I/O (load, save, remove operations)
  • Plugin name extraction from records
  • Poetry/pipx environment detection
  • Nested workflow directory discovery
  • Plugin-based workflow filtering

📊 Logs

  • community_plugin_install_started (INFO) — repo_url, version, package_name
  • community_plugin_install_success (INFO) — package_name, titan_plugin_name, duration
  • community_plugin_install_failed (ERROR) — repo_url, error_type, error_message
  • community_plugin_uninstall_started (INFO) — package_name, titan_plugin_name
  • community_plugin_uninstall_success (INFO) — package_name, duration
  • community_plugin_uninstall_failed (ERROR) — package_name, error_message
  • community_plugin_preview_fetch_ok (DEBUG) — repo_url, version, host
  • community_plugin_preview_fetch_failed (DEBUG) — repo_url, version, error_type
  • community_plugin_update_check (DEBUG) — plugin_name, current_version, latest_version, update_available
  • plugin_workflow_filter_applied (DEBUG) — plugin_name, total_workflows, filtered_workflows

✅ Checklist

  • Self-review done
  • Follows the project's logging rules (no secrets, no content in logs)
  • New and existing tests pass
  • Documentation updated if needed

@finxo finxo self-assigned this Mar 13, 2026
@finxo finxo force-pushed the feat/plugin_from_repo branch from 7b92010 to c7b7ea0 Compare March 13, 2026 06:50
@wiz-b6e4a6c509
Copy link

wiz-b6e4a6c509 bot commented Mar 13, 2026

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings 3 Medium
Software Management Finding Software Management Findings -
Total 3 Medium

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

req = Request(raw_url)
if token:
req.add_header("Authorization", f"token {token}")
with urlopen(req, timeout=_FETCH_TIMEOUT) as resp:

Choose a reason for hiding this comment

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

Medium SAST Finding

Insecure URL handling in Python urllib module (CWE-939)

More Details

The Python urllib module allows applications to open URLs and retrieve data from the web. However, if the URL is not a literal value and can be controlled by an attacker, it can lead to security vulnerabilities. The urllib module supports the "file://" scheme, which means an attacker could potentially read arbitrary files on the system if they can control the URL value.

This vulnerability poses a significant risk as it can lead to unauthorized access to sensitive information, data leaks, and potentially even remote code execution, depending on the application's context and privileges. It is crucial to avoid passing user-controlled input directly to the urllib module's functions without proper validation and sanitization.

Attribute Value
Impact Medium
Likelihood Medium

Remediation

To mitigate this vulnerability, it is recommended to either:

  1. Hardcode the URLs being used in the urllib module, ensuring that they are not derived from user input or other untrusted sources.
  2. Use a more secure and modern library like the requests module, which does not support the "file://" scheme by default.

Example using the requests module to issue an HTTPS request:

import requests

# Issue a GET request to https://example.com with a timeout of 10 seconds
response = requests.get('https://example.com', timeout=10)

# Work with the response object
# ...

Rule ID: WS-I011-PYTHON-00053


To ignore this finding as an exception, reply to this conversation with #wiz_ignore reason

If you'd like to ignore this finding in all future scans, add an exception in the .wiz file (learn more) or create an Ignore Rule (learn more).


To get more details on how to remediate this issue using AI, reply to this conversation with #wiz remediate

req.add_header("Accept", "application/vnd.github+json")
if token:
req.add_header("Authorization", f"Bearer {token}")
with urlopen(req, timeout=_FETCH_TIMEOUT) as resp:

Choose a reason for hiding this comment

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

Medium SAST Finding

Insecure URL handling in Python urllib module (CWE-939)

More Details

The Python urllib module allows applications to open URLs and retrieve data from the web. However, if the URL is not a literal value and can be controlled by an attacker, it can lead to security vulnerabilities. The urllib module supports the "file://" scheme, which means an attacker could potentially read arbitrary files on the system if they can control the URL value.

This vulnerability poses a significant risk as it can lead to unauthorized access to sensitive information, data leaks, and potentially even remote code execution, depending on the application's context and privileges. It is crucial to avoid passing user-controlled input directly to the urllib module's functions without proper validation and sanitization.

Attribute Value
Impact Medium
Likelihood Medium

Remediation

To mitigate this vulnerability, it is recommended to either:

  1. Hardcode the URLs being used in the urllib module, ensuring that they are not derived from user input or other untrusted sources.
  2. Use a more secure and modern library like the requests module, which does not support the "file://" scheme by default.

Example using the requests module to issue an HTTPS request:

import requests

# Issue a GET request to https://example.com with a timeout of 10 seconds
response = requests.get('https://example.com', timeout=10)

# Work with the response object
# ...

Rule ID: WS-I011-PYTHON-00053


To ignore this finding as an exception, reply to this conversation with #wiz_ignore reason

If you'd like to ignore this finding in all future scans, add an exception in the .wiz file (learn more) or create an Ignore Rule (learn more).


To get more details on how to remediate this issue using AI, reply to this conversation with #wiz remediate

req = Request(api_url)
if token:
req.add_header("PRIVATE-TOKEN", token)
with urlopen(req, timeout=_FETCH_TIMEOUT) as resp:

Choose a reason for hiding this comment

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

Medium SAST Finding

Insecure URL handling in Python urllib module (CWE-939)

More Details

The Python urllib module allows applications to open URLs and retrieve data from the web. However, if the URL is not a literal value and can be controlled by an attacker, it can lead to security vulnerabilities. The urllib module supports the "file://" scheme, which means an attacker could potentially read arbitrary files on the system if they can control the URL value.

This vulnerability poses a significant risk as it can lead to unauthorized access to sensitive information, data leaks, and potentially even remote code execution, depending on the application's context and privileges. It is crucial to avoid passing user-controlled input directly to the urllib module's functions without proper validation and sanitization.

Attribute Value
Impact Medium
Likelihood Medium

Remediation

To mitigate this vulnerability, it is recommended to either:

  1. Hardcode the URLs being used in the urllib module, ensuring that they are not derived from user input or other untrusted sources.
  2. Use a more secure and modern library like the requests module, which does not support the "file://" scheme by default.

Example using the requests module to issue an HTTPS request:

import requests

# Issue a GET request to https://example.com with a timeout of 10 seconds
response = requests.get('https://example.com', timeout=10)

# Work with the response object
# ...

Rule ID: WS-I011-PYTHON-00053


To ignore this finding as an exception, reply to this conversation with #wiz_ignore reason

If you'd like to ignore this finding in all future scans, add an exception in the .wiz file (learn more) or create an Ignore Rule (learn more).


To get more details on how to remediate this issue using AI, reply to this conversation with #wiz remediate

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.

1 participant