korext 0.9.12 → 1.0.1

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 (3) hide show
  1. package/README.md +88 -74
  2. package/bin/korext.js +81 -19
  3. package/package.json +23 -12
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
- # Korext CLI
1
+ # KOREXT CLI
2
2
 
3
- Enforce compliance on AI-generated code from the command line and CI/CD pipelines. 478 rules across 44 policy packs with real detection logic. Every violation mapped to specific regulatory clauses. SARIF output for CI scanner integration.
3
+ AI Code Governance for your terminal and CI/CD pipelines.
4
+
5
+ Enforce compliance policies on human written and AI generated code. 72 policy packs. 532 detection rules. 13 languages. Cryptographically signed proof bundles.
4
6
 
5
7
  ## Install
6
8
 
@@ -11,115 +13,127 @@ npm install -g korext
11
13
  ## Quick Start
12
14
 
13
15
  ```bash
16
+ # Sign in
14
17
  korext login
15
- korext enforce ./src --pack web-platform-v2
18
+
19
+ # Initialize your project
20
+ korext init
21
+
22
+ # Enforce policies on your code
23
+ korext enforce .
24
+
25
+ # Enforce with specific packs
26
+ korext enforce . --pack web,pci-dss-v1
27
+
28
+ # Enforce with a specific region
29
+ korext enforce . --region eu --pack web
30
+
31
+ # Generate a signed proof bundle
32
+ korext enforce . --pack web --sign
16
33
  ```
17
34
 
18
35
  ## Commands
19
36
 
20
37
  | Command | Description |
21
38
  |---------|-------------|
22
- | `korext login [token]` | Save API token |
23
- | `korext status` | Check connection and subscription |
24
- | `korext enforce [dir]` | Scan files for violations |
25
- | `korext policy init` | Initialize a policy document |
26
- | `korext policy extract` | AI rule extraction from documents |
27
- | `korext policy review` | Review extracted rules |
28
- | `korext rules sync` | Cache rules for offline use |
29
-
30
- ### Enforce Options
31
-
32
- | Flag | Description |
33
- |------|-------------|
34
- | `--pack <id>` | Select a policy pack |
35
- | `--format text\|json\|sarif` | Output format |
36
- | `--offline` | Use cached rules only |
37
- | `--sync-rules` | Download rule cache before scan |
39
+ | `korext login` | Sign in to your KOREXT account |
40
+ | `korext init` | Initialize a project with korext.json |
41
+ | `korext enforce <path>` | Run policy enforcement on files |
42
+ | `korext packs list` | List all available policy packs |
43
+ | `korext industries` | List industries and their packs |
44
+ | `korext bundle list` | List your recent proof bundles |
45
+ | `korext bundle export <id>` | Download a proof bundle as PDF |
46
+ | `korext bundle verify <id>` | Verify a proof bundle signature |
47
+ | `korext status` | Show current configuration and region |
48
+
49
+ ## Enforce Options
50
+
51
+ | Flag | Description | Default |
52
+ |------|-------------|---------|
53
+ | `--pack <ids>` | Comma separated pack IDs | web |
54
+ | `--region <name>` | Data region (us, eu, apac) | us |
55
+ | `--format <type>` | Output format (text, json, sarif) | text |
56
+ | `--sign` | Request signed proof bundle | false |
57
+ | `--industry <name>` | Select packs by industry | (none) |
58
+ | `--offline` | Run with local engine only | false |
59
+
60
+ ## Output Formats
61
+
62
+ **Text** (default): Human readable violation list with governance context.
63
+
64
+ **JSON**: Machine readable output with full violation details, confidence scores, and proof bundle metadata.
65
+
66
+ **SARIF**: Static Analysis Results Interchange Format for CI/CD integration. Compatible with GitHub Code Scanning, Azure DevOps, and other SARIF consumers.
38
67
 
39
68
  ## CI/CD Integration
40
69
 
41
70
  ### GitHub Actions
