Skip to content

Conversation

@toniblyx
Copy link
Member

@toniblyx toniblyx commented Jan 7, 2026

Context

Prowler currently supports sending security findings to Jira, but many teams use GitHub Issues for tracking security vulnerabilities and remediation tasks. This PR adds a complete GitHub integration that allows users to send Prowler findings as GitHub Issues, following the same pattern as the existing Jira integration.

Description

This PR implements a full-featured GitHub integration that creates GitHub Issues from Prowler security findings. The integration uses GitHub Personal Access Tokens (PAT) for authentication and provides a seamless experience similar to the existing Jira integration.

Key Features:

GitHub API Client:

  • Personal Access Token (PAT) authentication
  • Automatic repository discovery and validation
  • Label support for issue categorization
  • Rich markdown-formatted issues with comprehensive finding details
  • Connection testing and validation
  • Comprehensive error handling with custom exception classes

API Integration:

  • New integration type: "github"
  • CRUD operations for GitHub integrations
  • Async task processing for bulk operations
  • Repository access validation before dispatch
  • Support for filtering findings before sending

UI Components:

  • Complete React components following Prowler UI patterns
  • GitHub integration form with token and owner inputs
  • Integrations manager for listing and managing GitHub integrations
  • Integration card for main integrations overview page
  • Server actions for dispatching findings and polling tasks
  • Full TypeScript typing with Zod validation schemas

Security:

  • GitHub PAT encrypted with Fernet before storage
  • Repository access validated before allowing dispatch
  • All API calls use HTTPS
  • Comprehensive error handling and logging

Issue Format:

  • Title: [Prowler] SEVERITY - CHECK_ID - RESOURCE_UID
  • Body: Markdown-formatted with:
    • Finding details table (severity, status, provider, region, resource info)
    • Risk description
    • Remediation recommendations with URLs
    • Code blocks for remediation (CLI, Terraform, Native IaC)
    • Resource tags
    • Compliance framework mappings
    • Link back to finding in Prowler

Changes Include:

New Backend Files:

  • prowler/lib/outputs/github/github.py - Main GitHub API client class
  • prowler/lib/outputs/github/exceptions/exceptions.py - Custom exception classes
  • prowler/lib/outputs/github/__init__.py - Package exports
  • prowler/lib/outputs/github/exceptions/__init__.py - Exception exports

Modified Backend Files:

  • api/src/backend/api/models.py - Add GitHub to Integration choices
  • api/src/backend/api/utils.py - Add GitHub integration initialization and connection testing
  • api/src/backend/api/filters.py - Add IntegrationGitHubFindingsFilter
  • api/src/backend/api/v1/serializer_utils/integrations.py - Add GitHub serializers
  • api/src/backend/api/v1/serializers.py - Add GitHub dispatch serializer and validation
  • api/src/backend/api/v1/urls.py - Add GitHub integration routing
  • api/src/backend/api/v1/views.py - Add IntegrationGitHubViewSet
  • api/src/backend/tasks/tasks.py - Add github_integration_task
  • api/src/backend/tasks/jobs/integrations.py - Add send_findings_to_github job

New UI Files:

  • ui/components/integrations/github/github-integration-form.tsx - Form component
  • ui/components/integrations/github/github-integrations-manager.tsx - Manager component
  • ui/components/integrations/github/github-integration-card.tsx - Card component
  • ui/actions/integrations/github-dispatch.ts - Server actions for dispatch
  • ui/app/(prowler)/integrations/github/page.tsx - GitHub integrations page
  • ui/types/integrations.ts - Added GitHub schemas and types

Modified UI Files:

  • ui/components/integrations/index.ts - Export GitHub components
  • ui/app/(prowler)/integrations/page.tsx - Add GitHub integration card

API Endpoints

Create GitHub Integration:

POST /api/v1/integrations
{
  "integration_type": "github",
  "enabled": true,
  "credentials": {
    "token": "ghp_xxxxxxxxxxxx",
    "owner": "myorg"  // optional
  },
  "configuration": {},
  "providers": []
}

Test Connection:

POST /api/v1/integrations/{integration_id}/connection

Send Findings to GitHub:

POST /api/v1/integrations/{integration_id}/github/dispatches
{
  "repository": "owner/repo",
  "labels": ["security", "prowler"],  // optional
  "finding_id": "uuid"  // or finding_id__in for multiple
}

