@activemind/scd 1.4.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 (79) hide show
  1. package/LICENSE.md +35 -0
  2. package/README.md +417 -0
  3. package/bin/scd.js +140 -0
  4. package/lib/audit-report.js +93 -0
  5. package/lib/audit-sync.js +172 -0
  6. package/lib/audit.js +356 -0
  7. package/lib/cli-helpers.js +108 -0
  8. package/lib/commands/accept.js +28 -0
  9. package/lib/commands/audit.js +17 -0
  10. package/lib/commands/configure.js +200 -0
  11. package/lib/commands/doctor.js +14 -0
  12. package/lib/commands/exceptions.js +19 -0
  13. package/lib/commands/export-findings.js +46 -0
  14. package/lib/commands/findings.js +306 -0
  15. package/lib/commands/ignore.js +28 -0
  16. package/lib/commands/init.js +16 -0
  17. package/lib/commands/insights.js +24 -0
  18. package/lib/commands/install.js +15 -0
  19. package/lib/commands/list.js +109 -0
  20. package/lib/commands/remove.js +16 -0
  21. package/lib/commands/repo.js +862 -0
  22. package/lib/commands/report.js +234 -0
  23. package/lib/commands/resolve.js +25 -0
  24. package/lib/commands/rules.js +185 -0
  25. package/lib/commands/scan.js +519 -0
  26. package/lib/commands/scope.js +341 -0
  27. package/lib/commands/sync.js +40 -0
  28. package/lib/commands/uninstall.js +15 -0
  29. package/lib/commands/version.js +33 -0
  30. package/lib/comment-map.js +388 -0
  31. package/lib/config.js +325 -0
  32. package/lib/context-modifiers.js +211 -0
  33. package/lib/deep-analyzer.js +225 -0
  34. package/lib/doctor.js +236 -0
  35. package/lib/exception-manager.js +675 -0
  36. package/lib/export-findings.js +376 -0
  37. package/lib/file-context.js +380 -0
  38. package/lib/file-filter.js +204 -0
  39. package/lib/file-manifest.js +145 -0
  40. package/lib/git-utils.js +102 -0
  41. package/lib/global-config.js +239 -0
  42. package/lib/hooks-manager.js +130 -0
  43. package/lib/init-repo.js +147 -0
  44. package/lib/insights-analyzer.js +416 -0
  45. package/lib/insights-output.js +160 -0
  46. package/lib/installer.js +128 -0
  47. package/lib/output-constants.js +32 -0
  48. package/lib/output-terminal.js +407 -0
  49. package/lib/push-queue.js +322 -0
  50. package/lib/remove-repo.js +108 -0
  51. package/lib/repo-context.js +187 -0
  52. package/lib/report-html.js +1154 -0
  53. package/lib/report-index.js +157 -0
  54. package/lib/report-json.js +136 -0
  55. package/lib/report-markdown.js +250 -0
  56. package/lib/resolve-manager.js +148 -0
  57. package/lib/rule-registry.js +205 -0
  58. package/lib/scan-cache.js +171 -0
  59. package/lib/scan-context.js +312 -0
  60. package/lib/scan-schema.js +67 -0
  61. package/lib/scanner-full.js +681 -0
  62. package/lib/scanner-manual.js +348 -0
  63. package/lib/scanner-secrets.js +83 -0
  64. package/lib/scope.js +331 -0
  65. package/lib/store-verify.js +395 -0
  66. package/lib/store.js +310 -0
  67. package/lib/taint-register.js +196 -0
  68. package/lib/version-check.js +46 -0
  69. package/package.json +37 -0
  70. package/rules/rule-loader.js +324 -0
  71. package/rules/rules-aspx-cs.json +399 -0
  72. package/rules/rules-aspx.json +222 -0
  73. package/rules/rules-infra-leakage.json +434 -0
  74. package/rules/rules-js.json +664 -0
  75. package/rules/rules-php.json +521 -0
  76. package/rules/rules-python.json +466 -0
  77. package/rules/rules-secrets.json +99 -0
  78. package/rules/rules-sensitive-files.json +475 -0
  79. package/rules/rules-ts.json +76 -0