42
71
 
43
72
  ```yaml
44
- - name: Korext Compliance Check
45
- run: |
46
- npm install -g korext
47
- korext enforce ./src \
48
- --pack cmmc-level2-v1 \
49
- --format sarif
73
+ - uses: korext/enforce-action@v3
74
+ with:
75
+ pack: web,pci-dss-v1
76
+ region: eu
50
77
  env:
51
78
  KOREXT_API_TOKEN: ${{ secrets.KOREXT_API_TOKEN }}
52
79
  ```
53
80
 
54
- ### Exit Codes
55
-
56
- | Code | Meaning |
57
- |------|---------|
58
- | `0` | Clean (no critical or high violations) |
59
- | `1` | Violations found |
60
- | `2` | Error |
61
-
62
- Writes GitHub Actions Step Summary via `GITHUB_STEP_SUMMARY` when detected.
63
-
64
- ## SARIF Output
81
+ ### Pre-commit Hook
65
82
 
66
83
  ```bash
67
- korext enforce ./src --format sarif > results.sarif
84
+ # .husky/pre-commit
85
+ korext enforce . --pack web
68
86
  ```
69
87
 
70
- Generates OASIS SARIF 2.1.0 for CI scanner integration (GitHub Code Scanning, Azure DevOps, etc.).
71
-
72
- ## Offline Mode
88
+ ### Generic CI
73
89
 
74
90
  ```bash
75
- korext rules sync
76
- korext enforce ./src --offline
91
+ npm install -g korext
92
+ korext login --token $KOREXT_API_TOKEN
93
+ korext enforce . --pack web --format sarif --sign
77
94
  ```
78
95
 
79
- Cached rules enforce locally with zero network calls. Status output shows "Offline (local rules only)".
96
+ ## Exit Codes
97
+
98
+ | Code | Meaning |
99
+ |------|---------|
100
+ | 0 | PASS (no violations) |
101
+ | 1 | BLOCK (violations found) |
102
+ | 2 | ERROR (invalid input, network, auth) |
80
103
 
81
- ## Supported Compliance Frameworks
104
+ CI pipelines should fail on exit code 1 to block non-compliant code from merging.
82
105
 
83
- OWASP Top 10 | PCI-DSS | HIPAA | GDPR | SOC 2 | NIST SP 800-53 | NIST SP 800-171 | CMMC Level 2/3 | FedRAMP | ISO 27001 | DORA | NIS2 | CIS Benchmarks | UK DPA | Australian Privacy Act | APPI (Japan) | PDPA (Singapore, Taiwan) | and 25+ more
106
+ ## Configuration
84
107
 
85
- ## Key Features
108
+ ### korext.json
86
109
 
87
- - 478 rules across 44 policy packs
88
- - Three-layer governance: regulatory, technical standards (CWE, OWASP), security intelligence (MITRE ATT&CK)
89
- - 9 jurisdiction coverage (US, EU, UK, Canada, Australia, New Zealand, Japan, Taiwan, Singapore)
90
- - SARIF 2.1.0 output for CI scanner integration
91
- - GitHub Actions Step Summary generation
92
- - Offline mode with cached rules
93
- - Custom policy packs from uploaded documents
110
+ ```json
111
+ {
112
+ "project": "my-app",
113
+ "targetPacks": ["web", "pci-dss-v1"],
114
+ "region": "eu",
115
+ "industry": "finance"
116
+ }
117
+ ```
94
118
 
95
- ## Environment Variables
119
+ ### Environment Variables
96
120
 
97
121
  | Variable | Description |
98
122
  |----------|-------------|
99
- | `KOREXT_API_TOKEN` | API authentication token (recommended) |
100
- | `KOREXT_TOKEN` | Deprecated alias (shows warning) |
101
-
102
- ## Changelog
123
+ | `KOREXT_API_TOKEN` | API token for CI/CD (from dashboard) |
103
124
 
