Skip to content

Commit

Permalink
feat(security): Add option to control security check
Browse files Browse the repository at this point in the history
  • Loading branch information
yamadashy committed Sep 11, 2024
1 parent 90e092b commit d6afb28
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 13 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ Here's an explanation of the configuration options:
|`ignore.useGitignore`| Whether to use patterns from the project's `.gitignore` file |`true`|
|`ignore.useDefaultPatterns`| Whether to use default ignore patterns |`true`|
|`ignore.customPatterns`| Additional patterns to ignore (using glob patterns) |`[]`|
|`security.enableSecurityCheck`| Whether to perform security checks on files |`true`|

Example configuration:

Expand All @@ -320,6 +321,9 @@ Example configuration:
"useGitignore": true,
"useDefaultPatterns": true,
"customPatterns": ["additional-folder", "**/*.log"]
},
"security": {
"enableSecurityCheck": true
}
}
```
Expand Down Expand Up @@ -431,6 +435,16 @@ Example output:
Please review these files for potential sensitive information.
```

By default, the security check is enabled. You can disable it by setting `security.enableSecurityCheck` to `false` in your configuration file:

```json
{
"security": {
"enableSecurityCheck": false
}
}
```



## 📜 License
Expand Down
3 changes: 2 additions & 1 deletion src/cli/actions/defaultActionRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export const runDefaultAction = async (
logger.log('');
}

printSecurityCheck(cwd, packResult.suspiciousFilesResults);
printSecurityCheck(cwd, packResult.suspiciousFilesResults, config);
logger.log('');

printSummary(
Expand All @@ -88,6 +88,7 @@ export const runDefaultAction = async (
packResult.totalTokens,
config.output.filePath,
packResult.suspiciousFilesResults,
config
);
logger.log('');

Expand Down
18 changes: 14 additions & 4 deletions src/cli/cliPrinter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from 'node:path';
import pc from 'picocolors';
import type { RepopackConfigMerged } from '../config/configTypes.js';
import type { SuspiciousFileResult } from '../core/security/securityCheckRunner.js';
import { logger } from '../shared/logger.js';

Expand All @@ -9,12 +10,17 @@ export const printSummary = (
totalTokens: number,
outputPath: string,
suspiciousFilesResults: SuspiciousFileResult[],
config: RepopackConfigMerged,
) => {
let securityCheckMessage = '';
if (suspiciousFilesResults.length > 0) {
securityCheckMessage = pc.yellow(`${suspiciousFilesResults.length} suspicious file(s) detected and excluded`);
if (config.security.enableSecurityCheck) {
if (suspiciousFilesResults.length > 0) {
securityCheckMessage = pc.yellow(`${suspiciousFilesResults.length} suspicious file(s) detected and excluded`);
} else {
securityCheckMessage = pc.white('✔ No suspicious files detected');
}
} else {
securityCheckMessage = pc.white('✔ No suspicious files detected');
securityCheckMessage = pc.dim('Security check disabled');
}

logger.log(pc.white('📊 Pack Summary:'));
Expand All @@ -26,7 +32,11 @@ export const printSummary = (
logger.log(`${pc.white(' Security:')} ${pc.white(securityCheckMessage)}`);
};

export const printSecurityCheck = (rootDir: string, suspiciousFilesResults: SuspiciousFileResult[]) => {
export const printSecurityCheck = (rootDir: string, suspiciousFilesResults: SuspiciousFileResult[], config: RepopackConfigMerged) => {
if (!config.security.enableSecurityCheck) {
return;
}

logger.log(pc.white('🔎 Security Check:'));
logger.log(pc.dim('──────────────────'));

Expand Down
5 changes: 5 additions & 0 deletions src/config/configLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,9 @@ export const mergeConfigs = (
],
},
include: [...(defaultConfig.include || []), ...(fileConfig.include || []), ...(cliConfig.include || [])],
security: {
...defaultConfig.security,
...fileConfig.security,
...cliConfig.security,
},
});
6 changes: 6 additions & 0 deletions src/config/configTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ interface RepopackConfigBase {
useDefaultPatterns?: boolean;
customPatterns?: string[];
};
security?: {
enableSecurityCheck?: boolean;
};
}

export type RepopackConfigDefault = RepopackConfigBase & {
Expand All @@ -36,6 +39,9 @@ export type RepopackConfigDefault = RepopackConfigBase & {
useDefaultPatterns: boolean;
customPatterns?: string[];
};
security: {
enableSecurityCheck: boolean;
};
};

export type RepopackConfigFile = RepopackConfigBase;
Expand Down
16 changes: 14 additions & 2 deletions src/config/configValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function validateConfig(config: unknown): asserts config is RepopackConfi
throw new RepopackConfigValidationError('Configuration must be an object');
}

