mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
Compare commits
42 Commits
d1d03ba421
...
add-links-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2cf2a791b8 | ||
|
|
00ce63484e | ||
|
|
719b59c203 | ||
|
|
33ea05ab19 | ||
|
|
3b4a2c39cb | ||
|
|
9b9af9bbc4 | ||
|
|
8e19c74ccc | ||
|
|
957342fdd4 | ||
|
|
c3e395cd1c | ||
|
|
6a11df4434 | ||
|
|
6204e1b409 | ||
|
|
843c1ae360 | ||
|
|
a997f0b438 | ||
|
|
782b698590 | ||
|
|
59a7002c3e | ||
|
|
b5e13da454 | ||
|
|
5307bf4a8d | ||
|
|
113d1ce05d | ||
|
|
6c97f6d9cc | ||
|
|
a9e5068b6d | ||
|
|
c1213ac802 | ||
|
|
1693f7a8d5 | ||
|
|
0a3b9c10fc | ||
|
|
f249b54ce4 | ||
|
|
7b8558b837 | ||
|
|
2a87120229 | ||
|
|
5a13701cd8 | ||
|
|
6349f20bb9 | ||
|
|
4ce625aa15 | ||
|
|
23a77b75fb | ||
|
|
861f9691be | ||
|
|
a5fe98b0d2 | ||
|
|
d47ff104d6 | ||
|
|
d09adb3edd | ||
|
|
f76847d653 | ||
|
|
06cf9ed0cc | ||
|
|
75390c0979 | ||
|
|
27f5c9591b | ||
|
|
dbff60576b | ||
|
|
ff22d198d0 | ||
|
|
5c2b867546 | ||
|
|
ae2200131f |
26
README.md
26
README.md
@@ -80,19 +80,19 @@ prowler dashboard
|
||||
> For the most accurate and up-to-date information about checks, services, frameworks, and categories, visit [**Prowler Hub**](https://hub.prowler.com).
|
||||
|
||||
|
||||
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | Support | Stage | Interface |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| AWS | 576 | 82 | 38 | 10 | Official | Stable | UI, API, CLI |
|
||||
| GCP | 79 | 13 | 12 | 3 | Official | Stable | UI, API, CLI |
|
||||
| Azure | 162 | 19 | 12 | 4 | Official | Stable | UI, API, CLI |
|
||||
| Kubernetes | 83 | 7 | 5 | 7 | Official | Stable | UI, API, CLI |
|
||||
| GitHub | 17 | 2 | 1 | 0 | Official | Stable | UI, API, CLI |
|
||||
| M365 | 70 | 7 | 3 | 2 | Official | Stable | UI, API, CLI |
|
||||
| OCI | 51 | 13 | 1 | 10 | Official | Stable | UI, API, CLI |
|
||||
| IaC | [See `trivy` docs.](https://trivy.dev/latest/docs/coverage/iac/) | N/A | N/A | N/A | Official | Beta | CLI |
|
||||
| MongoDB Atlas | 10 | 3 | 0 | 0 | Official | Beta | CLI |
|
||||
| LLM | [See `promptfoo` docs.](https://www.promptfoo.dev/docs/red-team/plugins/) | N/A | N/A | N/A | Official | Beta | CLI |
|
||||
| NHN | 6 | 2 | 1 | 0 | Unofficial | Beta | CLI |
|
||||
| Provider | Checks | Services | [Compliance Frameworks](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/compliance/) | [Categories](https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/misc/#categories) | Support | Interface |
|
||||
|---|---|---|---|---|---|---|
|
||||
| AWS | 576 | 82 | 38 | 10 | Official | UI, API, CLI |
|
||||
| GCP | 79 | 13 | 11 | 3 | Official | UI, API, CLI |
|
||||
| Azure | 162 | 19 | 12 | 4 | Official | UI, API, CLI |
|
||||
| Kubernetes | 83 | 7 | 5 | 7 | Official | UI, API, CLI |
|
||||
| GitHub | 17 | 2 | 1 | 0 | Official | UI, API, CLI |
|
||||
| M365 | 70 | 7 | 3 | 2 | Official | UI, API, CLI |
|
||||
| OCI | 51 | 13 | 1 | 10 | Official | UI, API, CLI |
|
||||
| IaC | [See `trivy` docs.](https://trivy.dev/latest/docs/coverage/iac/) | N/A | N/A | N/A | Official | UI, API, CLI |
|
||||
| MongoDB Atlas | 10 | 3 | 0 | 0 | Official | CLI |
|
||||
| LLM | [See `promptfoo` docs.](https://www.promptfoo.dev/docs/red-team/plugins/) | N/A | N/A | N/A | Official | CLI |
|
||||
| NHN | 6 | 2 | 1 | 0 | Unofficial | CLI |
|
||||
|
||||
> [!Note]
|
||||
> The numbers in the table are updated periodically.
|
||||
|
||||
@@ -52,6 +52,11 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
---
|
||||
|
||||
### Changed
|
||||
- Adapt IaC provider to be used in the Prowler App [(#8751)](https://github.com/prowler-cloud/prowler/pull/8751)
|
||||
|
||||
---
|
||||
|
||||
## [v5.13.0] (Prowler v5.13.0)
|
||||
|
||||
### Added
|
||||
|
||||
@@ -17,6 +17,10 @@ SAMPLE_TRIVY_OUTPUT = {
|
||||
"Severity": "LOW",
|
||||
"PrimaryURL": "https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0001",
|
||||
"RuleID": "AVD-AWS-0001",
|
||||
"CauseMetadata": {
|
||||
"StartLine": 10,
|
||||
"EndLine": 15,
|
||||
},
|
||||
},
|
||||
{
|
||||
"ID": "AVD-AWS-0002",
|
||||
@@ -27,6 +31,10 @@ SAMPLE_TRIVY_OUTPUT = {
|
||||
"Severity": "LOW",
|
||||
"PrimaryURL": "https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0002",
|
||||
"RuleID": "AVD-AWS-0002",
|
||||
"CauseMetadata": {
|
||||
"StartLine": 20,
|
||||
"EndLine": 25,
|
||||
},
|
||||
},
|
||||
],
|
||||
"Vulnerabilities": [],
|
||||
@@ -46,6 +54,10 @@ SAMPLE_TRIVY_OUTPUT = {
|
||||
"Severity": "LOW",
|
||||
"PrimaryURL": "https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0003",
|
||||
"RuleID": "AVD-AWS-0003",
|
||||
"CauseMetadata": {
|
||||
"StartLine": 30,
|
||||
"EndLine": 35,
|
||||
},
|
||||
}
|
||||
],
|
||||
"Vulnerabilities": [],
|
||||
@@ -67,6 +79,10 @@ SAMPLE_FAILED_CHECK = {
|
||||
"Severity": "low",
|
||||
"PrimaryURL": "https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0001",
|
||||
"RuleID": "AVD-AWS-0001",
|
||||
"CauseMetadata": {
|
||||
"StartLine": 10,
|
||||
"EndLine": 15,
|
||||
},
|
||||
}
|
||||
|
||||
SAMPLE_PASSED_CHECK = {
|
||||
@@ -78,6 +94,10 @@ SAMPLE_PASSED_CHECK = {
|
||||
"Severity": "low",
|
||||
"PrimaryURL": "https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0003",
|
||||
"RuleID": "AVD-AWS-0003",
|
||||
"CauseMetadata": {
|
||||
"StartLine": 30,
|
||||
"EndLine": 35,
|
||||
},
|
||||
}
|
||||
|
||||
# Additional sample checks
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Snippet } from "@heroui/snippet";
|
||||
import { ExternalLink } from "lucide-react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
||||
import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet";
|
||||
@@ -17,6 +18,7 @@ import { FindingProps, ProviderType } from "@/types";
|
||||
|
||||
import { Muted } from "../muted";
|
||||
import { DeltaIndicator } from "./delta-indicator";
|
||||
import { buildGitFileUrl, extractLineRangeFromUid } from "./git-utils";
|
||||
|
||||
const MarkdownContainer = ({ children }: { children: string }) => {
|
||||
return (
|
||||
@@ -60,6 +62,16 @@ export const FindingDetail = ({
|
||||
params.set("id", findingDetails.id);
|
||||
const url = `${window.location.origin}${currentUrl.pathname}?${params.toString()}`;
|
||||
|
||||
// Build Git URL for IaC findings
|
||||
const gitUrl =
|
||||
providerDetails.provider === "iac"
|
||||
? buildGitFileUrl(
|
||||
providerDetails.uid,
|
||||
resource.name,
|
||||
extractLineRangeFromUid(attributes.uid) || "",
|
||||
)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 rounded-lg">
|
||||
{/* Header */}
|
||||
@@ -238,7 +250,33 @@ export const FindingDetail = ({
|
||||
</CustomSection>
|
||||
|
||||
{/* Resource Details */}
|
||||
<CustomSection title="Resource Details">
|
||||
<CustomSection
|
||||
title={
|
||||
<span className="flex items-center gap-2">
|
||||
Resource Details
|
||||
{gitUrl && (
|
||||
<a
|
||||
href={gitUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title="Go to Resource in the Repository"
|
||||
className="text-blue-600 transition-colors hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
aria-label="Open resource in repository"
|
||||
>
|
||||
<ExternalLink size={16} />
|
||||
</a>
|
||||
)}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<InfoField label="Resource ID" variant="simple">
|
||||
<Snippet className="bg-gray-50 py-1 dark:bg-slate-800" hideSymbol>
|
||||
<span className="text-xs whitespace-pre-line">
|
||||
{renderValue(resource.uid)}
|
||||
</span>
|
||||
</Snippet>
|
||||
</InfoField>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<InfoField label="Resource Name">
|
||||
{renderValue(resource.name)}
|
||||
|
||||
188
ui/components/findings/table/git-utils.ts
Normal file
188
ui/components/findings/table/git-utils.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Extracts line range from a Finding UID
|
||||
* Finding UID format: {CheckID}-{resource_name}-{line_range}
|
||||
* Example: "AVD-AWS-0001-main.tf-10:15" -> "10:15"
|
||||
*
|
||||
* @param findingUid - The finding UID
|
||||
* @returns Line range string or null if not found
|
||||
*/
|
||||
export function extractLineRangeFromUid(findingUid: string): string | null {
|
||||
if (!findingUid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Split by dash and get the last part (line range)
|
||||
const parts = findingUid.split("-");
|
||||
const lastPart = parts[parts.length - 1];
|
||||
|
||||
// Check if the last part is a line range in format "number:number"
|
||||
// This ensures we don't confuse numeric filenames with line ranges
|
||||
if (/^\d+:\d+$/.test(lastPart)) {
|
||||
return lastPart;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Git repository URL with file path and line numbers
|
||||
* Supports GitHub, GitLab, Bitbucket, and generic Git URLs
|
||||
*
|
||||
* @param repoUrl - Repository URL (can be HTTPS or git@ format)
|
||||
* @param filePath - Path to the file in the repository
|
||||
* @param lineRange - Line range in format "10-15" or "10:15" or "10"
|
||||
* @returns Complete URL to the file with line numbers, or null if URL cannot be built
|
||||
*/
|
||||
export function buildGitFileUrl(
|
||||
repoUrl: string,
|
||||
filePath: string,
|
||||
lineRange: string,
|
||||
): string | null {
|
||||
if (!repoUrl || !filePath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Normalize the repository URL
|
||||
let normalizedUrl = repoUrl.trim();
|
||||
|
||||
// Convert git@ format to HTTPS (best effort)
|
||||
if (normalizedUrl.startsWith("git@")) {
|
||||
// git@github.com:user/repo.git -> https://github.com/user/repo
|
||||
normalizedUrl = normalizedUrl
|
||||
.replace(/^git@/, "https://")
|
||||
.replace(/\.git$/, "")
|
||||
.replace(/:([^:]+)$/, "/$1"); // Replace last : with /
|
||||
}
|
||||
|
||||
// Remove .git suffix if present
|
||||
normalizedUrl = normalizedUrl.replace(/\.git$/, "");
|
||||
|
||||
// Parse URL to determine provider
|
||||
const url = new URL(normalizedUrl);
|
||||
const hostname = url.hostname.toLowerCase();
|
||||
|
||||
// Clean up file path (remove leading slashes)
|
||||
const cleanFilePath = filePath.replace(/^\/+/, "");
|
||||
|
||||
// Parse line range
|
||||
const { startLine, endLine } = parseLineRange(lineRange);
|
||||
|
||||
// Build URL based on Git provider
|
||||
if (hostname.includes("github")) {
|
||||
return buildGitHubUrl(normalizedUrl, cleanFilePath, startLine, endLine);
|
||||
} else if (hostname.includes("gitlab")) {
|
||||
return buildGitLabUrl(normalizedUrl, cleanFilePath, startLine, endLine);
|
||||
} else if (hostname.includes("bitbucket")) {
|
||||
return buildBitbucketUrl(
|
||||
normalizedUrl,
|
||||
cleanFilePath,
|
||||
startLine,
|
||||
endLine,
|
||||
);
|
||||
} else {
|
||||
// Generic Git provider - try GitHub format as fallback
|
||||
return buildGitHubUrl(normalizedUrl, cleanFilePath, startLine, endLine);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error building Git file URL:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses line range string into start and end line numbers
|
||||
*/
|
||||
function parseLineRange(lineRange: string): {
|
||||
startLine: number | null;
|
||||
endLine: number | null;
|
||||
} {
|
||||
if (!lineRange || lineRange === "file") {
|
||||
return { startLine: null, endLine: null };
|
||||
}
|
||||
|
||||
// Handle formats: "10-15", "10:15", "10"
|
||||
// Safe regex: anchored pattern for line numbers only (no ReDoS risk)
|
||||
// eslint-disable-next-line security/detect-unsafe-regex
|
||||
const match = lineRange.match(/^(\d+)[-:]?(\d+)?$/);
|
||||
if (match) {
|
||||
const startLine = parseInt(match[1], 10);
|
||||
const endLine = match[2] ? parseInt(match[2], 10) : startLine;
|
||||
return { startLine, endLine };
|
||||
}
|
||||
|
||||
return { startLine: null, endLine: null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds GitHub-style URL
|
||||
* Format: https://github.com/user/repo/blob/main/path/file.tf#L10-L15
|
||||
*/
|
||||
function buildGitHubUrl(
|
||||
baseUrl: string,
|
||||
filePath: string,
|
||||
startLine: number | null,
|
||||
endLine: number | null,
|
||||
): string {
|
||||
// Assume main/master branch for simplicity
|
||||
const branch = "main";
|
||||
let url = `${baseUrl}/blob/${branch}/${filePath}`;
|
||||
|
||||
if (startLine !== null) {
|
||||
if (endLine !== null && endLine !== startLine) {
|
||||
url += `#L${startLine}-L${endLine}`;
|
||||
} else {
|
||||
url += `#L${startLine}`;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds GitLab-style URL
|
||||
* Format: https://gitlab.com/user/repo/-/blob/main/path/file.tf#L10-15
|
||||
*/
|
||||
function buildGitLabUrl(
|
||||
baseUrl: string,
|
||||
filePath: string,
|
||||
startLine: number | null,
|
||||
endLine: number | null,
|
||||
): string {
|
||||
const branch = "main";
|
||||
let url = `${baseUrl}/-/blob/${branch}/${filePath}`;
|
||||
|
||||
if (startLine !== null) {
|
||||
if (endLine !== null && endLine !== startLine) {
|
||||
url += `#L${startLine}-${endLine}`;
|
||||
} else {
|
||||
url += `#L${startLine}`;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds Bitbucket-style URL
|
||||
* Format: https://bitbucket.org/user/repo/src/main/path/file.tf#lines-10:15
|
||||
*/
|
||||
function buildBitbucketUrl(
|
||||
baseUrl: string,
|
||||
filePath: string,
|
||||
startLine: number | null,
|
||||
endLine: number | null,
|
||||
): string {
|
||||
const branch = "main";
|
||||
let url = `${baseUrl}/src/${branch}/${filePath}`;
|
||||
|
||||
if (startLine !== null) {
|
||||
if (endLine !== null && endLine !== startLine) {
|
||||
url += `#lines-${startLine}:${endLine}`;
|
||||
} else {
|
||||
url += `#lines-${startLine}`;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import { type ReactNode } from "react";
|
||||
|
||||
interface CustomSectionProps {
|
||||
title: string;
|
||||
children: React.ReactNode;
|
||||
action?: React.ReactNode;
|
||||
title: string | ReactNode;
|
||||
children: ReactNode;
|
||||
action?: ReactNode;
|
||||
}
|
||||
|
||||
export const CustomSection = ({
|
||||
|
||||
Reference in New Issue
Block a user