diff --git a/website/client/components/Home/TryItResultContent.vue b/website/client/components/Home/TryItResultContent.vue index f22fd168..a59fd9f1 100644 --- a/website/client/components/Home/TryItResultContent.vue +++ b/website/client/components/Home/TryItResultContent.vue @@ -2,7 +2,7 @@ import ace, { type Ace } from 'ace-builds'; import themeTomorrowUrl from 'ace-builds/src-noconflict/theme-tomorrow?url'; import themeTomorrowNightUrl from 'ace-builds/src-noconflict/theme-tomorrow_night?url'; -import { BarChart2, Copy, Download, GitFork, PackageSearch, Share, Terminal } from 'lucide-vue-next'; +import { AlertTriangle, BarChart2, Copy, Download, GitFork, PackageSearch, Share, Terminal } from 'lucide-vue-next'; import { useData } from 'vitepress'; import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; import { VAceEditor } from 'vue3-ace-editor'; @@ -50,6 +50,10 @@ watch(isDark, (newIsDark) => { } }); +const hasSuspiciousFiles = computed(() => { + return props.result.metadata.suspiciousFiles && props.result.metadata.suspiciousFiles.length > 0; +}); + const formattedTimestamp = computed(() => { return formatTimestamp(props.result.metadata.timestamp); }); @@ -205,6 +209,19 @@ onUnmounted(() => { +
+

Security Alert

+

The following files were excluded because they may contain sensitive information:

+ +
+
@@ -350,6 +367,50 @@ dd { padding-left: 8px; } +.security-warning { + background: var(--vp-c-warning-soft); + border-radius: 6px; + padding: 12px; +} + +.warning-icon { + color: var(--vp-c-warning-1); +} + +.warning-description { + font-size: 12px; + color: var(--vp-c-text-2); + margin: 0 0 8px; +} + +.suspicious-files-list { + margin: 0; + padding: 0; + list-style: none; + font-size: 13px; +} + +.suspicious-files-list li { + margin-bottom: 6px; + border-left: 2px solid var(--vp-c-warning-1); + padding-left: 8px; +} + +.suspicious-files-list li:last-child { + margin-bottom: 0; +} + +.suspicious-messages { + display: flex; + flex-direction: column; + gap: 2px; +} + +.suspicious-message { + font-size: 12px; + color: var(--vp-c-text-2); +} + .file-path { color: var(--vp-c-text-1); margin-bottom: 2px; diff --git a/website/client/components/api/client.ts b/website/client/components/api/client.ts index f2e3f3fd..f1fa6f53 100644 --- a/website/client/components/api/client.ts +++ b/website/client/components/api/client.ts @@ -25,6 +25,11 @@ export interface PackRequest { file?: File; } +export interface SuspiciousFile { + filePath: string; + messages: string[]; +} + export interface PackResult { content: string; format: string; @@ -42,6 +47,7 @@ export interface PackResult { tokenCount: number; }[]; allFiles?: FileInfo[]; + suspiciousFiles?: SuspiciousFile[]; }; } diff --git a/website/client/package-lock.json b/website/client/package-lock.json index 62dbffbc..d18311d1 100644 --- a/website/client/package-lock.json +++ b/website/client/package-lock.json @@ -164,7 +164,6 @@ "integrity": "sha512-qI3LcFsVgtvpsBGR7aNSJYxhsR+Zl46+958ODzg8aCxIcdxiK7QEVLMJMZAR57jGqW0Lg/vrjtuLFDMfSE53qA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@algolia/client-common": "5.18.0", "@algolia/requester-browser-xhr": "5.18.0", @@ -325,7 +324,6 @@ "integrity": "sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -2948,7 +2946,6 @@ "integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -3387,7 +3384,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3405,7 +3401,6 @@ "integrity": "sha512-/tfpK2A4FpS0o+S78o3YSdlqXr0MavJIDlFK3XZrlXLy7vaRXJvW5jYg3v5e/wCaF8y0IpMjkYLhoV6QqfpOgw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@algolia/client-abtesting": "5.18.0", "@algolia/client-analytics": "5.18.0", @@ -3623,7 +3618,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -4415,7 +4409,6 @@ "integrity": "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "tabbable": "^6.2.0" } @@ -6167,7 +6160,6 @@ "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.6" }, @@ -7239,7 +7231,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -7372,7 +7363,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", @@ -7707,7 +7697,6 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, diff --git a/website/server/src/domains/pack/processZipFile.ts b/website/server/src/domains/pack/processZipFile.ts index a63b6493..2ba5daef 100644 --- a/website/server/src/domains/pack/processZipFile.ts +++ b/website/server/src/domains/pack/processZipFile.ts @@ -38,7 +38,7 @@ export async function processZipFile(file: File, format: string, options: PackOp fileSummary: options.fileSummary, directoryStructure: options.directoryStructure, compress: options.compress, - securityCheck: false, + securityCheck: true, topFilesLen: 10, include: options.includePatterns, ignore: options.ignorePatterns, @@ -68,6 +68,15 @@ export async function processZipFile(file: File, format: string, options: PackOp // Read the generated file const content = await fs.readFile(outputFilePath, 'utf-8'); + // Map suspicious files results + const suspiciousFiles = + packResult.suspiciousFilesResults.length > 0 + ? packResult.suspiciousFilesResults.map((suspiciousResult) => ({ + filePath: suspiciousResult.filePath, + messages: suspiciousResult.messages, + })) + : undefined; + // Create pack result const packResultData: PackResult = { content, @@ -88,6 +97,7 @@ export async function processZipFile(file: File, format: string, options: PackOp })) .sort((a, b) => b.charCount - a.charCount) .slice(0, cliOptions.topFilesLen), + suspiciousFiles, }, }; diff --git a/website/server/src/types.ts b/website/server/src/types.ts index e376e700..917c7781 100644 --- a/website/server/src/types.ts +++ b/website/server/src/types.ts @@ -28,6 +28,11 @@ interface PackSummary { totalTokens: number; } +export interface SuspiciousFile { + filePath: string; + messages: string[]; +} + export interface PackResult { content: string; format: string; @@ -37,6 +42,7 @@ export interface PackResult { summary?: PackSummary; topFiles?: TopFile[]; allFiles?: FileInfo[]; + suspiciousFiles?: SuspiciousFile[]; }; }