fortly-cli 1.0.0

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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/bin/fortly.js +2 -0
  4. package/dist/api/client.d.ts +10 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +39 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +40 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/config.d.ts +2 -0
  13. package/dist/commands/config.d.ts.map +1 -0
  14. package/dist/commands/config.js +43 -0
  15. package/dist/commands/config.js.map +1 -0
  16. package/dist/commands/report.d.ts +2 -0
  17. package/dist/commands/report.d.ts.map +1 -0
  18. package/dist/commands/report.js +25 -0
  19. package/dist/commands/report.js.map +1 -0
  20. package/dist/commands/scan.d.ts +2 -0
  21. package/dist/commands/scan.d.ts.map +1 -0
  22. package/dist/commands/scan.js +127 -0
  23. package/dist/commands/scan.js.map +1 -0
  24. package/dist/config/store.d.ts +9 -0
  25. package/dist/config/store.d.ts.map +1 -0
  26. package/dist/config/store.js +27 -0
  27. package/dist/config/store.js.map +1 -0
  28. package/dist/output/ci.d.ts +6 -0
  29. package/dist/output/ci.d.ts.map +1 -0
  30. package/dist/output/ci.js +39 -0
  31. package/dist/output/ci.js.map +1 -0
  32. package/dist/output/sarif.d.ts +21 -0
  33. package/dist/output/sarif.d.ts.map +1 -0
  34. package/dist/output/sarif.js +54 -0
  35. package/dist/output/sarif.js.map +1 -0
  36. package/dist/output/terminal.d.ts +33 -0
  37. package/dist/output/terminal.d.ts.map +1 -0
  38. package/dist/output/terminal.js +130 -0
  39. package/dist/output/terminal.js.map +1 -0
  40. package/package.json +33 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fortly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # fortly