Steps to Review

  1. Review GitHub API Client (prowler/lib/outputs/github/github.py):

    • Check authentication implementation
    • Review repository fetching logic
    • Verify issue creation with markdown formatting
    • Review error handling
  2. Review Backend Integration:

    • Check model changes in api/models.py
    • Review serializers and validators in api/v1/serializer_utils/integrations.py
    • Verify ViewSet implementation in api/v1/views.py
    • Check URL routing in api/v1/urls.py
  3. Review Async Tasks:

    • Check task definition in tasks/tasks.py
    • Review job logic in tasks/jobs/integrations.py
    • Verify connection testing in api/utils.py
  4. Review UI Components:

    • Check form component in ui/components/integrations/github/github-integration-form.tsx
    • Review manager component in ui/components/integrations/github/github-integrations-manager.tsx
    • Verify card component in ui/components/integrations/github/github-integration-card.tsx
    • Check server actions in ui/actions/integrations/github-dispatch.ts
    • Review page integration in ui/app/(prowler)/integrations/github/page.tsx
  5. Review Security:

    • Verify PAT encryption
    • Check repository access validation
    • Review HTTPS usage in API calls

Testing Checklist

Backend:

  • Create GitHub integration with valid PAT
  • Test connection returns accessible repositories
  • Send single finding creates GitHub issue with correct format
  • Send multiple findings in batch (async processing)
  • Verify markdown rendering in GitHub issues
  • Test with labels applied correctly
  • Test invalid token fails gracefully
  • Test unauthorized repository access is rejected
  • Update integration credentials works
  • Delete integration removes configuration

UI:

  • Integration card appears on main integrations page
  • Create integration form validates inputs correctly
  • Token input is properly masked (password field)
  • Owner field is optional and works correctly
  • Test connection button triggers repository fetch
  • Manager displays list of integrations with status
  • Edit credentials modal works correctly
  • Enable/disable toggle functions properly
  • Delete integration shows confirmation modal
  • Repository count displays correctly
  • Last synced timestamp formats correctly

Checklist

  • Are there new checks included in this PR? No
  • Review if the code is being covered by tests - Unit tests pending
  • Review if code is being documented following Python docstring standards
  • Review if backport is needed - Not applicable for new feature
  • Review if README.md needs updates - Documentation pending
  • Ensure new entries are added to CHANGELOG.md - To be added

UI

  • All issue/task requirements work as expected on the UI - Components implemented
  • Frontend follows existing integration patterns (Jira)
  • Screenshots/Video of the functionality flow - To be added
  • Ensure new entries are added to ui/CHANGELOG.md - To be added

API

  • Verify if API specs need to be regenerated - New endpoints added
  • Check if version updates are required
  • Ensure new entries are added to api/CHANGELOG.md - To be added

Implementation Summary

Backend (13 files changed, ~1,070 lines added):

  • Complete GitHub API client with PAT authentication
  • Integration model updates and serializers
  • ViewSet and URL routing for GitHub endpoints
  • Async task processing for bulk operations
  • Connection testing and repository discovery

UI (8 files changed, ~928 lines added):

  • Form component for creating/editing integrations
  • Manager component for listing integrations
  • Card component for main integrations page
  • Server actions for dispatching and polling
  • Complete TypeScript typing with Zod schemas
  • Integration page at /integrations/github

Total: 21 files changed, ~2,000 lines added

Next Steps

  1. Database Migration: Create Django migration for GitHub integration type
  2. Tests: Add unit and integration tests for backend and UI
  3. Documentation: Update README and add usage documentation
  4. Changelog: Add entries to relevant CHANGELOG files
  5. Screenshots: Add UI screenshots to PR

License

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Add complete GitHub integration to Prowler that allows sending security
findings as GitHub Issues, working similarly to the existing Jira integration.

Features:
- GitHub API client with Personal Access Token (PAT) authentication
- Support for creating issues from Prowler findings
- Automatic repository discovery and validation
- Label support for issue categorization
- Rich markdown-formatted issues with detailed finding information
- Full API integration with CRUD operations
- Async task processing for bulk operations
- Connection testing and validation

Implementation:
- Add GitHub API client in prowler/lib/outputs/github/
- Add GitHub to Integration model choices
- Create serializers and validators for GitHub credentials and configuration
- Implement IntegrationGitHubViewSet for API endpoints
- Add async tasks and job processing for sending findings
- Add URL routing for /integrations/{id}/github/dispatches endpoint

API Changes:
- New integration type: "github"
- Credentials: token (required), owner (optional)
- Configuration: repositories dict, owner string
- Dispatch endpoint accepts repository and optional labels

Issue Format:
- Title: [Prowler] SEVERITY - CHECK_ID - RESOURCE_UID
- Body includes: finding details, risk description, recommendations,
  remediation code (CLI/Terraform/IaC), resource tags, compliance info