const { output, ignore } = config as Partial<RepopackConfigFile>;
const { output, ignore, security } = config as Partial<RepopackConfigFile>;

// Validate output
if (output !== undefined) {
Expand All @@ -38,7 +38,7 @@ export function validateConfig(config: unknown): asserts config is RepopackConfi
}
}

// Validate ignore (existing code remains unchanged)
// Validate ignore
if (ignore !== undefined) {
if (typeof ignore !== 'object' || ignore == null) {
throw new RepopackConfigValidationError('ignore must be an object');
Expand All @@ -57,4 +57,16 @@ export function validateConfig(config: unknown): asserts config is RepopackConfi
}
}
}

// Validate security
if (security !== undefined) {
if (typeof security !== 'object' || security == null) {
throw new RepopackConfigValidationError('security must be an object');
}

const { enableSecurityCheck } = security;
if (enableSecurityCheck !== undefined && typeof enableSecurityCheck !== 'boolean') {
throw new RepopackConfigValidationError('security.enableSecurityCheck must be a boolean');
}
}
}
3 changes: 3 additions & 0 deletions src/config/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ export const defaultConfig: RepopackConfigDefault = {
useDefaultPatterns: true,
customPatterns: [],
},
security: {
enableSecurityCheck: true,
},
};
18 changes: 12 additions & 6 deletions src/core/packager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,18 @@ export const pack = async (
progressCallback('Collecting files...');
const rawFiles = await deps.collectFiles(filePaths, rootDir);

// Perform security check and filter out suspicious files
progressCallback('Running security check...');
const suspiciousFilesResults = await deps.runSecurityCheck(rawFiles, progressCallback);
const safeRawFiles = rawFiles.filter(
(rawFile) => !suspiciousFilesResults.some((result) => result.filePath === rawFile.path),
);
let safeRawFiles = rawFiles;
let suspiciousFilesResults: SuspiciousFileResult[] = [];

if (config.security.enableSecurityCheck) {
// Perform security check and filter out suspicious files
progressCallback('Running security check...');
suspiciousFilesResults = await deps.runSecurityCheck(rawFiles, progressCallback);
safeRawFiles = rawFiles.filter(
(rawFile) => !suspiciousFilesResults.some((result) => result.filePath === rawFile.path),
);
}

const safeFilePaths = safeRawFiles.map((file) => file.path);
logger.trace('Safe files count:', safeRawFiles.length);

Expand Down
3 changes: 3 additions & 0 deletions tests/cli/actions/defaultActionRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ describe('defaultActionRunner', () => {
customPatterns: [],
},
include: [],
security: {
enableSecurityCheck: true,
},
});
vi.mocked(packager.pack).mockResolvedValue({
totalFiles: 10,
Expand Down
31 changes: 31 additions & 0 deletions tests/core/packager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,35 @@ describe('packager', () => {
expect(result.suspiciousFilesResults[0].filePath).toContain(suspiciousFile);
expect(result.totalFiles).toBe(2); // Only safe files should be counted
});

test('pack should skip security check when disabled', async () => {
const mockConfig = createMockConfig({
security: {
enableSecurityCheck: false,
},
});

const result = await pack('root', mockConfig, () => {}, mockDeps);

expect(mockDeps.runSecurityCheck).not.toHaveBeenCalled();
expect(result.suspiciousFilesResults).toEqual([]);
expect(result.totalFiles).toBe(2); // All files should be included
});

test('pack should perform security check when enabled', async () => {
const mockConfig = createMockConfig({
security: {
enableSecurityCheck: true,
},
});

const suspiciousFile = { filePath: 'suspicious.txt', messages: ['Suspicious content detected'] };
vi.mocked(mockDeps.runSecurityCheck).mockResolvedValue([suspiciousFile]);

const result = await pack('root', mockConfig, () => {}, mockDeps);

expect(mockDeps.runSecurityCheck).toHaveBeenCalled();
expect(result.suspiciousFilesResults).toEqual([suspiciousFile]);
expect(result.totalFiles).toBe(2); // All files should still be included in the result
});
});
4 changes: 4 additions & 0 deletions tests/testing/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const createMockConfig = (config: DeepPartial<RepopackConfigMerged> = {})
customPatterns: [...(defaultConfig.ignore.customPatterns || []), ...(config.ignore?.customPatterns || [])],
},
include: [...(defaultConfig.include || []), ...(config.include || [])],
security: {
...defaultConfig.security,
...config.security,
},
};
};

Expand Down

0 comments on commit d6afb28

Please sign in to comment.