package/LICENSE.md ADDED
@@ -0,0 +1,35 @@
1
+ GNU AFFERO GENERAL PUBLIC LICENSE
2
+ Version 3, 19 November 2007
3
+
4
+ Copyright (C) 2026 Activemind Solutions AB
5
+ Contact: info@activemind.se
6
+ https://activemind.se
7
+
8
+ This program is free software: you can redistribute it and/or modify
9
+ it under the terms of the GNU Affero General Public License as published
10
+ by the Free Software Foundation, either version 3 of the License, or
11
+ (at your option) any later version.
12
+
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU Affero General Public License for more details.
17
+
18
+ You should have received a copy of the GNU Affero General Public License
19
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
20
+
21
+ ---
22
+
23
+ COMMERCIAL LICENSE
24
+
25
+ If you wish to use Secure Code by Design in a proprietary product or
26
+ service, or distribute it as part of a commercial offering without
27
+ complying with the terms of the AGPL-3.0, a commercial license is
28
+ available from Activemind Solutions AB.
29
+
30
+ Contact: info@activemind.se
31
+
32
+ ---
33
+
34
+ The full text of the GNU Affero General Public License v3 is available at:
35
+ https://www.gnu.org/licenses/agpl-3.0.txt
package/README.md ADDED
@@ -0,0 +1,417 @@
1
+ # Secure Code by Design
2
+
3
+ > Automated security scanning for development teams using AI coding tools.
4
+
5
+ Secure Code by Design (`scd`) is a CLI tool that catches security vulnerabilities before they reach production — running quietly in the background via git hooks and on-demand scans. Built for SMB companies using traditional coding and AI coding tools (Claude Code, GitHub Copilot, Cursor) which generates code faster than their security awareness can keep up with.
6
+
7
+ **Not a replacement for penetration testing.** scd helps you find and fix common vulnerability patterns before they reach production, so that professional security assessments can focus on harder, context-specific problems. It does not replace a penetration test, threat model, or security audit.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **189 security rules** across JavaScript, TypeScript, Python, PHP, ASP.NET, and more
14
+ - **Taint analysis** — tracks user-controlled variables from HTTP input to dangerous sinks
15
+ - **Pre-scan file classification** — files are classified into source, test, and excluded contexts before any rule runs; test files and vendor code are routed separately
16
+ - **Git hooks** – secrets scanning on pre-commit, full OWASP scan on pre-push
17
+ - **Zero repo footprint** – no files written or modified to your repository
18
+ - **Compact terminal output** – summary + top issues + most affected files (use `--verbose` for full detail)
19
+ - **HTML, Markdown and JSON reports** with fix guidance for each finding
20
+ - **Deep analysis** – optional AI-powered analysis via scd-server; requires the Deep Analysis Pack (Premium)
21
+ - **Per-scan storage** – every scan saved with a unique random ID (`s-a3f9b2c1`), never overwritten; regenerate reports from any historical scan
22
+ - **Finding IDs** – every finding gets a stable ID (`f-a1b2c3d4e5`) shown in scan output, reports and export — use directly with `scd accept` and `scd ignore`
23
+ - **Exception management** – reviewed exceptions tracked in config, never as code comments
24
+ - **Exception sync** – pull team-lead approvals from scd-server, sync rejected back with reason
25
+ - **Audit trail** – append-only scan history per repository
26
+ - **`.gitignore` respected** – files git ignores are excluded from scans by default; use `--include-ignored` to override
27
+ - **Scan scope management** – explicitly exclude files, directories, or rules with documented reasons via `scope.yml`; every exclusion is tracked in scan output and audit log
28
+ - **Pipeline-friendly** – works as a subprocess or in CI/CD without a TTY; use `--log-to` to control logging behaviour in automated contexts
29
+
30
+ ## Team & Premium
31
+
32
+ scd-server extends the CLI with team collaboration features. When you're ready to move beyond local scanning:
33
+
34
+ - **Team dashboard** — aggregated findings, trend analysis, and knowledge gap tracking across your whole team
35
+ - **Exception approval flow** — developers request exceptions, team leads approve or reject with a reason
36
+ - **CRA Compliance Report** — ready-made documentation for EU Cyber Resilience Act conformity assessments
37
+ - **Findings history** — every scan from every developer in one place, searchable and filterable
38
+ - **Deep Analysis Pack** — AI-powered analysis of CRITICAL and HIGH findings; confirms real vulnerabilities, identifies false positives, and suggests concrete fixes. Your code never leaves your infrastructure.
39
+
40
+ scd-server runs in your own infrastructure. No code, no findings, and no scan data ever leaves your network.
41
+
42
+ See [securecodebydesign.com](https://securecodebydesign.com) for plans and pricing.
43
+
44
+ ---
45
+
46
+ ## Requirements
47
+
48
+ - Node.js 22 or later
49
+ - Git (required for hook installation)
50
+ - npm (included with Node.js)
51
+
52
+ **macOS / Linux:** No additional requirements.
53
+
54
+ **Windows:** Windows 10 (build 1803) or later required. Git for Windows must be installed (not WSL). Windows Terminal or PowerShell recommended — `cmd.exe` has limited ANSI colour support.
55
+
56
+ > On Windows, the store directory is `%USERPROFILE%\\.scd\\` (e.g. `C:\\Users\\YourName\\.scd\\`). All `~/.scd` references in this documentation refer to this path on Windows.
57
+
58
+ ---
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ npm install -g @activemind/scd
64
+ scd --version
65
+ ```
66
+
67
+ See [INSTALL.md](INSTALL.md) for platform-specific Node.js setup, advanced options, and
68
+ [installation troubleshooting](INSTALL.md#troubleshooting).
69
+
70
+ ---
71
+
72
+ ## Quick start
73
+
74
+ ```bash
75
+ # Register a project and install git hooks
76
+ cd /path/to/your/project
77
+ scd init
78
+
79
+ # Run a full security scan
80
+ scd scan
81
+
82
+ # Run with verbose output (full file-grouped + rule-grouped detail)
83
+ scd scan --verbose
84
+
85
+ # Generate an HTML report from the last scan
86
+ scd report
87
+
88
+ # Open the report in your browser
89
+ scd report open # macOS / Windows
90
+ scd report serve # Linux / Firefox (starts local HTTP server)
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Commands
96
+
97
+ ### Scanning
98
+
99
+ | Command | Description |
100
+ |---|---|
101
+ | `scd scan [target]` | Run a full security scan — vendor and `.gitignore`d files excluded by default |
102
+ | `scd scan --verbose` | Full file-grouped + rule-grouped output |
103
+ | `scd scan --deep` | Deep analysis via scd-server *(Premium)* |
104
+ | `scd scan --include-vendor` | Include vendor/dependency code in scan |
105
+ | `scd scan --vendor-only` | Scan only vendor/dependency code (supply chain) |
106
+ | `scd scan --include-ignored` | Scan files excluded by `.gitignore` (default: respect `.gitignore`) |
107
+ | `scd scan --exclude <pattern>` | Exclude a file or directory for this scan only (repeatable, not saved) |
108
+ | `scd scan --exclude-rule <id>` | Exclude a rule for this scan only (repeatable, not saved) |
109
+ | `scd scan --log-to <mode>` | Logging mode for non-interactive use: `none`, `current`, `target` (see below) |
110
+ | `scd scan --no-sync` | Skip pushing this scan to scd-server (audit log kept locally) *(Premium)* |
111
+ | `scd scan --no-audit` | Skip audit logging entirely for this scan |
112
+
113
+ #### `--exclude` and `--exclude-rule` — one-off scan exclusions
114
+
115
+ Exclude files or rules for a single scan without modifying `scope.yml`. Useful for quick ad-hoc filtering or testing rule changes.
116
+
117
+ ```bash
118
+ scd scan --exclude "tests/fixtures/" --exclude-rule INFRA-002
119
+ ```
120
+
121
+ One-off exclusions are shown in scan output, stored in the scan JSON, and never written to disk. For permanent exclusions, use `scd repo scope`.
122
+
123
+ #### `--log-to` — non-interactive and pipeline use
124
+
125
+ When `scd scan` is used as a subprocess or in a CI/CD pipeline without a TTY, it automatically detects the missing terminal and scans without logging — no prompt, no hanging. A single informational line is written to stderr.
126
+
127
+ Use `--log-to` when you need explicit control over logging in non-interactive contexts:
128
+
129
+ | Value | Behaviour |
130
+ |---|---|
131
+ | `none` | Scan without logging, no prompt (same as auto-detect default) |
132
+ | `current` | Log results to the current working directory's repo, no prompt |
133
+ | `target` | Log results to the target repository's repo, no prompt |
134
+
135
+ ```bash
136
+ # Automated pipeline — no TTY, no prompt, output file always written
137
+ scd scan ./repo --format json --output results.json
138
+
139
+ # Cron job — scan and log results to current repo
140
+ scd scan . --log-to current
141
+
142
+ # Explicit no-logging
143
+ scd scan . --log-to none
144
+ ```
145
+
146
+ Normal interactive behaviour (with a TTY and no `--log-to`) is completely unchanged.
147
+
148
+ ### Reports
149
+
150
+ | Command | Description |
151
+ |---|---|
152
+ | `scd report` | Generate report from last scan (HTML default) |
153
+ | `scd report open` | Generate report and open in browser |
154
+ | `scd report serve` | Serve report via local HTTP server |
155
+ | `scd report serve --index` | Always show report index page |
156
+ | `scd report --scan <id>` | Generate report from a specific saved scan |
157
+ | `scd export-findings` | Export all findings from a scan to JSON |
158
+ | `scd export-findings --deep-only` | Export only findings that have a deep analysis result |
159
+ | `scd export-findings --severity critical` | Filter exported findings by severity |
160
+ | `scd export-findings --scan <id>` | Export from a specific saved scan |
161
+
162
+ ### Findings
163
+
164
+ | Command | Description |
165
+ |---|---|
166
+ | `scd findings` | List open (unhandled) findings from last scan |
167
+ | `scd findings <finding-id>` | Show a specific finding with full detail (problem, scenario, fix) |
168
+ | `scd findings --verbose` | Show all open findings with problem description, scenario, and fix |
169
+ | `scd findings --all` | All findings including excepted and resolved |
170
+ | `scd findings --excepted` | Only excepted findings |
171
+ | `scd findings --show-suppressed` | Show findings suppressed by file context classification |
172
+ | `scd findings --severity critical` | Filter by severity |
173
+ | `scd findings --rule <id>` | Filter by rule ID |
174
+ | `scd findings --scan <id>` | Load a specific historic scan |
175
+
176
+ ### Exception and scope management
177
+
178
+ | Command | Description |
179
+ |---|---|
180
+ | `scd accept <finding-id> --reason "<text>"` | Accept a risk — requires team-lead approval via scd-server |
181
+ | `scd ignore <finding-id> --reason "<text>"` | Ignore a finding (false positive, out of scope) |
182
+ | `scd resolve` | Mark an EXPOSURE finding as handled, or remove a rejected exception |
183
+ | `scd sync` | Pull approvals/rejections from scd-server |
184
+ | `scd exceptions` | List all exceptions and their status |
185
+ | `scd scope --show` | Show current scope exclusions |
186
+ | `scd scope --add-file <pattern>` | Permanently exclude a file or directory |
187
+ | `scd scope --add-rule <id>` | Permanently exclude a rule |
188
+ | `scd scope --remove-file <pattern>` | Remove a file exclusion |
189
+ | `scd scope --remove-rule <id>` | Remove a rule exclusion |
190
+
191
+ ### Repository management
192
+
193
+ | Command | Description |
194
+ |---|---|
195
+ | `scd init` | Register current directory and install git hooks |
196
+ | `scd repo` | Show repo info and scan statistics |
197
+ | `scd repo configure` | Show or update per-repo configuration |
198
+ | `scd repo hooks --disable --reason "<text>"` | Disable git hooks for this repo (reason required) |
199
+ | `scd repo hooks --enable` | Re-enable git hooks |
200
+ | `scd repo scope` | Manage per-repo scope exclusions |
201
+ | `scd list` | List all registered repos |
202
+ | `scd hooks` | Show hook status across all repos |
203
+ | `scd remove` | Remove repo from scd |
204
+
205
+ ### Rules and insights
206
+
207
+ | Command | Description |
208
+ |---|---|
209
+ | `scd rules` | List all rules |
210
+ | `scd rules --search <term>` | Search rules by name or ID |
211
+ | `scd rules --stats` | Show rule counts by severity |
212
+ | `scd insights` | Behavioural analysis across scan history |
213
+ | `scd audit` | Show audit log |
214
+
215
+ ### Diagnostics
216
+
217
+ | Command | Description |
218
+ |---|---|
219
+ | `scd doctor` | Verify installation, hook status, and server connectivity |
220
+ | `scd version` | Show version and rule counts |
221
+ | `scd configure --show` | Show server configuration and global defaults |
222
+
223
+ ---
224
+
225
+ ## Privacy and data handling
226
+
227
+ scd is designed for teams where code privacy is non-negotiable.
228
+
229
+ **Local scanning.** Standard `scd scan` runs entirely on your machine. No code, no findings, no metadata leaves your network. Nothing is sent anywhere unless you explicitly connect scd-server.
230
+
231
+ **scd-server.** When configured, scd pushes scan metadata and findings to your own scd-server instance — running in your own infrastructure. Findings never reach Activemind's servers.
232
+
233
+ **Deep analysis.** `scd scan --deep` sends the triggering code line and 8 lines of surrounding context to your scd-server for AI analysis. The filename, rule ID, and severity are included. Whole files are never sent. Deep analysis requires scd-server with the Deep Analysis Pack. See [securecodebydesign.com](https://securecodebydesign.com) for subscription options.
234
+
235
+ Set `trust_level: maximum_privacy` with `scd repo configure --trust-level maximum_privacy` to disable all external API calls entirely.
236
+
237
+ ### Exception management
238
+
239
+ Exceptions are managed by finding ID — shown in scan output, reports, and `scd findings`. Never edit source code comments.
240
+
241
+ ```bash
242
+ # View open findings with their IDs
243
+ scd findings
244
+
245
+ # Accept a risk (requires team-lead approval via scd-server)
246
+ scd accept f-a1b2c3d4e5 --reason "Parameterized internally, validated input only"
247
+
248
+ # Ignore a finding (false positive, out of scope etc.)
249
+ scd ignore f-a1b2c3d4e5 --reason "Source maps intentionally included in staging" \
250
+ --tag false_positive
251
+
252
+ # Pull approvals/rejections from team server
253
+ scd sync
254
+
255
+ # List exceptions and their status
256
+ scd exceptions --list all
257
+
258
+ # Remove a rejected exception after fixing the issue
259
+ scd resolve --rejected exc-mn7k96ml
260
+ ```
261
+
262
+ Exceptions include a hash of the relevant code line. If the code changes, the exception requires re-approval automatically.
263
+
264
+ After `scd sync`, the next scan shows pending status inline:
265
+
266
+ ```
267
+ ℹ 2 exception(s) pending approval – synced recently – run scd sync
268
+ ⚠ 1 rejected exception(s) — fix required:
269
+ PHP-INJ-002 WS_addUser.php:10 [exc-mn7k96ml]
270
+ ```
271
+
272
+ ### Project configuration
273
+
274
+ Per-repository configuration lives in `~/.scd/repos/{repoId}/config.yml` — outside your repository, alongside scan history and exceptions. This keeps your repository clean and avoids committing security configuration to source control.
275
+
276
+ ```yaml
277
+ trust_level: balanced # maximum_privacy | balanced | maximum_analysis
278
+ scan_mode: full # full (with taint analysis) | fast (regex only)
279
+ block_on_critical: true
280
+ block_on_high: true
281
+ ```
282
+
283
+ Edit with `scd repo configure --<option> <value>` or directly in the file.
284
+
285
+ `trust_level` controls which external connections are permitted:
286
+
287
+ | Value | Behaviour |
288
+ |---|---|
289
+ | `maximum_privacy` | No external API calls. Local model only. Strongest privacy guarantee. |
290
+ | `balanced` | Default. Local model preferred; cloud available as explicit opt-in. |
291
+ | `maximum_analysis` | Cloud provider (Claude API). Maximum analysis depth. |
292
+
293
+ ---
294
+
295
+ ## Exporting findings
296
+
297
+ `scd export-findings` produces a self-contained JSON snapshot useful for sharing with an external reviewer:
298
+
299
+ ```bash
300
+ scd export-findings # all findings
301
+ scd export-findings --deep-only # only findings with deep analysis
302
+ scd export-findings --severity critical # filter by severity
303
+ scd export-findings --rule PHP-INJ-001 # filter by rule
304
+ scd export-findings --scan s-a3f9b2c1 # from specific scan
305
+ scd export-findings --output /tmp/review.json
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Multi-machine setup
311
+
312
+ See [INSTALL.md](INSTALL.md) for full platform-specific instructions including Node.js setup for macOS, Linux, and Windows.
313
+
314
+ ---
315
+
316
+ ## Project structure
317
+
318
+ ```
319
+ bin/
320
+ scd.js ← CLI entry point (all scd commands)
321
+ lib/
322
+ commands/ ← One file per scd command (scan, findings, report, …)
323
+ scanner-full.js ← OWASP scanner with taint analysis
324
+ scanner-secrets.js ← Fast secrets scanner (pre-commit)
325
+ file-manifest.js ← Pre-scan file classification (source/test/excluded)
326
+ file-context.js ← Per-file classification with two-layer detection
327
+ context-modifiers.js ← Severity adjustment based on file context + _trace
328
+ comment-map.js ← Per-file line classifier (CODE/COMMENT/MIXED)
329
+ taint-register.js ← Single-file taint tracking engine
330
+ store.js ← Global store path management
331
+ store-verify.js ← Store health checks and cleanup
332
+ scan-cache.js ← Per-scan storage (scans/ directory)
333
+ scan-context.js ← Repo-logging context resolution
334
+ rule-registry.js ← Normalised catalogue of all rules
335
+ config.js ← Config loading, isExcepted(), getRuleAction()
336
+ exception-manager.js ← Exception/ignore create, sync, resolve
337
+ deep-analyzer.js ← Deep analysis via scd-server
338
+ cli-helpers.js ← Shared CLI utilities (warnIfOutdated, openInBrowser, tryFlush)
339
+ output-terminal.js ← Compact + verbose terminal output
340
+ report-html.js ← HTML report generator
341
+ report-markdown.js ← Markdown report generator
342
+ report-json.js ← JSON report generator
343
+ export-findings.js ← Export findings to JSON
344
+ rules/ ← Rule definitions per language
345
+ rule-loader.js ← JSON→runtime compiler (pattern, antipatterns, extensions)
346
+ rules-js.json ← JavaScript/TypeScript rules incl. JS-ERR-002/B/C
347
+ rules-infra-leakage.json ← Infrastructure rules incl. INFRA-001/B/C, 002/B/C
348
+ rules-sensitive-files.json ← Sensitive file rules incl. LOG-004, EXPOSURE-001
349
+ rules-secrets.json ← Secrets detection
350
+ rules-python.json ← Python rules
351
+ rules-php.json ← PHP rules
352
+ rules-aspx.json ← ASP.NET markup rules
353
+ rules-aspx-cs.json ← ASP.NET C# rules
354
+ rules-ts.json ← TypeScript-specific rules
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Dependencies
360
+
361
+ scd is intentionally lightweight. Keeping the dependency surface small is a deliberate design principle — fewer dependencies means fewer supply chain risks, faster installs, and easier security auditing.
362
+
363
+ | Package | Version | Purpose |
364
+ |---|---|---|
365
+ | [commander](https://github.com/tj/commander.js) | ^14.0.3 | CLI argument parsing and subcommand structure |
366
+ | [semver](https://github.com/npm/node-semver) | ^7.x | Semantic version comparison for server compatibility checks |
367
+
368
+ No other runtime dependencies. Node.js built-in modules handle everything else.
369
+
370
+ Verify at any time:
371
+
372
+ ```bash
373
+ npm list # full dependency tree
374
+ npm audit # check for known vulnerabilities
375
+ ```
376
+
377
+ ---
378
+
379
+ ## Roadmap
380
+
381
+ - `scd deps` – Dependency vulnerability scanning against OSV + CISA KEV feeds (designed, in development)
382
+ - Config-context file classification — distinguishes application config, infrastructure config, and schema/documentation files before rules run; improves precision for YAML and configuration-heavy projects
383
+ - `scd uninstall` – clean removal with store data options
384
+
385
+ ---
386
+
387
+ ## Disclaimer
388
+
389
+ Secure Code by Design is a static analysis tool designed to help development teams identify common security vulnerability patterns in source code. It is provided as a technical aid, not as a guarantee of security.
390
+
391
+ **scd does not replace professional security testing.** No automated tool can detect all vulnerabilities in a codebase. scd does not perform dynamic analysis, penetration testing, runtime monitoring, or threat modelling. Findings depend on rule coverage, code patterns, and the languages supported — classes of vulnerabilities may exist that scd does not and cannot detect.
392
+
393
+ **No liability for security incidents.** Activemind Solutions AB and the contributors to this project accept no liability for security breaches, data loss, regulatory penalties, or any other damages arising from the use or non-use of this tool, including cases where a vulnerability present in a scanned codebase was not identified by scd. The presence of a passing scan does not constitute a security certification or assurance of any kind.
394
+
395
+ **scd is one layer of defence.** Effective application security requires multiple overlapping measures: secure design, code review, dependency management, penetration testing, monitoring, and incident response. scd is designed to make one of those layers — routine code scanning — easier and more consistent. It is not a substitute for any of the others.
396
+
397
+ If your organisation requires a formal security assessment, contact a qualified security professional or penetration testing firm.
398
+
399
+ ---
400
+
401
+ ## Security & responsible disclosure
402
+
403
+ Secure Code by Design is a security tool — and like any software, it may contain vulnerabilities. We encourage security testing of this product and welcome responsible disclosure.
404
+
405
+ **Expected behaviour:** Running `scd scan` on this repository will trigger findings in the rule files themselves — patterns that match injection, hardcoded secrets, and similar issues are present by design as test cases. These are expected false positives when scanning the tool's own source code.
406
+
407
+ **Reporting a vulnerability:** If you discover a genuine security issue, please report it privately to [security@activemind.se](mailto:security@activemind.se). Do not open a public GitHub issue for security vulnerabilities.
408
+
409
+ We aim to acknowledge reports within 2 business days and resolve confirmed issues as quickly as possible. Credit is given to researchers who report valid findings responsibly.
410
+
411
+ ---
412
+
413
+ ## About
414
+
415
+ Built by [Activemind Solutions AB](https://activemind.se) — security consulting and penetration testing.
416
+
417
+ > Secure Code by Design is a commercial product. See LICENSE for terms.
package/bin/scd.js ADDED
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scd – CLI entry point
4
+ * Config-aware with audit logging
5
+ */
6
+
7
+ const { Command } = require('commander');
8
+
9
+ const { warnIfOutdated, openInBrowser, tryFlush } = require('../lib/cli-helpers');
10
+ const { loadConfig, getRepoRoot } = require('../lib/config');
11
+
12
+ const program = new Command();
13
+
14
+ const pkg = require('../package.json');
15
+
16
+
17
+ program
18
+ .name('scd')
19
+ .description('Secure Code by Design – automated security scanning');
20
+
21
+ // Handle --version / -V before Commander parses — shows scd version output
22
+ // identical to `scd version`, instead of Commander's default single-line format.
23
+ if (process.argv.includes('--version') || process.argv.includes('-V')) {
24
+ require('../lib/commands/version').showVersion();
25
+ process.exit(0);
26
+ }
27
+
28
+ require('../lib/commands/scan').register(program);
29
+
30
+
31
+ require('../lib/commands/install').register(program);
32
+ require('../lib/commands/uninstall').register(program);
33
+
34
+ require('../lib/commands/doctor').register(program);
35
+
36
+ require('../lib/commands/accept').register(program);
37
+
38
+ require('../lib/commands/ignore').register(program);
39
+
40
+ require('../lib/commands/findings').register(program);
41
+
42
+
43
+ require('../lib/commands/sync').register(program);
44
+
45
+ require('../lib/commands/exceptions').register(program);
46
+
47
+ require('../lib/commands/resolve').register(program);
48
+
49
+ require('../lib/commands/init').register(program);
50
+
51
+ require('../lib/commands/remove').register(program);
52
+
53
+ require('../lib/commands/report').register(program);
54
+
55
+ require('../lib/commands/audit').register(program);
56
+ require('../lib/commands/insights').register(program);
57
+
58
+ require('../lib/commands/configure').register(program);
59
+ require('../lib/commands/scope').register(program);
60
+
61
+
62
+ require('../lib/commands/repo').register(program);
63
+
64
+ require('../lib/commands/version').register(program);
65
+ require('../lib/commands/list').register(program);
66
+ require('../lib/commands/rules').register(program);
67
+
68
+ require('../lib/commands/export-findings').register(program);
69
+
70
+
71
+ // ── scd review-rules (Activemind-internal, hidden from scd --help) ───────────
72
+ {
73
+ const { Command } = require('commander');
74
+ const reviewCmd = new Command('review-rules');
75
+ reviewCmd
76
+ .description('Export findings with rule internals for Activemind rule quality review')
77
+ .option('--scan <id>', 'Scan ID to export (default: latest scan)')
78
+ .option('--severity <level>', 'Filter by severity: critical, high, medium, exposure')
79
+ .option('--rule <id>', 'Filter to a specific rule ID')
80
+ .option('--deep-only', 'Export only findings that have a deep analysis result')
81
+ .option('--output <path>', 'Output file path (default: ~/.scd/repos/{id}/exports/scd-review-{scanId}.json)')
82
+ .action(async (opts) => {
83
+ const path = require('path');
84
+ const store = require('../lib/store');
85
+ const { exportFindings } = require('../lib/export-findings');
86
+ const { loadCache } = require('../lib/scan-cache');
87
+ const repoRoot = getRepoRoot();
88
+
89
+ let resolvedScanId = opts.scan || null;
90
+ if (!resolvedScanId) {
91
+ const latest = loadCache(repoRoot);
92
+ if (latest) resolvedScanId = latest.scanId;
93
+ }
94
+
95
+ const defaultName = 'scd-review-' + (resolvedScanId || 'scan') + '.json';
96
+ const outputPath = opts.output
97
+ ? path.resolve(process.cwd(), opts.output)
98
+ : store.exportPath(repoRoot, defaultName);
99
+
100
+ await exportFindings({
101
+ repoRoot,
102
+ scanId: opts.scan || null,
103
+ severity: opts.severity || null,
104
+ rule: opts.rule || null,
105
+ deepOnly: !!opts.deepOnly,
106
+ outputPath,
107
+ includeRuleInternals: true,
108
+ command: 'review-rules',
109
+ });
110
+ });
111
+
112
+ program.addCommand(reviewCmd, { hidden: true });
113
+ }
114
+
115
+
116
+ program.parse(process.argv);
117
+
118
+ // ── Push worker – trigger after every command ─────────────────────────────
119
+ // Non-blocking: runs after the CLI command completes.
120
+ // Only active when a central URL is configured.
121
+ // Failures are silent – never affect CLI output or exit code.
122
+ setImmediate(() => {
123
+ try {
124
+ const { getCentralUrl } = require('../lib/global-config');
125
+ const centralUrl = getCentralUrl();
126
+ if (!centralUrl) return;
127
+
128
+ const { flush, queueSize } = require('../lib/push-queue');
129
+ if (queueSize() === 0) return;
130
+
131
+ // Pass repoRoot so meta includes repo and installation identity
132
+ const repoRoot = (() => {
133
+ try { return require('../lib/config').getRepoRoot(); } catch { return null; }
134
+ })();
135
+
136
+ flush(centralUrl, { repoRoot }).catch(() => {});
137
+ } catch {
138
+ // Non-fatal
139
+ }
140
+ });
@@ -0,0 +1,93 @@
1
+ const { RESET, BOLD, DIM, RED, GREEN, YELLOW, CYAN } = require('./output-constants');
2
+ /**
3
+ * audit-report.js
4
+ * Human-readable terminal report of the audit log.
5
+ * Shows findings history, exceptions, expired exceptions.
6
+ */
7
+
8
+ const { readAuditLog, EVENTS } = require('./audit');
9
+
10
+ async function showAuditReport(repoRoot, limit = 50) {
11
+ const events = readAuditLog(repoRoot, 500);
12
+
13
+ if (events.length === 0) {
14
+ console.log(DIM + '\n No audit log found yet.' + RESET + '\n');
15
+ return;
16
+ }
17
+
18
+ console.log(`\n${CYAN}${BOLD}╔══════════════════════════════════════════╗${RESET}`);
19
+ console.log(`${CYAN}${BOLD}║ Secure Code by Design – Audit Report ║${RESET}`);
20
+ console.log(`${CYAN}${BOLD}╚══════════════════════════════════════════╝${RESET}\n`);
21
+
22
+ // ── Stats ────────────────────────────────────────────────────────────────
23
+ const scans = events.filter(e => e.event === EVENTS.SCAN_STARTED);
24
+ const blocked = events.filter(e => e.event === EVENTS.FINDING_BLOCKED);
25
+ const warned = events.filter(e => e.event === EVENTS.FINDING_WARNED);
26
+ const excepted = events.filter(e => e.event === EVENTS.FINDING_EXCEPTED);
27
+ const expired = events.filter(e => e.event === EVENTS.FINDING_EXCEPTION_EXPIRED);
28
+ const scanBlocked = events.filter(e => e.event === EVENTS.SCAN_BLOCKED);
29
+
30
+ console.log(`${BOLD}Summary${RESET}`);
31
+ console.log(` Total scans: ${scans.length}`);
32
+ console.log(` Blocked scans: ${RED}${scanBlocked.length}${RESET}`);
33
+ console.log(` Blocked findings: ${RED}${blocked.length}${RESET}`);
34
+ console.log(` Warned findings: ${YELLOW}${warned.length}${RESET}`);
35
+ console.log(` Excepted findings: ${DIM}${excepted.length}${RESET}`);
36
+
37
+ if (expired.length > 0) {
38
+ console.log(` ${RED}${BOLD}Expired exceptions: ${expired.length} – action required!${RESET}`);
39
+ }
40
+
41
+ // ── Expired exceptions – these need immediate attention ──────────────────
42
+ if (expired.length > 0) {
43
+ console.log(`\n${RED}${BOLD}⚠️ Expired exceptions – immediate action required${RESET}`);
44
+ console.log(`${RED}${'─'.repeat(50)}${RESET}`);
45
+ for (const e of expired.slice(-10)) {
46
+ console.log(` ${e.timestamp.slice(0, 10)} ${e.rule_id} ${e.file}:${e.line}`);
47
+ console.log(` ${DIM}Exception approved by: ${e.exception_by || 'unknown'}${RESET}`);
48
+ }
49
+ }
50
+
51
+ // ── Recent blocked findings ───────────────────────────────────────────────
52
+ if (blocked.length > 0) {
53
+ console.log(`\n${BOLD}Recent blocked findings${RESET}`);
54
+ console.log(`${'─'.repeat(50)}`);
55
+ for (const e of blocked.slice(-10)) {
56
+ const date = e.timestamp.slice(0, 16).replace('T', ' ');
57
+ console.log(` ${DIM}${date}${RESET} ${RED}${e.severity}${RESET} ${e.rule_id}`);
58
+ console.log(` ${DIM}${e.file}:${e.line} [${e.git_user}]${RESET}`);
59
+ }
60
+ }
61
+
62
+ // ── Active exceptions ─────────────────────────────────────────────────────
63
+ if (excepted.length > 0) {
64
+ console.log(`\n${BOLD}Active exceptions (recent runs)${RESET}`);
65
+ console.log(`${'─'.repeat(50)}`);
66
+
67
+ // Deduplicate by rule+file
68
+ const seen = new Set();
69
+ for (const e of excepted.slice(-20)) {
70
+ const key = `${e.rule_id}:${e.file}`;
71
+ if (seen.has(key)) continue;
72
+ seen.add(key);
73
+ const date = e.timestamp.slice(0, 10);
74
+ console.log(` ${DIM}${date}${RESET} ${YELLOW}${e.rule_id}${RESET} ${e.file}`);
75
+ console.log(` ${DIM}Approved by: ${e.exception_by || 'not specified'}${RESET}`);
76
+ }
77
+ console.log(`\n ${DIM}Run 'scd approve --list' for full list${RESET}`);
78
+ }
79
+
80
+ // ── Recent scan history ───────────────────────────────────────────────────
81
+ console.log(`\n${BOLD}Recent scans${RESET}`);
82
+ console.log(`${'─'.repeat(50)}`);
83
+ for (const e of scans.slice(-5)) {
84
+ const date = e.timestamp.slice(0, 16).replace('T', ' ');
85
+ const outcome = scanBlocked.find(b => b.session_id === e.session_id);
86
+ const icon = outcome ? `${RED}🚫${RESET}` : `${GREEN}✅${RESET}`;
87
+ console.log(` ${icon} ${DIM}${date}${RESET} ${e.hook} ${e.files_count} file(s) [${e.git_user}]`);
88
+ }
89
+
90
+ console.log('');
91
+ }
92
+
93
+ module.exports = { showAuditReport };