veracarto 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +88 -4
- package/dist/cli/index.js.map +2 -2
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -42963,7 +42963,82 @@ var init_build5 = __esm({
|
|
|
42963
42963
|
});
|
|
42964
42964
|
|
|
42965
42965
|
// src/cli/ui/Detail.tsx
|
|
42966
|
-
function
|
|
42966
|
+
function getFixCommands(item, gcpProjectId) {
|
|
42967
|
+
const meta = typeof item.metadata === "string" ? (() => {
|
|
42968
|
+
try {
|
|
42969
|
+
return JSON.parse(item.metadata);
|
|
42970
|
+
} catch {
|
|
42971
|
+
return {};
|
|
42972
|
+
}
|
|
42973
|
+
})() : item.metadata || {};
|
|
42974
|
+
const resource = item.affected_resource || "";
|
|
42975
|
+
const projectId = gcpProjectId || meta.projectId || meta.gcp_project_id || "YOUR_PROJECT_ID";
|
|
42976
|
+
switch (item.playbook_id) {
|
|
42977
|
+
case "gcp-firewall-broad":
|
|
42978
|
+
return {
|
|
42979
|
+
fix: [
|
|
42980
|
+
`gcloud compute firewall-rules update ${resource} \\`,
|
|
42981
|
+
` --project=${projectId} \\`,
|
|
42982
|
+
` --source-ranges=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16`
|
|
42983
|
+
],
|
|
42984
|
+
rollback: [
|
|
42985
|
+
`gcloud compute firewall-rules update ${resource} \\`,
|
|
42986
|
+
` --project=${projectId} \\`,
|
|
42987
|
+
` --source-ranges=0.0.0.0/0`
|
|
42988
|
+
]
|
|
42989
|
+
};
|
|
42990
|
+
case "gcp-public-bucket":
|
|
42991
|
+
return {
|
|
42992
|
+
fix: [
|
|
42993
|
+
`gcloud storage buckets update gs://${resource} --uniform-bucket-level-access`,
|
|
42994
|
+
`gcloud storage buckets remove-iam-policy-binding gs://${resource} \\`,
|
|
42995
|
+
` --member=allUsers --role=roles/storage.objectViewer`
|
|
42996
|
+
],
|
|
42997
|
+
rollback: [
|
|
42998
|
+
`gcloud storage buckets add-iam-policy-binding gs://${resource} \\`,
|
|
42999
|
+
` --member=allUsers --role=roles/storage.objectViewer`
|
|
43000
|
+
]
|
|
43001
|
+
};
|
|
43002
|
+
case "gcp-overpermissioned-iam": {
|
|
43003
|
+
const member = meta.member || `serviceAccount:${resource}`;
|
|
43004
|
+
const role = meta.role || "roles/editor";
|
|
43005
|
+
return {
|
|
43006
|
+
fix: [
|
|
43007
|
+
`gcloud projects remove-iam-policy-binding ${projectId} \\`,
|
|
43008
|
+
` --member=${member} \\`,
|
|
43009
|
+
` --role=${role}`
|
|
43010
|
+
],
|
|
43011
|
+
rollback: [
|
|
43012
|
+
`gcloud projects add-iam-policy-binding ${projectId} \\`,
|
|
43013
|
+
` --member=${member} \\`,
|
|
43014
|
+
` --role=${role}`
|
|
43015
|
+
]
|
|
43016
|
+
};
|
|
43017
|
+
}
|
|
43018
|
+
case "gcp-audit-logging-disabled":
|
|
43019
|
+
return {
|
|
43020
|
+
fix: [
|
|
43021
|
+
`gcloud projects get-iam-policy ${resource || projectId} --format=json > /tmp/policy.json`,
|
|
43022
|
+
`# Add audit config to policy.json`,
|
|
43023
|
+
`gcloud projects set-iam-policy ${resource || projectId} /tmp/policy.json`
|
|
43024
|
+
],
|
|
43025
|
+
rollback: [
|
|
43026
|
+
`gcloud projects set-iam-policy ${resource || projectId} /tmp/policy-backup.json`
|
|
43027
|
+
]
|
|
43028
|
+
};
|
|
43029
|
+
case "github-dependabot":
|
|
43030
|
+
return {
|
|
43031
|
+
fix: [
|
|
43032
|
+
`# Draft PR: bump ${meta.dependency || "package"} ${meta.fromVersion || ""} \u2192 ${meta.toVersion || "latest"}`,
|
|
43033
|
+
`# PR opened automatically by Veracarto`
|
|
43034
|
+
],
|
|
43035
|
+
rollback: []
|
|
43036
|
+
};
|
|
43037
|
+
default:
|
|
43038
|
+
return null;
|
|
43039
|
+
}
|
|
43040
|
+
}
|
|
43041
|
+
function Detail({ item, slackTeamId, gcpProjectId, onBack, onApprove, onDismiss, onTierChange, onNoise }) {
|
|
42967
43042
|
const [loading, setLoading] = (0, import_react31.useState)(false);
|
|
42968
43043
|
const [dismissMode, setDismissMode] = (0, import_react31.useState)(false);
|
|
42969
43044
|
const [dismissReason, setDismissReason] = (0, import_react31.useState)("");
|
|
@@ -42975,6 +43050,8 @@ function Detail({ item, slackTeamId, onBack, onApprove, onDismiss, onTierChange,
|
|
|
42975
43050
|
const [noiseReason, setNoiseReason] = (0, import_react31.useState)("");
|
|
42976
43051
|
const confidencePct = Math.round((item.confidence || 0) * 100);
|
|
42977
43052
|
const tierColor = TIER_COLORS2[item.tier] || "#888888";
|
|
43053
|
+
const fixCommands = getFixCommands(item, gcpProjectId);
|
|
43054
|
+
const [copied, setCopied] = (0, import_react31.useState)(false);
|
|
42978
43055
|
function getSuggestedRule() {
|
|
42979
43056
|
const resource = item.affected_resource || "unknown";
|
|
42980
43057
|
const category = (item.affected_resource_type || "").toUpperCase();
|
|
@@ -43005,6 +43082,11 @@ function Detail({ item, slackTeamId, onBack, onApprove, onDismiss, onTierChange,
|
|
|
43005
43082
|
if (input === "d" && !loading) {
|
|
43006
43083
|
setDismissMode(true);
|
|
43007
43084
|
}
|
|
43085
|
+
if (input === "c" && !loading && fixCommands) {
|
|
43086
|
+
clipboardy_default.writeSync(fixCommands.fix.join("\n"));
|
|
43087
|
+
setCopied(true);
|
|
43088
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
43089
|
+
}
|
|
43008
43090
|
if (input === "t" && !loading) {
|
|
43009
43091
|
setTierSelectMode(true);
|
|
43010
43092
|
}
|
|
@@ -43065,7 +43147,7 @@ function Detail({ item, slackTeamId, onBack, onApprove, onDismiss, onTierChange,
|
|
|
43065
43147
|
setLoading(false);
|
|
43066
43148
|
}
|
|
43067
43149
|
}
|
|
43068
|
-
return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react31.default.createElement(Box_default, { borderStyle: "single", borderBottom: false, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "\u2190 back"), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: tierColor, bold: true }, "T", item.tier), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, " \xB7 ", confidencePct, "%"))), /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", borderStyle: "single", borderTop: false, borderBottom: false, paddingX: 2, paddingY: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "white" }, item.title), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "RESOURCE"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.affected_resource_type || "unknown", " \xB7 ", item.affected_resource), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, item.is_production ? /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#f59e0b" }, "production") : /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "non-production"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#444444" }, " \xB7 "), item.is_internet_facing ? /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#f59e0b" }, "internet-facing") : /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "internal")), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "AGENT REASONING"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.agent_reasoning || item.description || "No reasoning available."), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "RECOMMENDED ACTION"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.recommended_action || "No recommendation."), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "BLAST RADIUS"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.blast_radius || "Unknown"), loading && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#22c55e" }, /* @__PURE__ */ import_react31.default.createElement(build_default2, { type: "dots" })), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, " executing..."))), resultMessage && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { color: resultMessage.startsWith("\u2713") ? "#22c55e" : "#ef4444" }, resultMessage)), dismissMode && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "Dismiss reason: "), /* @__PURE__ */ import_react31.default.createElement(
|
|
43150
|
+
return /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column" }, /* @__PURE__ */ import_react31.default.createElement(Box_default, { borderStyle: "single", borderBottom: false, paddingX: 1, justifyContent: "space-between" }, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "\u2190 back"), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: tierColor, bold: true }, "T", item.tier), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, " \xB7 ", confidencePct, "%"))), /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", borderStyle: "single", borderTop: false, borderBottom: false, paddingX: 2, paddingY: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "white" }, item.title), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "RESOURCE"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.affected_resource_type || "unknown", " \xB7 ", item.affected_resource), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, item.is_production ? /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#f59e0b" }, "production") : /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "non-production"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#444444" }, " \xB7 "), item.is_internet_facing ? /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#f59e0b" }, "internet-facing") : /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "internal")), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "AGENT REASONING"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.agent_reasoning || item.description || "No reasoning available."), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "RECOMMENDED ACTION"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.recommended_action || "No recommendation."), /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "BLAST RADIUS"), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#cccccc" }, item.blast_radius || "Unknown"), fixCommands && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "FIX COMMAND"), copied ? /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#22c55e" }, " copied") : /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#444444" }, " [c] copy")), /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", borderStyle: "single", paddingX: 1 }, fixCommands.fix.map((line, i) => /* @__PURE__ */ import_react31.default.createElement(Text, { key: `fix-${i}`, color: "#22c55e" }, line)))), fixCommands && fixCommands.rollback.length > 0 && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { bold: true, color: "#888888" }, "ROLLBACK"), /* @__PURE__ */ import_react31.default.createElement(Box_default, { flexDirection: "column", borderStyle: "single", paddingX: 1 }, fixCommands.rollback.map((line, i) => /* @__PURE__ */ import_react31.default.createElement(Text, { key: `rb-${i}`, color: "#888888" }, line)))), loading && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#22c55e" }, /* @__PURE__ */ import_react31.default.createElement(build_default2, { type: "dots" })), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, " executing..."))), resultMessage && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Text, { color: resultMessage.startsWith("\u2713") ? "#22c55e" : "#ef4444" }, resultMessage)), dismissMode && /* @__PURE__ */ import_react31.default.createElement(import_react31.default.Fragment, null, /* @__PURE__ */ import_react31.default.createElement(Text, null, " "), /* @__PURE__ */ import_react31.default.createElement(Box_default, null, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "Dismiss reason: "), /* @__PURE__ */ import_react31.default.createElement(
|
|
43069
43151
|
build_default,
|
|
43070
43152
|
{
|
|
43071
43153
|
value: dismissReason,
|
|
@@ -43115,7 +43197,7 @@ function Detail({ item, slackTeamId, onBack, onApprove, onDismiss, onTierChange,
|
|
|
43115
43197
|
}
|
|
43116
43198
|
}
|
|
43117
43199
|
}
|
|
43118
|
-
)), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#444444" }, "[enter] submit [esc] cancel"))), /* @__PURE__ */ import_react31.default.createElement(Box_default, { borderStyle: "single", borderTop: false, paddingX: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "[a] mark fixed [d] dismiss [n] noise [e] exception [t] tier [esc] back")));
|
|
43200
|
+
)), /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#444444" }, "[enter] submit [esc] cancel"))), /* @__PURE__ */ import_react31.default.createElement(Box_default, { borderStyle: "single", borderTop: false, paddingX: 1 }, /* @__PURE__ */ import_react31.default.createElement(Text, { color: "#888888" }, "[a] mark fixed [c] copy fix [d] dismiss [n] noise [e] exception [t] tier [esc] back")));
|
|
43119
43201
|
}
|
|
43120
43202
|
var import_react31, TIER_COLORS2, TIER_ITEMS;
|
|
43121
43203
|
var init_Detail = __esm({
|
|
@@ -43127,6 +43209,7 @@ var init_Detail = __esm({
|
|
|
43127
43209
|
await init_build5();
|
|
43128
43210
|
await init_build4();
|
|
43129
43211
|
init_open();
|
|
43212
|
+
init_clipboardy();
|
|
43130
43213
|
init_api();
|
|
43131
43214
|
TIER_COLORS2 = {
|
|
43132
43215
|
1: "#888888",
|
|
@@ -44447,6 +44530,7 @@ function Dashboard() {
|
|
|
44447
44530
|
{
|
|
44448
44531
|
item: selectedItem,
|
|
44449
44532
|
slackTeamId,
|
|
44533
|
+
gcpProjectId: status?.gcpProjectId,
|
|
44450
44534
|
onBack: () => {
|
|
44451
44535
|
setView("dashboard");
|
|
44452
44536
|
setSelectedItem(null);
|
|
@@ -45058,7 +45142,7 @@ var {
|
|
|
45058
45142
|
// src/cli/index.ts
|
|
45059
45143
|
init_config();
|
|
45060
45144
|
var program2 = new Command();
|
|
45061
|
-
program2.name("veracarto").description("Security findings, down to what matters").version("0.1.
|
|
45145
|
+
program2.name("veracarto").description("Security findings, down to what matters").version("0.1.7");
|
|
45062
45146
|
program2.command("init").description("Interactive onboarding wizard").option("--step <step>", "Jump to a specific step (gcp, github, slack)").action(async (opts) => {
|
|
45063
45147
|
const { runInit: runInit2 } = await init_init().then(() => init_exports);
|
|
45064
45148
|
await runInit2(opts.step);
|