Security:
- GitHub PAT encrypted with Fernet before storage
- Repository access validated before dispatch
- All API calls use HTTPS
- Comprehensive error handling and logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@toniblyx toniblyx requested review from a team as code owners January 7, 2026 20:39
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

Conflict Markers Resolved

All conflict markers have been successfully resolved in this pull request.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

⚠️ Changes detected in the following folders without a corresponding update to the CHANGELOG.md:

  • api
  • ui
  • prowler

Please add an entry to the corresponding CHANGELOG.md file to maintain a clear history of changes.



def initialize_prowler_integration(integration: Integration) -> Jira:
def initialize_prowler_integration(integration: Integration):

Check notice

Code scanning / CodeQL

Explicit returns mixed with implicit (fall through) returns

Mixing implicit and explicit returns may indicate an error, as implicit returns always return None.

Copilot Autofix

AI 11 days ago

In general, to fix mixed explicit/implicit returns, ensure that every code path ends with an explicit return (either returning a value or None/raising). Here, the function currently returns a client for GitHub and JIRA, and implicitly returns None for other integration types or future additions. The safest, most explicit fix without changing existing successful behavior is to add a final return None at the end of the function. This preserves current semantics (callers that previously got None still get None) but makes the intent and return type consistent and removes the implicit fall-through. No extra imports or helper methods are needed; we only add a single explicit return None before the end of initialize_prowler_integration in api/src/backend/api/utils.py.

Suggested changeset 1
api/src/backend/api/utils.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/api/src/backend/api/utils.py b/api/src/backend/api/utils.py
--- a/api/src/backend/api/utils.py
+++ b/api/src/backend/api/utils.py
@@ -433,6 +433,7 @@
                 integration.configuration["repositories"] = {}
                 integration.connected = False
                 integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
+                integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
                 integration.save()
             raise github_auth_error
     elif integration.integration_type == Integration.IntegrationChoices.JIRA:
@@ -445,3 +446,5 @@
                 integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
                 integration.save()
             raise jira_auth_error
+
+    return None
EOF
@@ -433,6 +433,7 @@
integration.configuration["repositories"] = {}
integration.connected = False
integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
integration.save()
raise github_auth_error
elif integration.integration_type == Integration.IntegrationChoices.JIRA:
@@ -445,3 +446,5 @@
integration.connection_last_checked_at = datetime.now(tz=timezone.utc)
integration.save()
raise jira_auth_error

return None
Copilot is powered by AI and may make mistakes. Always verify output.
@codecov
Copy link

codecov bot commented Jan 7, 2026

Codecov Report

❌ Patch coverage is 12.93801% with 323 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.49%. Comparing base (df8d823) to head (5532770).
⚠️ Report is 38 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9732      +/-   ##
==========================================
- Coverage   92.46%   86.49%   -5.98%     
==========================================
  Files         160      277     +117     
  Lines       22814    30139    +7325     