2
+
3
+ Automated web security scanner with AI-powered vulnerability detection.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/fortly.svg)](https://www.npmjs.com/package/fortly)
6
+ [![license](https://img.shields.io/npm/l/fortly.svg)](https://github.com/fortly/fortly-cli/blob/main/LICENSE)
7
+ [![node](https://img.shields.io/node/v/fortly.svg)](https://nodejs.org/)
8
+
9
+ > Requires Node.js >= 18
10
+
11
+ ---
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # Run without installing
17
+ npx fortly scan https://example.com
18
+
19
+ # Install globally
20
+ npm install -g fortly
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ ```bash
28
+ # Basic scan
29
+ fortly scan https://myapp.com
30
+
31
+ # Scan with options
32
+ fortly scan https://myapp.com --depth 5 --format html --output ./reports
33
+
34
+ # Cloud mode (unlimited scans)
35
+ fortly config set api-key ft_sk_your_key_here
36
+ fortly scan https://myapp.com --cloud
37
+
38
+ # CI/CD mode (exit code 1 if score below threshold)
39
+ fortly scan https://staging.myapp.com --ci --fail-threshold 70
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Commands
45
+
46
+ ### `fortly scan <target>`
47
+
48
+ Run a security scan against a target URL.
49
+
50
+ | Option | Type | Default | Description |
51
+ |---|---|---|---|
52
+ | `--depth <n>` | number | `3` | Maximum crawl depth |
53
+ | `--timeout <ms>` | number | `30000` | Request timeout in milliseconds |
54
+ | `--threads <n>` | number | `10` | Number of concurrent threads |
55
+ | `--format <type>` | string | `terminal` | Output format (`terminal`, `json`, `html`, `both`, `sarif`) |
56
+ | `--output <path>` | string | `./` | Directory for saved reports |
57
+ | `--fail-threshold <n>` | number | `0` | Minimum score to pass (0-100). Exit code 1 if below |
58
+ | `--cloud` | boolean | `false` | Use cloud engine for unlimited scans |
59
+ | `--api-key <key>` | string | &mdash; | API key for cloud mode (overrides config) |
60
+ | `--no-ai` | boolean | `false` | Disable AI-powered vulnerability detection |
61
+ | `--ci` | boolean | `false` | CI-friendly output (no color, no interactive prompts) |
62
+ | `--verbose` | boolean | `false` | Enable verbose logging |
63
+
64
+ ### `fortly report <path>`
65
+
66
+ View a previously saved report file in the terminal.
67
+
68
+ ### `fortly config <action> [key] [value]`
69
+
70
+ Manage CLI configuration.
71
+
72
+ | Action | Description |
73
+ |---|---|
74
+ | `set <key> <value>` | Set a configuration value |
75
+ | `get <key>` | Get a configuration value |
76
+ | `list` | List all configuration values |
77
+ | `reset` | Reset configuration to defaults |
78
+
79
+ ---
80
+
81
+ ## Output Formats
82
+
83
+ | Format | Description |
84
+ |---|---|
85
+ | `terminal` | Colored output with tables (default) |
86
+ | `json` | Machine-readable JSON |
87
+ | `html` | Full HTML report with charts and details |
88
+ | `both` | JSON + HTML |
89
+ | `sarif` | SARIF 2.1.0 for GitHub Code Scanning |
90
+
91
+ ---
92
+
93
+ ## CI/CD Integration
94
+
95
+ ### GitHub Actions
96
+
97
+ ```yaml
98
+ - name: Run Fortly
99
+ run: |
100
+ npx fortly scan ${{ secrets.TARGET_URL }} \
101
+ --ci \
102
+ --fail-threshold 70 \
103
+ --format sarif \
104
+ --output ./results
105
+
106
+ - name: Upload SARIF
107
+ uses: github/codeql-action/upload-sarif@v3
108
+ with:
109
+ sarif_file: ./results
110
+ ```
111
+
112
+ ### GitLab CI
113
+
114
+ ```yaml
115
+ security_scan:
116
+ image: node:20
117
+ script:
118
+ - npx fortly scan $TARGET_URL --ci --fail-threshold 70 --format json --output ./results
119
+ artifacts:
120
+ paths:
121
+ - results/
122
+ when: always
123
+ ```
124
+
125
+ ### Azure Pipelines
126
+
127
+ ```yaml
128
+ - script: |
129
+ npx fortly scan $(TARGET_URL) --ci --fail-threshold 70 --format json --output $(Build.ArtifactStagingDirectory)/fortly
130
+ displayName: "Run Fortly Scan"
131
+
132
+ - publish: $(Build.ArtifactStagingDirectory)/fortly
133
+ artifact: fortly-report
134
+ condition: always()
135
+ ```
136
+
137
+ ### Jenkins
138
+
139
+ ```groovy
140
+ stage('Security Scan') {
141
+ steps {
142
+ sh 'npx fortly scan $TARGET_URL --ci --fail-threshold 70 --format json --output ./fortly-report'
143
+ }
144
+ post {
145
+ always {
146
+ archiveArtifacts artifacts: 'fortly-report/**', allowEmptyArchive: true
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Exit Codes
155
+
156
+ | Code | Meaning |
157
+ |---|---|
158
+ | `0` | Scan passed (score above threshold) |
159
+ | `1` | Scan failed (score below threshold or error) |
160
+
161
+ ---
162
+
163
+ ## Configuration
164
+
165
+ Configuration is stored in `~/.config/fortly/`.
166
+
167
+ | Key | Description |
168
+ |---|---|
169
+ | `api-key` | API key for cloud mode |
170
+ | `default-threshold` | Default fail threshold for scans |
171
+ | `default-format` | Default output format |
172
+
173
+ ```bash
174
+ fortly config set api-key ft_sk_your_key_here
175
+ fortly config set default-threshold 70
176
+ fortly config set default-format json
177
+ fortly config list
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Features
183
+
184
+ - **15 security scanners** covering a wide range of vulnerability classes
185
+ - **AI-powered vulnerability detection** for reduced false positives
186
+ - **OWASP Top 10 + API Top 10** full coverage
187
+ - **IaC scanning** for Terraform, Dockerfile, and Kubernetes manifests
188
+ - **Compliance mapping** to SOC2, ISO 27001, PCI DSS, HIPAA, and NIST frameworks
189
+ - **SARIF output** for native GitHub Code Scanning integration
190
+
191
+ ---
192
+
193
+ ## License
194
+
195
+ [MIT](./LICENSE)
package/bin/fortly.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/cli.js');
@@ -0,0 +1,10 @@
1
+ export declare class CloudClient {
2
+ private http;
3
+ constructor(baseUrl: string, apiKey: string);
4
+ createScan(targetUrl: string): Promise<{
5
+ scanId: string;
6
+ }>;
7
+ getScan(scanId: string): Promise<any>;
8
+ waitForCompletion(scanId: string, timeoutSeconds: number): Promise<any>;
9
+ }
10
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAEA,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAgB;gBAEhB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAQrC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAK1D,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAKrC,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CAU9E"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CloudClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class CloudClient {
9
+ http;
10
+ constructor(baseUrl, apiKey) {
11
+ this.http = axios_1.default.create({
12
+ baseURL: baseUrl,
13
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
14
+ timeout: 30000,
15
+ });
16
+ }
17
+ async createScan(targetUrl) {
18
+ const { data } = await this.http.post("/api/v2/scans", { targetUrl });
19
+ return data.data;
20
+ }
21
+ async getScan(scanId) {
22
+ const { data } = await this.http.get(`/api/v2/scans/${scanId}`);
23
+ return data.data;
24
+ }
25
+ async waitForCompletion(scanId, timeoutSeconds) {
26
+ const deadline = Date.now() + timeoutSeconds * 1000;
27
+ while (Date.now() < deadline) {
28
+ const scan = await this.getScan(scanId);
29
+ if (scan.status === "completed")
30
+ return scan;
31
+ if (scan.status === "failed")
32
+ throw new Error(`Scan failed: ${scan.error || "unknown"}`);
33
+ await new Promise(r => setTimeout(r, 5000));
34
+ }
35
+ throw new Error(`Scan timed out after ${timeoutSeconds}s`);
36
+ }
37
+ }
38
+ exports.CloudClient = CloudClient;
39
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA6C;AAE7C,MAAa,WAAW;IACd,IAAI,CAAgB;IAE5B,YAAY,OAAe,EAAE,MAAc;QACzC,IAAI,CAAC,IAAI,GAAG,eAAK,CAAC,MAAM,CAAC;YACvB,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAClF,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,MAAM,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,MAAc,EAAE,cAAsB;QAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,GAAG,IAAI,CAAC;QACpD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW;gBAAE,OAAO,IAAI,CAAC;YAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,IAAI,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;YACzF,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,cAAc,GAAG,CAAC,CAAC;IAC7D,CAAC;CACF;AA/BD,kCA+BC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const commander_1 = require("commander");
4
+ const scan_1 = require("./commands/scan");
5
+ const report_1 = require("./commands/report");
6
+ const config_1 = require("./commands/config");
7
+ const program = new commander_1.Command();
8
+ program
9
+ .name("fortly")
10
+ .description("Fortly CLI — Automated web security scanner")
11
+ .version("1.0.0");
12
+ program
13
+ .command("scan <target>")
14
+ .description("Scan a target URL for security vulnerabilities")
15
+ .option("-d, --depth <number>", "Maximum crawl depth", "3")
16
+ .option("-t, --timeout <number>", "Request timeout in ms", "10000")
17
+ .option("--threads <number>", "Concurrent requests", "5")
18
+ .option("-f, --format <type>", "Output format: html, json, both, terminal", "terminal")
19
+ .option("-o, --output <dir>", "Output directory for reports", "./fortly-reports")
20
+ .option("--fail-threshold <number>", "Exit with code 1 if score below threshold (for CI)")
21
+ .option("--cloud", "Use Fortly cloud API instead of local scan")
22
+ .option("--api-key <key>", "API key for cloud mode (or set FT_API_KEY env var)")
23
+ .option("--no-ai", "Disable AI-powered scanning")
24
+ .option("--ci", "CI mode: minimal output, JSON to stdout, exit codes")
25
+ .option("-v, --verbose", "Verbose output")
26
+ .action(scan_1.scanCommand);
27
+ program
28
+ .command("report <path>")
29
+ .description("View a previously generated scan report")
30
+ .option("-f, --format <type>", "Output format: terminal, json", "terminal")
31
+ .action(report_1.reportCommand);
32
+ program
33
+ .command("config")
34
+ .description("Manage Fortly CLI configuration")
35
+ .argument("<action>", "Action: set, get, list, reset")
36
+ .argument("[key]", "Config key (e.g., api-key, default-threshold)")
37
+ .argument("[value]", "Config value")
38
+ .action(config_1.configCommand);
39
+ program.parse();
40
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAAA,yCAAoC;AACpC,0CAA8C;AAC9C,8CAAkD;AAClD,8CAAkD;AAElD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,6CAA6C,CAAC;KAC1D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,gDAAgD,CAAC;KAC7D,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,EAAE,GAAG,CAAC;KAC1D,MAAM,CAAC,wBAAwB,EAAE,uBAAuB,EAAE,OAAO,CAAC;KAClE,MAAM,CAAC,oBAAoB,EAAE,qBAAqB,EAAE,GAAG,CAAC;KACxD,MAAM,CAAC,qBAAqB,EAAE,2CAA2C,EAAE,UAAU,CAAC;KACtF,MAAM,CAAC,oBAAoB,EAAE,8BAA8B,EAAE,kBAAkB,CAAC;KAChF,MAAM,CAAC,2BAA2B,EAAE,oDAAoD,CAAC;KACzF,MAAM,CAAC,SAAS,EAAE,4CAA4C,CAAC;KAC/D,MAAM,CAAC,iBAAiB,EAAE,oDAAoD,CAAC;KAC/E,MAAM,CAAC,SAAS,EAAE,6BAA6B,CAAC;KAChD,MAAM,CAAC,MAAM,EAAE,qDAAqD,CAAC;KACrE,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAAC;KACzC,MAAM,CAAC,kBAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,qBAAqB,EAAE,+BAA+B,EAAE,UAAU,CAAC;KAC1E,MAAM,CAAC,sBAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iCAAiC,CAAC;KAC9C,QAAQ,CAAC,UAAU,EAAE,+BAA+B,CAAC;KACrD,QAAQ,CAAC,OAAO,EAAE,+CAA+C,CAAC;KAClE,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;KACnC,MAAM,CAAC,sBAAa,CAAC,CAAC;AAEzB,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function configCommand(action: string, key?: string, value?: string): Promise<void>;
2
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAGA,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,iBA4B/E"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.configCommand = configCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const store_1 = require("../config/store");
9
+ async function configCommand(action, key, value) {
10
+ const store = new store_1.ConfigStore();
11
+ switch (action) {
12
+ case "set":
13
+ if (!key || !value) {
14
+ console.error("Usage: fortly config set <key> <value>");
15
+ process.exit(1);
16
+ }
17
+ store.set(key, value);
18
+ console.log(chalk_1.default.green(`Set ${key}`));
19
+ break;
20
+ case "get":
21
+ if (!key) {
22
+ console.error("Usage: fortly config get <key>");
23
+ process.exit(1);
24
+ }
25
+ const val = store.get(key);
26
+ console.log(val ?? chalk_1.default.gray("(not set)"));
27
+ break;
28
+ case "list":
29
+ const all = store.getAll();
30
+ for (const [k, v] of Object.entries(all)) {
31
+ console.log(`${chalk_1.default.cyan(k)}: ${k.includes("key") ? "****" + String(v).slice(-4) : v}`);
32
+ }
33
+ break;
34
+ case "reset":
35
+ store.reset();
36
+ console.log(chalk_1.default.green("Configuration reset"));
37
+ break;
38
+ default:
39
+ console.error(`Unknown action: ${action}`);
40
+ process.exit(1);
41
+ }
42
+ }
43
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":";;;;;AAGA,sCA4BC;AA/BD,kDAA0B;AAC1B,2CAA8C;AAEvC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,GAAY,EAAE,KAAc;IAC9E,MAAM,KAAK,GAAG,IAAI,mBAAW,EAAE,CAAC;IAEhC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK;YACR,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;gBAAC,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YACjG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC;YACvC,MAAM;QACR,KAAK,KAAK;YACR,IAAI,CAAC,GAAG,EAAE,CAAC;gBAAC,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;gBAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;YAC/E,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,eAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YAC5C,MAAM;QACR,KAAK,MAAM;YACT,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC3B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,GAAG,CAAC,GAAG,eAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3F,CAAC;YACD,MAAM;QACR,KAAK,OAAO;YACV,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAChD,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function reportCommand(path: string, options: any): Promise<void>;
2
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,iBAe7D"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.reportCommand = reportCommand;
7
+ const fs_1 = require("fs");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const terminal_1 = require("../output/terminal");
10
+ async function reportCommand(path, options) {
11
+ if (!(0, fs_1.existsSync)(path)) {
12
+ console.error(chalk_1.default.red(`File not found: ${path}`));
13
+ process.exit(1);
14
+ }
15
+ const content = (0, fs_1.readFileSync)(path, "utf-8");
16
+ const report = JSON.parse(content);
17
+ if (options.format === "json") {
18
+ console.log(JSON.stringify(report, null, 2));
19
+ }
20
+ else {
21
+ const reporter = new terminal_1.TerminalReporter();
22
+ reporter.printResults(report);
23
+ }
24
+ }
25
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":";;;;;AAIA,sCAeC;AAnBD,2BAA8C;AAC9C,kDAA0B;AAC1B,iDAAsD;AAE/C,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,OAAY;IAC5D,IAAI,CAAC,IAAA,eAAU,EAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEnC,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,MAAM,QAAQ,GAAG,IAAI,2BAAgB,EAAE,CAAC;QACxC,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function scanCommand(target: string, options: any): Promise<void>;
2
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B7E"}
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.scanCommand = scanCommand;
7
+ const ora_1 = __importDefault(require("ora"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const terminal_1 = require("../output/terminal");
10
+ const ci_1 = require("../output/ci");
11
+ const client_1 = require("../api/client");
12
+ const store_1 = require("../config/store");
13
+ async function scanCommand(target, options) {
14
+ const config = new store_1.ConfigStore();
15
+ const isCloud = options.cloud || false;
16
+ const isCi = options.ci || false;
17
+ const reporter = isCi ? new ci_1.CiReporter() : new terminal_1.TerminalReporter();
18
+ // Banner (skip in CI)
19
+ if (!isCi) {
20
+ reporter.banner();
21
+ }
22
+ // Validate target URL
23
+ try {
24
+ new URL(target);
25
+ }
26
+ catch {
27
+ console.error(chalk_1.default.red(`Invalid URL: ${target}`));
28
+ process.exit(1);
29
+ }
30
+ if (isCloud) {
31
+ // Cloud mode: use API
32
+ const apiKey = options.apiKey || process.env.FT_API_KEY || config.get("api-key");
33
+ if (!apiKey) {
34
+ console.error(chalk_1.default.red("API key required for cloud mode. Use --api-key or set FT_API_KEY"));
35
+ process.exit(1);
36
+ }
37
+ await runCloudScan(target, apiKey, options, reporter);
38
+ }
39
+ else {
40
+ // Local mode: use embedded engine
41
+ await runLocalScan(target, options, reporter);
42
+ }
43
+ }
44
+ async function runCloudScan(target, apiKey, options, reporter) {
45
+ const client = new client_1.CloudClient(options.apiUrl || "https://api.fortly.io", apiKey);
46
+ const spinner = (0, ora_1.default)("Creating scan...").start();
47
+ try {
48
+ const scan = await client.createScan(target);
49
+ spinner.text = "Scanning target...";
50
+ const result = await client.waitForCompletion(scan.scanId, 300);
51
+ spinner.succeed("Scan complete");
52
+ reporter.printResults(result);
53
+ handleThreshold(result.score, options.failThreshold);
54
+ }
55
+ catch (err) {
56
+ spinner.fail(err.message);
57
+ process.exit(1);
58
+ }
59
+ }
60
+ async function runLocalScan(target, options, reporter) {
61
+ // Dynamic import of the scan engine (from scan-execute lib)
62
+ // In published npm package, this would be bundled
63
+ // For development, we import from the sibling project
64
+ const spinner = (0, ora_1.default)("Initializing scan engine...").start();
65
+ try {
66
+ let runScan;
67
+ try {
68
+ // Dynamic require to avoid TypeScript static analysis on optional dependency
69
+ const engineName = "fortly-scan-engine";
70
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
71
+ const engine = require(engineName);
72
+ runScan = engine.runScan;
73
+ }
74
+ catch {
75
+ spinner.fail("Scan engine not available. Use --cloud mode or install fortly-scan-engine.");
76
+ process.exit(1);
77
+ }
78
+ const scanConfig = {
79
+ target,
80
+ maxDepth: parseInt(options.depth) || 3,
81
+ maxRequests: 500,
82
+ timeout: parseInt(options.timeout) || 10000,
83
+ delay: 100,
84
+ threads: parseInt(options.threads) || 5,
85
+ retryAttempts: 2,
86
+ userAgent: "Fortly-CLI/1.0",
87
+ followRedirects: true,
88
+ excludePaths: ["/logout", "/signout"],
89
+ outputDir: options.output || "./fortly-reports",
90
+ outputFormat: options.format === "terminal" ? "both" : options.format,
91
+ verbose: options.verbose || false,
92
+ aiEnabled: options.ai !== false,
93
+ aiMaxCalls: 80,
94
+ };
95
+ spinner.text = `Scanning ${target}...`;
96
+ const report = await runScan(scanConfig);
97
+ spinner.succeed("Scan complete");
98
+ // Print results
99
+ reporter.printResults({
100
+ score: report.score,
101
+ grade: report.grade,
102
+ summary: report.summary,
103
+ vulnerabilities: report.vulnerabilities,
104
+ target: report.target,
105
+ scanDuration: report.scanDuration,
106
+ });
107
+ // Handle output format
108
+ if (options.format !== "terminal") {
109
+ reporter.printReportPaths(options.output);
110
+ }
111
+ handleThreshold(report.score, options.failThreshold);
112
+ }
113
+ catch (err) {
114
+ spinner.fail(`Scan failed: ${err.message}`);
115
+ process.exit(1);
116
+ }
117
+ }
118
+ function handleThreshold(score, threshold) {
119
+ if (threshold) {
120
+ const t = parseInt(threshold);
121
+ if (score < t) {
122
+ console.error(chalk_1.default.red(`\nScore ${score} is below threshold ${t}. Failing.`));
123
+ process.exit(1);
124
+ }
125
+ }
126
+ }
127
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare class ConfigStore {
2
+ private store;
3
+ constructor();
4
+ get(key: string): string | undefined;
5
+ set(key: string, value: string): void;
6
+ getAll(): Record<string, unknown>;
7
+ reset(): void;
8
+ }
9
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/config/store.ts"],"names":[],"mappings":"AAEA,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAO;;IAMpB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIrC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjC,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ConfigStore = void 0;
7
+ const conf_1 = __importDefault(require("conf"));
8
+ class ConfigStore {
9
+ store;
10
+ constructor() {
11
+ this.store = new conf_1.default({ projectName: "fortly" });
12
+ }
13
+ get(key) {
14
+ return this.store.get(key);
15
+ }
16
+ set(key, value) {
17
+ this.store.set(key, value);
18
+ }
19
+ getAll() {
20
+ return this.store.store;
21
+ }
22
+ reset() {
23
+ this.store.clear();
24
+ }
25
+ }
26
+ exports.ConfigStore = ConfigStore;
27
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/config/store.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAwB;AAExB,MAAa,WAAW;IACd,KAAK,CAAO;IAEpB;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,cAAI,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAuB,CAAC;IACnD,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAa;QAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAtBD,kCAsBC"}
@@ -0,0 +1,6 @@
1
+ export declare class CiReporter {
2
+ banner(): void;
3
+ printResults(result: any): void;
4
+ printReportPaths(outputDir: string): void;
5
+ }
6
+ //# sourceMappingURL=ci.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../src/output/ci.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAU;IACrB,MAAM,IAAI,IAAI;IAId,YAAY,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI;IA6B/B,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG1C"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CiReporter = void 0;
4
+ class CiReporter {
5
+ banner() {
6
+ // No banner in CI mode
7
+ }
8
+ printResults(result) {
9
+ // Single JSON line to stdout for easy parsing
10
+ const output = {
11
+ score: result.score,
12
+ grade: result.grade,
13
+ target: result.target,
14
+ vulnerabilities: result.summary.totalVulnerabilities,
15
+ critical: result.summary.critical,
16
+ high: result.summary.high,
17
+ medium: result.summary.medium,
18
+ low: result.summary.low,
19
+ info: result.summary.info,
20
+ duration: result.scanDuration,
21
+ };
22
+ console.log(JSON.stringify(output));
23
+ // Also output GitHub Actions annotations if running in GH Actions
24
+ if (process.env.GITHUB_ACTIONS) {
25
+ if (result.summary.critical > 0) {
26
+ console.log(`::error::Fortly found ${result.summary.critical} critical vulnerabilities`);
27
+ }
28
+ if (result.summary.high > 0) {
29
+ console.log(`::warning::Fortly found ${result.summary.high} high severity vulnerabilities`);
30
+ }
31
+ console.log(`::notice::Security Score: ${result.score}/100 (${result.grade})`);
32
+ }
33
+ }
34
+ printReportPaths(outputDir) {
35
+ console.log(JSON.stringify({ reportDir: outputDir }));
36
+ }
37
+ }
38
+ exports.CiReporter = CiReporter;
39
+ //# sourceMappingURL=ci.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/output/ci.ts"],"names":[],"mappings":";;;AAAA,MAAa,UAAU;IACrB,MAAM;QACJ,uBAAuB;IACzB,CAAC;IAED,YAAY,CAAC,MAAW;QACtB,8CAA8C;QAC9C,MAAM,MAAM,GAAG;YACb,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,oBAAoB;YACpD,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ;YACjC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;YACzB,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM;YAC7B,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG;YACvB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;YACzB,QAAQ,EAAE,MAAM,CAAC,YAAY;SAC9B,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAEpC,kEAAkE;QAClE,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;YAC/B,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,yBAAyB,MAAM,CAAC,OAAO,CAAC,QAAQ,2BAA2B,CAAC,CAAC;YAC3F,CAAC;YACD,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC5B,OAAO,CAAC,GAAG,CAAC,2BAA2B,MAAM,CAAC,OAAO,CAAC,IAAI,gCAAgC,CAAC,CAAC;YAC9F,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,6BAA6B,MAAM,CAAC,KAAK,SAAS,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,gBAAgB,CAAC,SAAiB;QAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;CACF;AArCD,gCAqCC"}
@@ -0,0 +1,21 @@
1
+ interface SarifReport {
2
+ $schema: string;
3
+ version: string;
4
+ runs: Array<{
5
+ tool: {
6
+ driver: {
7
+ name: string;
8
+ version: string;
9
+ informationUri: string;
10
+ rules: any[];
11
+ };
12
+ };
13
+ results: any[];
14
+ }>;
15
+ }
16
+ export declare class SarifExporter {
17
+ static generate(result: any): SarifReport;
18
+ static write(result: any, outputPath: string): void;
19
+ }
20
+ export {};
21
+ //# sourceMappingURL=sarif.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../src/output/sarif.ts"],"names":[],"mappings":"AAAA,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,KAAK,CAAC;QACV,IAAI,EAAE;YAAE,MAAM,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,OAAO,EAAE,MAAM,CAAC;gBAAC,cAAc,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,GAAG,EAAE,CAAA;aAAE,CAAA;SAAE,CAAC;QAC1F,OAAO,EAAE,GAAG,EAAE,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,qBAAa,aAAa;IACxB,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,WAAW;IA6CzC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;CAMpD"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SarifExporter = void 0;
4
+ class SarifExporter {
5
+ static generate(result) {
6
+ const rules = (result.vulnerabilities || []).map((v, i) => ({
7
+ id: `VH-${v.type}`,
8
+ name: v.type,
9
+ shortDescription: { text: v.title },
10
+ fullDescription: { text: v.description || v.title },
11
+ defaultConfiguration: {
12
+ level: v.severity === "critical" || v.severity === "high" ? "error" :
13
+ v.severity === "medium" ? "warning" : "note",
14
+ },
15
+ helpUri: `https://docs.fortly.io/vulns/${v.type}`,
16
+ }));
17
+ // Deduplicate rules by id
18
+ const uniqueRules = [...new Map(rules.map((r) => [r.id, r])).values()];
19
+ const results = (result.vulnerabilities || []).map((v) => ({
20
+ ruleId: `VH-${v.type}`,
21
+ level: v.severity === "critical" || v.severity === "high" ? "error" :
22
+ v.severity === "medium" ? "warning" : "note",
23
+ message: { text: `${v.title}: ${v.description || ""}`.trim() },
24
+ locations: [{
25
+ physicalLocation: {
26
+ artifactLocation: { uri: v.url || result.target },
27
+ },
28
+ }],
29
+ }));
30
+ return {
31
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
32
+ version: "2.1.0",
33
+ runs: [{
34
+ tool: {
35
+ driver: {
36
+ name: "Fortly",
37
+ version: "1.0.0",
38
+ informationUri: "https://fortly.io",
39
+ rules: uniqueRules,
40
+ },
41
+ },
42
+ results,
43
+ }],
44
+ };
45
+ }
46
+ static write(result, outputPath) {
47
+ const { writeFileSync, mkdirSync } = require("fs");
48
+ const { dirname } = require("path");
49
+ mkdirSync(dirname(outputPath), { recursive: true });
50
+ writeFileSync(outputPath, JSON.stringify(SarifExporter.generate(result), null, 2));
51
+ }
52
+ }
53
+ exports.SarifExporter = SarifExporter;
54
+ //# sourceMappingURL=sarif.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/output/sarif.ts"],"names":[],"mappings":";;;AASA,MAAa,aAAa;IACxB,MAAM,CAAC,QAAQ,CAAC,MAAW;QACzB,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;YACvE,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE;YAClB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,gBAAgB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE;YACnC,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,KAAK,EAAE;YACnD,oBAAoB,EAAE;gBACpB,KAAK,EAAE,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;oBAC9D,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;aACpD;YACD,OAAO,EAAE,gCAAgC,CAAC,CAAC,IAAI,EAAE;SAClD,CAAC,CAAC,CAAC;QAEJ,0BAA0B;QAC1B,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAE5E,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;YAC9D,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE;YACtB,KAAK,EAAE,CAAC,CAAC,QAAQ,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAC9D,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;YACnD,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;YAC9D,SAAS,EAAE,CAAC;oBACV,gBAAgB,EAAE;wBAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE;qBAClD;iBACF,CAAC;SACH,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,OAAO,EAAE,gGAAgG;YACzG,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,CAAC;oBACL,IAAI,EAAE;wBACJ,MAAM,EAAE;4BACN,IAAI,EAAE,QAAQ;4BACd,OAAO,EAAE,OAAO;4BAChB,cAAc,EAAE,mBAAmB;4BACnC,KAAK,EAAE,WAAW;yBACnB;qBACF;oBACD,OAAO;iBACR,CAAC;SACH,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAW,EAAE,UAAkB;QAC1C,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACpC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC;CACF;AApDD,sCAoDC"}
@@ -0,0 +1,33 @@
1
+ interface ScanResultData {
2
+ score: number;
3
+ grade: string;
4
+ target: string;
5
+ scanDuration?: number;
6
+ summary: {
7
+ totalVulnerabilities: number;
8
+ critical: number;
9
+ high: number;
10
+ medium: number;
11
+ low: number;
12
+ info: number;
13
+ };
14
+ vulnerabilities: Array<{
15
+ severity: string;
16
+ title: string;
17
+ type: string;
18
+ url: string;
19
+ cwe?: string;
20
+ }>;
21
+ }
22
+ export declare class TerminalReporter {
23
+ banner(): void;
24
+ printResults(result: ScanResultData): void;
25
+ printReportPaths(outputDir: string): void;
26
+ private printScoreBar;
27
+ private getScoreColor;
28
+ private severityBadge;
29
+ private colorCount;
30
+ private formatDuration;
31
+ }
32
+ export {};
33
+ //# sourceMappingURL=terminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/output/terminal.ts"],"names":[],"mappings":"AAGA,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE;QACP,oBAAoB,EAAE,MAAM,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,eAAe,EAAE,KAAK,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ;AAED,qBAAa,gBAAgB;IAC3B,MAAM,IAAI,IAAI;IAYd,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IA6E1C,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMzC,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,cAAc;CAKvB"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TerminalReporter = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const cli_table3_1 = __importDefault(require("cli-table3"));
9
+ class TerminalReporter {
10
+ banner() {
11
+ console.log("");
12
+ console.log(chalk_1.default.bold.red(" ██╗ ██╗██╗ ██╗██╗ ███╗ ██╗"));
13
+ console.log(chalk_1.default.bold.red(" ██║ ██║██║ ██║██║ ████╗ ██║"));
14
+ console.log(chalk_1.default.bold.red(" ██║ ██║██║ ██║██║ ██╔██╗ ██║"));
15
+ console.log(chalk_1.default.bold.red(" ╚██╗ ██╔╝██║ ██║██║ ██║╚██╗██║"));
16
+ console.log(chalk_1.default.bold.red(" ╚████╔╝ ╚██████╔╝███████╗██║ ╚████║"));
17
+ console.log(chalk_1.default.bold.red(" ╚═══╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝"));
18
+ console.log(chalk_1.default.gray(" Fortly CLI — Automated Web Security Scanner"));
19
+ console.log(chalk_1.default.gray(" Use only on applications you have authorization to test.\n"));
20
+ }
21
+ printResults(result) {
22
+ console.log("");
23
+ // Score section
24
+ const scoreColor = this.getScoreColor(result.score);
25
+ console.log(chalk_1.default.bold(" Target: ") + chalk_1.default.cyan(result.target));
26
+ if (result.scanDuration) {
27
+ console.log(chalk_1.default.bold(" Duration: ") + chalk_1.default.gray(this.formatDuration(result.scanDuration)));
28
+ }
29
+ console.log("");
30
+ console.log(chalk_1.default.bold(" Security Score: ") + scoreColor(` ${result.score}/100 `) + chalk_1.default.bold(` Grade: ${result.grade}`));
31
+ console.log("");
32
+ // Progress bar
33
+ this.printScoreBar(result.score);
34
+ console.log("");
35
+ // Summary table
36
+ const summaryTable = new cli_table3_1.default({
37
+ head: [
38
+ chalk_1.default.white("Severity"),
39
+ chalk_1.default.white("Count"),
40
+ ],
41
+ colWidths: [20, 10],
42
+ style: { head: [], border: ["gray"] },
43
+ });
44
+ summaryTable.push([chalk_1.default.red("Critical"), this.colorCount(result.summary.critical, "critical")], [chalk_1.default.hex("#ff6b35")("High"), this.colorCount(result.summary.high, "high")], [chalk_1.default.yellow("Medium"), this.colorCount(result.summary.medium, "medium")], [chalk_1.default.green("Low"), this.colorCount(result.summary.low, "low")], [chalk_1.default.gray("Info"), String(result.summary.info)], [chalk_1.default.bold("Total"), chalk_1.default.bold(String(result.summary.totalVulnerabilities))]);
45
+ console.log(summaryTable.toString());
46
+ console.log("");
47
+ // Top vulnerabilities (max 10)
48
+ if (result.vulnerabilities.length > 0) {
49
+ console.log(chalk_1.default.bold(" Top Findings:"));
50
+ console.log("");
51
+ const vulnTable = new cli_table3_1.default({
52
+ head: [
53
+ chalk_1.default.white("Sev"),
54
+ chalk_1.default.white("Title"),
55
+ chalk_1.default.white("Type"),
56
+ chalk_1.default.white("URL"),
57
+ ],
58
+ colWidths: [12, 30, 22, 40],
59
+ style: { head: [], border: ["gray"] },
60
+ wordWrap: true,
61
+ });
62
+ for (const vuln of result.vulnerabilities.slice(0, 10)) {
63
+ vulnTable.push([
64
+ this.severityBadge(vuln.severity),
65
+ vuln.title,
66
+ vuln.type,
67
+ vuln.url.length > 38 ? vuln.url.substring(0, 35) + "..." : vuln.url,
68
+ ]);
69
+ }
70
+ console.log(vulnTable.toString());
71
+ if (result.vulnerabilities.length > 10) {
72
+ console.log(chalk_1.default.gray(` ... and ${result.vulnerabilities.length - 10} more vulnerabilities`));
73
+ }
74
+ }
75
+ else {
76
+ console.log(chalk_1.default.green(" No vulnerabilities found. The target appears well-secured."));
77
+ }
78
+ console.log("");
79
+ }
80
+ printReportPaths(outputDir) {
81
+ console.log(chalk_1.default.bold(" Reports saved to:"));
82
+ console.log(chalk_1.default.cyan(` ${outputDir}/`));
83
+ console.log("");
84
+ }
85
+ printScoreBar(score) {
86
+ const width = 40;
87
+ const filled = Math.round((score / 100) * width);
88
+ const empty = width - filled;
89
+ const color = this.getScoreColor(score);
90
+ const bar = color("█".repeat(filled)) + chalk_1.default.gray("░".repeat(empty));
91
+ console.log(` ${bar} ${score}%`);
92
+ }
93
+ getScoreColor(score) {
94
+ if (score >= 90)
95
+ return chalk_1.default.bgGreen.black;
96
+ if (score >= 70)
97
+ return chalk_1.default.bgYellow.black;
98
+ if (score >= 50)
99
+ return chalk_1.default.bgHex("#ff6b35").black;
100
+ return chalk_1.default.bgRed.white;
101
+ }
102
+ severityBadge(severity) {
103
+ switch (severity.toLowerCase()) {
104
+ case "critical": return chalk_1.default.bgRed.white.bold(" CRIT ");
105
+ case "high": return chalk_1.default.bgHex("#ff6b35").white.bold(" HIGH ");
106
+ case "medium": return chalk_1.default.bgYellow.black(" MED ");
107
+ case "low": return chalk_1.default.bgGreen.black(" LOW ");
108
+ default: return chalk_1.default.bgGray.white(" INFO ");
109
+ }
110
+ }
111
+ colorCount(count, severity) {
112
+ if (count === 0)
113
+ return chalk_1.default.green("0");
114
+ switch (severity) {
115
+ case "critical": return chalk_1.default.red.bold(String(count));
116
+ case "high": return chalk_1.default.hex("#ff6b35").bold(String(count));
117
+ case "medium": return chalk_1.default.yellow(String(count));
118
+ default: return String(count);
119
+ }
120
+ }
121
+ formatDuration(ms) {
122
+ if (ms < 1000)
123
+ return `${ms}ms`;
124
+ if (ms < 60000)
125
+ return `${(ms / 1000).toFixed(1)}s`;
126
+ return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
127
+ }
128
+ }
129
+ exports.TerminalReporter = TerminalReporter;
130
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/output/terminal.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "fortly-cli",
3
+ "version": "1.0.0",
4
+ "description": "Fortly CLI — Automated web security scanner with AI-powered vulnerability detection",
5
+ "bin": {
6
+ "fortly": "./bin/fortly.js"
7
+ },
8
+ "main": "dist/cli.js",
9
+ "files": ["bin/", "dist/", "README.md", "LICENSE"],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "jest --coverage",
13
+ "start": "ts-node src/cli.ts"
14
+ },
15
+ "keywords": ["security", "scanner", "vulnerability", "dast", "owasp", "pentest", "cli"],
16
+ "dependencies": {
17
+ "commander": "^12.0.0",
18
+ "ora": "^5.4.1",
19
+ "chalk": "^4.1.2",
20
+ "cli-table3": "^0.6.0",
21
+ "conf": "^10.2.0",
22
+ "axios": "^1.6.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^20.0.0",
26
+ "@types/jest": "^29.0.0",
27
+ "jest": "^29.0.0",
28
+ "ts-jest": "^29.0.0",
29
+ "ts-node": "^10.9.2",
30
+ "typescript": "^5.0.0"
31
+ },
32
+ "engines": { "node": ">=18.0.0" }
33
+ }