Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/lib/api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,25 @@
| "invalid"
| "valid";

export interface Incident {
type IncidentVaultProperties = {
secret_vaulted: false;
} | {
secret_vaulted: true;
vault_type: string;
vault_name: string;
vault_path: string;
vault_path_count: number;
}

Check warning on line 27 in src/lib/api-types.ts

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

Missing semicolon

Check warning on line 27 in src/lib/api-types.ts

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

Missing semicolon

Check warning on line 27 in src/lib/api-types.ts

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

Missing semicolon

export type Incident = {
type: string;
occurrences: Occurrence[];
validity: Validity;
ignore_sha: string;
known_secret: boolean;
incident_url: string;
total_occurrences: number;
secret_vaulted: boolean;
}
} & IncidentVaultProperties

Check warning on line 37 in src/lib/api-types.ts

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

Missing semicolon

Check warning on line 37 in src/lib/api-types.ts

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

Missing semicolon

Check warning on line 37 in src/lib/api-types.ts

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

Missing semicolon

export interface EntityWithIncidents {
incidents: Incident[];
Expand Down
22 changes: 20 additions & 2 deletions src/lib/ggshield-results-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
Occurrence,
Validity,
} from "./api-types";
import { pluralize } from "../utils";

const validityDisplayName: Record<Validity, string> = {
unknown: "Unknown",
Expand Down Expand Up @@ -45,6 +46,7 @@ function filterUriOccurrences(occurrences: Occurrence[]): Occurrence[] {
* @param results ggshield scan results
* @returns incidents diagnostics
*/

export function parseGGShieldResults(
results: GGShieldScanResults,
): Diagnostic[] {
Expand All @@ -63,6 +65,22 @@ export function parseGGShieldResults(
new Position(occurrence.line_start - 1, occurrence.index_start),
new Position(occurrence.line_end - 1, occurrence.index_end),
);

let vaultInfo = "";

if (incident.secret_vaulted) {
if (incident.vault_path_count !== null) {
vaultInfo += `Secret found in vault: YES (${incident.vault_path_count} ${pluralize(incident.vault_path_count, "location")})
├─ Vault Type: ${incident.vault_type}
├─ Vault Name: ${incident.vault_name}
└─ Secret Path: ${incident.vault_path}`;
} else {
vaultInfo += "Secret found in vault: YES";
}
} else {
vaultInfo += "Secret found in vault: NO";
}

let diagnostic = new Diagnostic(
range,
`ggshield: ${occurrence.type}
Expand All @@ -73,11 +91,11 @@ Known by GitGuardian dashboard: ${incident.known_secret ? "YES" : "NO"}
Total occurrences: ${incident.total_occurrences}
Incident URL: ${incident.incident_url || "N/A"}
Secret SHA: ${incident.ignore_sha}
Secret in Secrets Manager: ${incident.secret_vaulted ? "YES" : "NO"}`,
${vaultInfo}`,
DiagnosticSeverity.Warning,
);

diagnostic.source = "gitguardian";
diagnostic.source = "\ngitguardian";
diagnostics.push(diagnostic);
},
);
Expand Down
45 changes: 45 additions & 0 deletions src/test/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,48 @@ export const scanResultsWithUriIncident = `{
"total_occurrences": 1,
"secrets_engine_version": "2.126.0"
}`;

export const scanResultsVaulted = `{
"id":"test.py",
"type":"path_scan",
"entities_with_incidents":[
{
"mode":"FILE",
"filename":"test.py",
"incidents":[
{
"policy":"Secrets detection",
"occurrences":[
{
"match":"DDACC73DdB04********************************************057c78317C39",
"type":"apikey",
"line_start":4,
"line_end":4,
"index_start":11,
"index_end":79,
"pre_line_start":4,
"pre_line_end":4
}
],
"type":"Generic High Entropy Secret",
"validity":"no_checker",
"ignore_sha":"38353eb1a2aac5b24f39ed67912234d4b4a2e23976d504a88b28137ed2b9185e",
"total_occurrences":2,
"incident_url":"",
"known_secret":false,
"secret_vaulted": true,
"vault_type": "AWS Secrets Manager",
"vault_name": "463175827647/us-west-2",
"vault_path": "arn:aws:secretsmanager:us-west-2:463175827647:secret:xav-test-svef2q:pwd",
"vault_path_count": 2

}
],
"total_incidents":1,
"total_occurrences":1
}
],
"total_incidents":1,
"total_occurrences":1,
"secrets_engine_version":"2.96.0"
}`;
14 changes: 13 additions & 1 deletion src/test/suite/results-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { parseGGShieldResults } from "../../lib/ggshield-results-parser";
import { DiagnosticSeverity } from "vscode";
import {
scanResultsNoIncident,
scanResultsVaulted,
scanResultsWithIncident,
scanResultsWithUriIncident,
} from "../constants";
Expand All @@ -17,14 +18,25 @@ suite("parseGGShieldResults", () => {
const diagnostic = diagnostics[0];
assert.ok(diagnostic.message.includes("apikey"));
assert.ok(diagnostic.message.includes("Generic High Entropy Secret"));
assert.ok(diagnostic.message.includes("Secret in Secrets Manager: NO"));
assert.ok(diagnostic.message.includes("Secret found in vault: NO"));
assert.strictEqual(diagnostic.range.start.line, 3);
assert.strictEqual(diagnostic.range.start.character, 11);
assert.strictEqual(diagnostic.range.end.line, 3);
assert.strictEqual(diagnostic.range.end.character, 79);
assert.strictEqual(diagnostic.severity, DiagnosticSeverity.Warning);
});

test("Should parse vault information", () => {
const diagnostics = parseGGShieldResults(
JSON.parse(scanResultsVaulted),
);
const diagnostic = diagnostics[0];
assert.ok(diagnostic.message.includes("Secret found in vault: YES"));
assert.ok(diagnostic.message.includes("├─ Vault Type: AWS Secrets Manager"));
assert.ok(diagnostic.message.includes("├─ Vault Name: 463175827647/us-west-2"));
assert.ok(diagnostic.message.includes("└─ Secret Path: arn:aws:secretsmanager:us-west-2:463175827647:secret:xav-test-svef2q:pwd"));
});

test("Should return an empty array if there are no incidents", () => {
const diagnostics = parseGGShieldResults(JSON.parse(scanResultsNoIncident));
assert.strictEqual(diagnostics.length, 0);
Expand Down
4 changes: 4 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@
return "";
}
}

export function pluralize(num: number, word: string): string {
return `${[1, -1].includes(num) ? word : word + "s"}`

Check warning on line 34 in src/utils.ts

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

Missing semicolon

Check warning on line 34 in src/utils.ts

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

Missing semicolon

Check warning on line 34 in src/utils.ts

View workflow job for this annotation

GitHub Actions / build-and-test (windows-latest)

Missing semicolon
}
Loading