==========================================
+ Hits        21096    26069    +4973     
- Misses       1718     4070    +2352     
Flag Coverage Δ
api 92.14% <36.09%> (-0.33%) ⬇️
prowler-py3.10-github 78.02% <ø> (?)
prowler-py3.10-lib 68.48% <0.00%> (?)
prowler-py3.11-github 78.02% <ø> (?)
prowler-py3.11-lib 68.48% <0.00%> (?)
prowler-py3.12-github 78.02% <ø> (?)
prowler-py3.12-lib 68.48% <0.00%> (?)
prowler-py3.9-github 78.02% <ø> (?)
prowler-py3.9-lib 68.48% <0.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
prowler 68.48% <0.00%> (∅)
api 92.14% <36.09%> (-0.33%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

🔒 Container Security Scan

Image: prowler-api:628b724
Last scan: 2026-01-07 20:49:00 UTC

📊 Vulnerability Summary

Severity Count
🔴 Critical 11
Total 11

10 package(s) affected

⚠️ Action Required

Critical severity vulnerabilities detected. These should be addressed before merging:

  • Review the detailed scan results
  • Update affected packages to patched versions
  • Consider using a different base image if updates are unavailable

📋 Resources:

Add complete frontend implementation for GitHub integration following
the same pattern as Jira integration.

Components:
- GitHubIntegrationForm: Form for creating/editing GitHub integrations
- GitHubIntegrationsManager: Manager component for listing and managing integrations
- GitHubIntegrationCard: Card component for main integrations page
- GitHub integration page at /integrations/github

Features:
- Personal Access Token input with validation
- Optional repository owner filter
- Connection testing and repository discovery
- Enable/disable integration toggle
- Edit credentials functionality
- Delete integration with confirmation
- Pagination support
- Integration status display with last checked timestamp

Server Actions:
- getGitHubIntegrations(): Fetch enabled GitHub integrations
- sendFindingToGitHub(): Send finding to GitHub as issue
- pollGitHubDispatchTask(): Poll async task completion

Types & Schemas:
- githubIntegrationFormSchema: Zod schema for creation
- editGitHubIntegrationFormSchema: Zod schema for editing
- GitHubCredentialsPayload: TypeScript interface for credentials
- GitHubDispatchRequest/Response: API types for dispatching

Integration Page:
- Created /integrations/github page with features list
- Added GitHub card to main integrations overview
- Exported GitHub components from integrations index

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@toniblyx toniblyx requested a review from a team as a code owner January 7, 2026 20:44
Comment on lines +95 to +99
const response = await fetch(url.toString(), {
method: "POST",
headers,
body: JSON.stringify(payload),
});

Check failure

Code scanning / CodeQL

Server-side request forgery Critical

The
URL
of this request depends on a
user-provided value
.

Copilot Autofix

AI 11 days ago

In general, to fix this type of issue you constrain user-controlled values before incorporating them into request URLs. You either (a) map them to known safe constants (allow‑list) or (b) strictly validate them against an expected format and reject or sanitize anything that doesn’t conform. For path segments, you must prevent path traversal (../), slashes, and other characters that could alter the intended endpoint.

For this specific case, the best minimal fix without changing existing functionality is to validate integrationId against a strict pattern of allowed characters before building the URL. A typical approach is to allow only URL-safe identifier characters such as letters, digits, hyphens, and underscores, and reject anything else. If the value fails validation, we return an error before making the request. This confines the request to the intended /integrations/{safe-id}/github/dispatches path and prevents manipulation like embedding slashes or .. segments.

Implementation details within ui/actions/integrations/github-dispatch.ts:

  • Add a small helper function (inside this file) that checks integrationId with a regular expression such as /^[A-Za-z0-9_-]+$/. If it doesn’t match, the function should return false.
  • At the beginning of sendFindingToGitHub, use this helper to validate integrationId. If invalid, immediately return { success: false, error: "Invalid integration ID" } (or similar) instead of continuing.
  • Keep the rest of the logic unchanged: apiBaseUrl continues to define the host, and integrationId is only used once it is known to match the safe pattern.

No new imports are needed; we can implement validation using built‑in JavaScript/TypeScript capabilities.

Suggested changeset 1
ui/actions/integrations/github-dispatch.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/ui/actions/integrations/github-dispatch.ts b/ui/actions/integrations/github-dispatch.ts
--- a/ui/actions/integrations/github-dispatch.ts
+++ b/ui/actions/integrations/github-dispatch.ts
@@ -73,6 +73,16 @@
   | { success: true; taskId: string; message: string }
   | { success: false; error: string }
 > => {
+  // Validate integrationId to avoid using unsafe path segments in the request URL
+  // Allow only URL-safe identifier characters (letters, digits, underscores, hyphens).
+  const integrationIdIsValid = /^[A-Za-z0-9_-]+$/.test(integrationId);
+  if (!integrationIdIsValid) {
+    return {
+      success: false,
+      error: "Invalid integration ID",
+    };
+  }
+
   const headers = await getAuthHeaders({ contentType: true });
   const url = new URL(
     `${apiBaseUrl}/integrations/${integrationId}/github/dispatches`,
EOF
@@ -73,6 +73,16 @@
| { success: true; taskId: string; message: string }
| { success: false; error: string }
> => {
// Validate integrationId to avoid using unsafe path segments in the request URL
// Allow only URL-safe identifier characters (letters, digits, underscores, hyphens).
const integrationIdIsValid = /^[A-Za-z0-9_-]+$/.test(integrationId);
if (!integrationIdIsValid) {
return {
success: false,
error: "Invalid integration ID",
};
}

const headers = await getAuthHeaders({ contentType: true });
const url = new URL(
`${apiBaseUrl}/integrations/${integrationId}/github/dispatches`,
Copilot is powered by AI and may make mistakes. Always verify output.
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

🔒 Container Security Scan

Image: prowler:628b724
Last scan: 2026-01-07 20:53:35 UTC

📊 Vulnerability Summary

Severity Count
🔴 Critical 3
Total 3

3 package(s) affected

⚠️ Action Required

Critical severity vulnerabilities detected. These should be addressed before merging:

  • Review the detailed scan results
  • Update affected packages to patched versions
  • Consider using a different base image if updates are unavailable

📋 Resources:

@jfagoagas
Copy link
Member

I'm closing this as requested. We'll work on this once prioritised.

@jfagoagas jfagoagas closed this Jan 12, 2026
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.

3 participants