@capgo/capgo-sec 1.0.4

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/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@capgo/capgo-sec",
3
+ "version": "1.0.4",
4
+ "description": "Security scanner for Capacitor apps - detect vulnerabilities, hardcoded secrets, and security misconfigurations",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "capsec": "./dist/cli/index.js"
9
+ },
10
+ "type": "module",
11
+ "scripts": {
12
+ "build": "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node",
13
+ "dev": "bun run src/cli/index.ts",
14
+ "test": "bun test",
15
+ "lint": "eslint src --ext .ts",
16
+ "prepublishOnly": "bun run build"
17
+ },
18
+ "keywords": [
19
+ "capacitor",
20
+ "security",
21
+ "scanner",
22
+ "vulnerability",
23
+ "static-analysis",
24
+ "ionic",
25
+ "mobile",
26
+ "android",
27
+ "ios"
28
+ ],
29
+ "author": "Capgo Team",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/Cap-go/capgo-sec"
34
+ },
35
+ "homepage": "https://capgo.app/security-scanner/",
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "dependencies": {
40
+ "@babel/parser": "^7.24.0",
41
+ "@babel/traverse": "^7.24.0",
42
+ "@babel/types": "^7.24.0",
43
+ "chalk": "^5.3.0",
44
+ "commander": "^12.0.0",
45
+ "fast-glob": "^3.3.2",
46
+ "ora": "^8.0.1"
47
+ },
48
+ "devDependencies": {
49
+ "@types/babel__traverse": "^7.20.5",
50
+ "@types/bun": "latest",
51
+ "typescript": "^5.4.0"
52
+ }
53
+ }
package/renovate.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:base"
5
+ ],
6
+ "dependencyDashboard": false,
7
+ "automerge": true,
8
+ "automergeType": "pr",
9
+ "packageRules": [
10
+ {
11
+ "matchUpdateTypes": [
12
+ "minor",
13
+ "patch"
14
+ ],
15
+ "automerge": true
16
+ },
17
+ {
18
+ "matchDepTypes": [
19
+ "devDependencies"
20
+ ],
21
+ "automerge": true
22
+ },
23
+ {
24
+ "matchManagers": [
25
+ "swift-pm"
26
+ ],
27
+ "matchPackagePatterns": [
28
+ "^https://github.com/ionic-team/capacitor-swift-pm\\.git$",
29
+ "^ionic-team/capacitor-swift-pm$",
30
+ "^capacitor-swift-pm$"
31
+ ],
32
+ "allowedVersions": "8.0.0",
33
+ "enabled": false
34
+ }
35
+ ],
36
+ "schedule": [
37
+ "before 5am on monday"
38
+ ]
39
+ }
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import ora from 'ora';
5
+ import chalk from 'chalk';
6
+ import { SecurityScanner } from '../scanners/engine.js';
7
+ import { formatCliReport, formatJsonReport, formatHtmlReport } from '../utils/reporter.js';
8
+ import type { ScanOptions, RuleCategory, Severity } from '../types.js';
9
+ import { ruleCount } from '../rules/index.js';
10
+
11
+ const program = new Command();
12
+
13
+ const VERSION = '1.0.0';
14
+
15
+ const BANNER = `
16
+ ${chalk.hex('#7c3aed').bold('╔═══════════════════════════════════════════════════════════╗')}
17
+ ${chalk.hex('#7c3aed').bold('║')} ${chalk.white.bold('🔒 CAPSEC')} - Capacitor Security Scanner ${chalk.hex('#7c3aed').bold('║')}
18
+ ${chalk.hex('#7c3aed').bold('║')} ${chalk.gray(`v${VERSION} • ${ruleCount} security rules • capacitor-sec.dev`)} ${chalk.hex('#7c3aed').bold('║')}
19
+ ${chalk.hex('#7c3aed').bold('╚═══════════════════════════════════════════════════════════╝')}
20
+ `;
21
+
22
+ program
23
+ .name('capsec')
24
+ .version(VERSION)
25
+ .description('Security scanner for Capacitor apps - detect vulnerabilities, hardcoded secrets, and security misconfigurations')
26
+ .addHelpText('before', BANNER);
27
+
28
+ program
29
+ .command('scan')
30
+ .description('Scan a Capacitor project for security issues')
31
+ .argument('[path]', 'Path to the Capacitor project', '.')
32
+ .option('-o, --output <format>', 'Output format: cli, json, html', 'cli')
33
+ .option('-f, --output-file <file>', 'Write output to a file')
34
+ .option('-s, --severity <level>', 'Minimum severity to report: critical, high, medium, low, info', 'low')
35
+ .option('-c, --categories <categories>', 'Categories to scan (comma-separated)', '')
36
+ .option('-e, --exclude <patterns>', 'Additional patterns to exclude (comma-separated)', '')
37
+ .option('--ci', 'CI mode: exit with code 1 if high or critical issues found', false)
38
+ .option('-v, --verbose', 'Verbose output', false)
39
+ .action(async (path: string, options: any) => {
40
+ console.log(BANNER);
41
+
42
+ const spinner = ora('Initializing security scan...').start();
43
+
44
+ try {
45
+ const scanOptions: ScanOptions = {
46
+ path: path.startsWith('/') ? path : `${process.cwd()}/${path}`,
47
+ output: options.output,
48
+ outputFile: options.outputFile,
49
+ severity: options.severity as Severity,
50
+ categories: options.categories ? options.categories.split(',').map((c: string) => c.trim()) as RuleCategory[] : undefined,
51
+ exclude: options.exclude ? options.exclude.split(',').map((e: string) => e.trim()) : undefined,
52
+ ci: options.ci,
53
+ verbose: options.verbose
54
+ };
55
+
56
+ spinner.text = `Scanning ${scanOptions.path}...`;
57
+
58
+ const scanner = new SecurityScanner(scanOptions);
59
+ const result = await scanner.scan();
60
+
61
+ spinner.succeed(`Scanned ${result.filesScanned} files in ${result.duration}ms`);
62
+
63
+ // Format output
64
+ let output: string;
65
+ switch (options.output) {
66
+ case 'json':
67
+ output = formatJsonReport(result);
68
+ break;
69
+ case 'html':
70
+ output = formatHtmlReport(result);
71
+ break;
72
+ default:
73
+ output = formatCliReport(result);
74
+ }
75
+
76
+ // Write to file or stdout
77
+ if (options.outputFile) {
78
+ await Bun.write(options.outputFile, output);
79
+ console.log(chalk.green(`\n✓ Report saved to ${options.outputFile}`));
80
+ } else {
81
+ console.log(output);
82
+ }
83
+
84
+ // CI mode exit codes
85
+ if (options.ci) {
86
+ if (result.summary.critical > 0 || result.summary.high > 0) {
87
+ console.log(chalk.red('\n✗ CI check failed: High or critical severity issues found'));
88
+ process.exit(1);
89
+ } else {
90
+ console.log(chalk.green('\n✓ CI check passed'));
91
+ process.exit(0);
92
+ }
93
+ }
94
+
95
+ } catch (error) {
96
+ spinner.fail('Scan failed');
97
+ console.error(chalk.red(`Error: ${(error as Error).message}`));
98
+ if (options.verbose) {
99
+ console.error(error);
100
+ }
101
+ process.exit(1);
102
+ }
103
+ });
104
+
105
+ program
106
+ .command('rules')
107
+ .description('List all security rules')
108
+ .option('-c, --category <category>', 'Filter by category')
109
+ .option('-s, --severity <severity>', 'Filter by severity')
110
+ .action((options: any) => {
111
+ console.log(BANNER);
112
+
113
+ // Import rules dynamically
114
+ import('../rules/index.js').then(({ allRules }) => {
115
+ let rules = allRules;
116
+
117
+ if (options.category) {
118
+ rules = rules.filter(r => r.category === options.category);
119
+ }
120
+
121
+ if (options.severity) {
122
+ rules = rules.filter(r => r.severity === options.severity);
123
+ }
124
+
125
+ console.log(chalk.bold(`\n${rules.length} Security Rules\n`));
126
+ console.log('─'.repeat(60));
127
+
128
+ const byCategory = new Map<string, typeof rules>();
129
+ for (const rule of rules) {
130
+ if (!byCategory.has(rule.category)) {
131
+ byCategory.set(rule.category, []);
132
+ }
133
+ byCategory.get(rule.category)!.push(rule);
134
+ }
135
+
136
+ for (const [category, categoryRules] of byCategory) {
137
+ console.log(chalk.bold.cyan(`\n${category.toUpperCase()} (${categoryRules.length})`));
138
+ for (const rule of categoryRules) {
139
+ const severityColor =
140
+ rule.severity === 'critical' ? chalk.bgRed.white :
141
+ rule.severity === 'high' ? chalk.red :
142
+ rule.severity === 'medium' ? chalk.yellow :
143
+ rule.severity === 'low' ? chalk.cyan :
144
+ chalk.gray;
145
+
146
+ console.log(` ${chalk.gray(rule.id)} ${severityColor(`[${rule.severity}]`)} ${rule.name}`);
147
+ console.log(chalk.gray(` ${rule.description}`));
148
+ }
149
+ }
150
+
151
+ console.log('\n');
152
+ });
153
+ });
154
+
155
+ program
156
+ .command('init')
157
+ .description('Initialize capsec configuration file')
158
+ .action(async () => {
159
+ console.log(BANNER);
160
+
161
+ const configContent = `{
162
+ "$schema": "https://capacitor-sec.dev/schema/capsec.json",
163
+ "exclude": [
164
+ "**/node_modules/**",
165
+ "**/dist/**",
166
+ "**/build/**"
167
+ ],
168
+ "severity": "low",
169
+ "categories": [],
170
+ "rules": {}
171
+ }`;
172
+
173
+ const configPath = `${process.cwd()}/capsec.config.json`;
174
+ await Bun.write(configPath, configContent);
175
+ console.log(chalk.green(`✓ Created ${configPath}`));
176
+ });
177
+
178
+ // Default command is scan
179
+ if (process.argv.length === 2) {
180
+ process.argv.push('scan');
181
+ }
182
+
183
+ program.parse();
package/src/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ // Capsec - Capacitor Security Scanner
2
+ // https://capacitor-sec.dev
3
+
4
+ export { SecurityScanner } from './scanners/engine.js';
5
+ export { formatCliReport, formatJsonReport, formatHtmlReport } from './utils/reporter.js';
6
+ export { allRules, rulesByCategory, ruleCount } from './rules/index.js';
7
+
8
+ export type {
9
+ Rule,
10
+ Finding,
11
+ ScanResult,
12
+ ScanOptions,
13
+ Severity,
14
+ RuleCategory,
15
+ CapacitorConfig
16
+ } from './types.js';
17
+
18
+ // Re-export individual rule sets for custom configurations
19
+ export {
20
+ secretsRules,
21
+ storageRules,
22
+ networkRules,
23
+ capacitorRules,
24
+ androidRules,
25
+ iosRules,
26
+ authenticationRules,
27
+ webviewRules,
28
+ loggingRules,
29
+ debugRules,
30
+ cryptographyRules
31
+ } from './rules/index.js';