104
- ### v0.9.5
125
+ ## Data Sovereignty
105
126
 
106
- Fixed
107
- - Watch mode now detects file changes correctly and scans on startup
108
- - Enforcing a nonexistent directory now prints an error and exits with code 2 instead of silently passing
109
- - Offline enforcement prints how many rules are available versus how many require server analysis
110
- - Policy commands now default to the production API instead of localhost
127
+ Choose your data processing region: US, EU, or Asia Pacific. Set via `--region` flag, `korext.json`, or `korext init`. All enforcement data stays in your chosen region.
111
128
 
112
129
  ## Links
113
130
 
114
- - Website: [korext.com](https://www.korext.com)
115
- - Dashboard: [app.korext.com](https://app.korext.com)
116
- - VS Code Extension: [marketplace.visualstudio.com](https://marketplace.visualstudio.com/items?itemName=Korext.korext)
117
- - LinkedIn: [linkedin.com/company/korext](https://www.linkedin.com/company/korext)
118
- - GitHub: [github.com/Korext](https://github.com/Korext)
119
- - Support: support@korext.com
131
+ - [Website](https://korext.com)
132
+ - [Dashboard](https://app.korext.com)
133
+ - [Documentation](https://korext.com/docs)
134
+ - [GitHub Action](https://github.com/marketplace/actions/korext-enforce)
135
+ - [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=Korext.korext)
120
136
 
121
- ---
137
+ ## License
122
138
 
123
- **Publisher**: Korext
124
- **License**: Proprietary
125
- **Version**: 0.9.5
139
+ Proprietary. See [Terms of Service](https://korext.com/legal).
package/bin/korext.js CHANGED
@@ -295,6 +295,15 @@ async function fetchAndCacheRules() {
295
295
  * Run rules locally against code using cached regex definitions.
296
296
  * Mirrors korext-core/src/engine/localEngine.ts analyzeLocally().
297
297
  */
298
+ // M1: Check if a line is a comment (skip from local engine scanning)
299
+ function isCommentLine(line) {
300
+ const trimmed = line.trim();
301
+ return trimmed.startsWith('//')
302
+ || trimmed.startsWith('*')
303
+ || trimmed.startsWith('/*')
304
+ || trimmed.startsWith('#');
305
+ }
306
+
298
307
  function analyzeLocally(code, packId, definitions) {
299
308
  // Normalize packId to array to support multi-pack (e.g. ["web", "pci-dss-v1"])
300
309
  const packIdList = Array.isArray(packId) ? packId : [packId];
@@ -321,6 +330,8 @@ function analyzeLocally(code, packId, definitions) {
321
330
  try {
322
331
  const re = new RegExp(pattern.regex, pattern.flags || 'gi');
323
332
  lines.forEach((line, i) => {
333
+ // M1: Skip comment lines to avoid false positives
334
+ if (isCommentLine(line)) return;
324
335
  re.lastIndex = 0;
325
336
  if (re.test(line)) {
326
337
  violations.push({
@@ -371,7 +382,12 @@ const program = new Command();
371
382
  program
372
383
  .name('korext')
373
384
  .description('Korext Command Line Interface - Enterprise Policy Enforcement')
374
- .version(version);
385
+ .version(version)
386
+ .action(() => {
387
+ // H3: Show help and exit 0 when no subcommand is provided
388
+ program.outputHelp();
389
+ process.exit(0);
390
+ });
375
391
 
376
392
  program
377
393
  .command('login [token]')
@@ -585,6 +601,7 @@ program
585
601
  .command('init')
586
602
  .description('Initialize a korext.json configuration file for your project')
587
603
  .option('--non-interactive', 'Skip prompts and use defaults', false)
604
+ .option('--region <region>', 'Data processing region (us, eu, apac)')
588
605
  .action(async (options) => {
589
606
  console.log(chalk.bold.hex('#F27D26')('\n\u25b2 KOREXT PROJECT INIT'));
590
607
  console.log(chalk.dim('=======================================\n'));
@@ -613,13 +630,15 @@ program
613
630
  const taxonomy = buildTaxonomyFromPacks(defs.packs);
614
631
 
615
632
  if (options.nonInteractive) {
616
- // Non-interactive: default to web pack
633
+ // Non-interactive: default to web pack, optionally with region
617
634
  const config = {
618
635
  targetPacks: ['web'],
636
+ ...(options.region && { region: options.region }),
619
637
  exclude: ['node_modules', 'dist', 'build', '.next']
620
638
  };
621
639
  fs.writeFileSync(outputPath, JSON.stringify(config, null, 2));
622
- console.log(chalk.green(`Created ${outputPath} with default pack: web\n`));
640
+ const regionNote = options.region ? ` (region: ${options.region})` : '';
641
+ console.log(chalk.green(`Created ${outputPath} with default pack: web${regionNote}\n`));
623
642
  process.exit(0);
624
643
  }
625
644
 
@@ -856,6 +875,13 @@ program
856
875
  const format = options.format.toLowerCase();
857
876
  const isText = format === 'text';
858
877
 
878
+ // H1: Validate output format before proceeding
879
+ const SUPPORTED_FORMATS = ['text', 'json', 'sarif'];
880
+ if (!SUPPORTED_FORMATS.includes(format)) {
881
+ console.error(chalk.red(`\n\u2716 Unsupported format: "${format}". Supported formats: ${SUPPORTED_FORMATS.join(', ')}`));
882
+ process.exit(2);
883
+ }
884
+
859
885
  // ── Workspace config reader ──────────────────────────────────────────────
860
886
  function loadWorkspaceConfig(targetDir) {
861
887
  const configPaths = [
@@ -916,7 +942,7 @@ program
916
942
  } else {
917
943
  console.error(JSON.stringify({ error: `Unknown pack ID(s): ${unknownPacks.join(', ')}` }));
918
944
  }
919
- process.exit(1);
945
+ process.exit(2); // C2: Error exit for invalid pack ID
920
946
  }
921
947
  }
922
948
  } else if (options.industry) {
@@ -925,14 +951,14 @@ program
925
951
  if (!taxonomy) {
926
952
  if (isText) console.error(chalk.red('\n\u2716 --industry requires cached rule definitions.'));
927
953
  if (isText) console.error(chalk.dim(` Run ${chalk.green('korext rules sync')} first to cache pack tags.`));
928
- process.exit(1);
954
+ process.exit(2); // C2: Error exit for missing cache
929
955
  }
930
956
  packIds = resolvePacksForIndustryRegion(options.industry, options.region || null, taxonomy);
931
957
  packSource = 'industry-flag';
932
958
  if (packIds.length === 0) {
933
959
  if (isText) console.error(chalk.red(`\n\u2716 No packs found for industry '${options.industry}'${options.region ? ` in region '${options.region}'` : ''}.`));
934
960
  if (isText) console.error(chalk.dim(` Run ${chalk.green('korext industries')} to see valid industry names.`));
935
- process.exit(1);
961
+ process.exit(2); // C2: Error exit for no matching packs
936
962
  }
937
963
  if (isText) console.log(`[KOREXT] Resolved ${packIds.length} packs for industry: ${options.industry}${options.region ? ` (region: ${options.region})` : ''}`);
938
964
  } else {
@@ -1002,11 +1028,30 @@ program
1002
1028
  let forceOffline = options.offline;
1003
1029
  let localDefinitions = null;
1004
1030
 
1005
- // Pre-flight: verify directory exists
1031
+ // C1: Pre-flight: verify path exists and determine file vs directory
1006
1032
  const resolvedInputDir = path.resolve(dir);
1007
1033
  if (!fs.existsSync(resolvedInputDir)) {
1008
- if (isText) console.error(chalk.red(`\n Directory does not exist: ${resolvedInputDir}`));
1009
- else console.error(JSON.stringify({ error: `Directory does not exist: ${resolvedInputDir}` }));
1034
+ if (isText) console.error(chalk.red(`\n\u2716 Path does not exist: ${resolvedInputDir}`));
1035
+ else console.error(JSON.stringify({ error: `Path does not exist: ${resolvedInputDir}` }));
1036
+ process.exit(2);
1037
+ }
1038
+
1039
+ // C1: Detect single file vs directory
1040
+ let isSingleFile = false;
1041
+ const inputStats = fs.statSync(resolvedInputDir);
1042
+ if (inputStats.isFile()) {
1043
+ isSingleFile = true;
1044
+ const ext = path.extname(resolvedInputDir);
1045
+ const SUPPORTED_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.java', '.rs'];
1046
+ if (!SUPPORTED_EXTENSIONS.includes(ext)) {
1047
+ if (isText) console.error(chalk.red(`\n\u2716 Unsupported file type: ${ext}`));
1048
+ else console.error(JSON.stringify({ error: `Unsupported file type: ${ext}` }));
1049
+ if (isText) console.error(chalk.dim(` Supported: ${SUPPORTED_EXTENSIONS.join(', ')}\n`));
1050
+ process.exit(2);
1051
+ }
1052
+ } else if (!inputStats.isDirectory()) {
1053
+ if (isText) console.error(chalk.red(`\n\u2716 Invalid path (not a file or directory): ${resolvedInputDir}`));
1054
+ else console.error(JSON.stringify({ error: `Invalid path: ${resolvedInputDir}` }));
1010
1055
  process.exit(2);
1011
1056
  }
1012
1057
 
@@ -1033,7 +1078,7 @@ program
1033
1078
  if (!localDefinitions) {
1034
1079
  if (isText) console.error(chalk.red('\n✖ Offline mode requires cached rule definitions.'));
1035
1080
  if (isText) console.error(chalk.dim(` Run ${chalk.green('korext rules sync')} or ${chalk.green('korext enforce --sync-rules')} first while online.`));
1036
- process.exit(1);
1081
+ process.exit(2); // C2: Error exit for missing offline cache
1037
1082
  }
1038
1083
  if (isText) {
1039
1084
  console.log(chalk.yellow('\n⚡ Offline mode: using local rule engine (regex-based analysis)'));
@@ -1079,12 +1124,17 @@ program
1079
1124
  bundles: []
1080
1125
  };
1081
1126
 
1127
+ // C1: Single file support
1082
1128
  let files;
1083
- try {
1084
- files = findFiles(dir);
1085
- } catch (e) {
1086
- if (isText) console.error(chalk.red(`Error reading directory: ${e.message}`));
1087
- process.exit(1);
1129
+ if (isSingleFile) {
1130
+ files = [resolvedInputDir];
1131
+ } else {
1132
+ try {
1133
+ files = findFiles(dir);
1134
+ } catch (e) {
1135
+ if (isText) console.error(chalk.red(`Error reading directory: ${e.message}`));
1136
+ process.exit(2); // C2: Error exit for filesystem errors
1137
+ }
1088
1138
  }
1089
1139
 
1090
1140
  report.summary.totalFiles = files.length;
@@ -1150,6 +1200,18 @@ program
1150
1200
  });
1151
1201
  clearTimeout(timeoutId);
1152
1202
 
1203
+ // C3 + H2: Differentiate auth errors from server/network errors
1204
+ if (res.status === 401 || res.status === 403) {
1205
+ if (fileSpinner) fileSpinner.stop();
1206
+ if (isText) {
1207
+ console.error(chalk.red('\n\u2716 Authentication failed. Your token may be expired.'));
1208
+ console.error(chalk.dim(` Run: ${chalk.green('korext login')} to re-authenticate.\n`));
1209
+ } else {
1210
+ console.error(JSON.stringify({ error: 'Authentication failed. Token may be expired. Run: korext login' }));
1211
+ }
1212
+ process.exit(2);
1213
+ }
1214
+
1153
1215
  if (!res.ok) {
1154
1216
  throw new Error(`HTTP ${res.status}`);
1155
1217
  }
@@ -1170,7 +1232,7 @@ program
1170
1232
  file: displayPath,
1171
1233
  bundleId: result.proofBundle.bundleId,
1172
1234
  decision: result.proofBundle.decision,
1173
- signed: !!result.proofBundle.hmacSignature,
1235
+ signed: !!result.proofBundle.hmacSignature || !!result.proofBundle.signature,
1174
1236
  verifyUrl: `https://app.korext.com/verify/${result.proofBundle.bundleId}`,
1175
1237
  });
1176
1238
  }
@@ -1180,12 +1242,12 @@ program
1180
1242
  fetchAndCacheRules().catch(() => {});
1181
1243
  }
1182
1244
  } catch (e) {
1183
- // Server unreachable fall back to local engine
1245
+ // Network error or server 5xx: fall back to local engine
1184
1246
  if (localDefinitions) {
1185
1247
  if (!usedLocalEngine && isText && i === 0) {
1186
1248
  // Show fallback banner once
1187
- console.log(chalk.yellow(`\n Server unreachable. Falling back to local engine (regex-based analysis).`));
1188
- console.log(chalk.dim(` Cached rules: v${localDefinitions.version} · ${localDefinitions.ruleCount} rules\n`));
1249
+ console.log(chalk.yellow(`\n\u26a1 Server unreachable. Falling back to local engine (regex-based analysis).`));
1250
+ console.log(chalk.dim(` Cached rules: v${localDefinitions.version} \u00b7 ${localDefinitions.ruleCount} rules\n`));
1189
1251
  }
1190
1252
  fileViolations = analyzeLocally(fileContent, pack, localDefinitions);
1191
1253
  usedLocalEngine = true;
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "korext",
3
- "version": "0.9.12",
3
+ "version": "1.0.1",
4
4
  "mcpName": "io.github.Korext/governance",
5
- "description": "Korext Command Line Interface",
5
+ "description": "KOREXT CLI. AI Code Governance. Enforce compliance policies on human written and AI generated code. 72 policy packs. 532 rules. 13 languages. Signed proof bundles.",
6
6
  "type": "module",
7
7
  "main": "bin/korext.js",
8
8
  "bin": {
9
9
  "korext": "bin/korext.js"
10
10
  },
11
- "author": "Korext <support@korext.com>",
12
- "license": "ISC",
11
+ "author": "Korext <tombruno@korext.com> (https://korext.com)",
12
+ "license": "SEE LICENSE IN LICENSE",
13
13
  "dependencies": {
14
14
  "chalk": "^4.1.2",
15
15
  "commander": "^14.0.3",
@@ -19,24 +19,35 @@
19
19
  "ora": "^5.4.1"
20
20
  },
21
21
  "files": [
22
- "bin/"
22
+ "bin/",
23
+ "README.md",
24
+ "LICENSE"
23
25
  ],
24
- "homepage": "https://www.korext.com",
26
+ "homepage": "https://korext.com",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://korext.com"
30
+ },
25
31
  "bugs": {
32
+ "url": "https://korext.com/support",
26
33
  "email": "support@korext.com"
27
34
  },
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
28
38
  "keywords": [
29
39
  "governance",
30
40
  "compliance",
31
41
  "security",
32
- "cli",
33
- "cicd",
34
- "sarif",
42
+ "SAST",
43
+ "linter",
44
+ "code-quality",
35
45
  "AI",
36
- "code review",
46
+ "policy",
37
47
  "PCI-DSS",
38
48
  "HIPAA",
39
- "OWASP",
40
- "korext"
49
+ "GDPR",
50
+ "proof-bundle",
51
+ "sovereignty"
41
52
  ]
42
53
  }