@vibe-validate/cli 0.17.0-rc4 → 0.17.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.
- package/config-templates/minimal.yaml +19 -8
- package/config-templates/typescript-library.yaml +19 -8
- package/config-templates/typescript-nodejs.yaml +19 -8
- package/config-templates/typescript-react.yaml +19 -8
- package/dist/bin/vibe-validate +54 -3
- package/dist/bin/vibe-validate.d.ts +5 -0
- package/dist/bin/vibe-validate.d.ts.map +1 -1
- package/dist/bin/vibe-validate.js +54 -3
- package/dist/bin/vibe-validate.js.map +1 -1
- package/dist/bin/vv +54 -3
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -1
- package/dist/commands/create-extractor.d.ts.map +1 -1
- package/dist/commands/create-extractor.js +41 -6
- package/dist/commands/create-extractor.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +172 -126
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/pre-commit.d.ts.map +1 -1
- package/dist/commands/pre-commit.js +177 -63
- package/dist/commands/pre-commit.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +15 -14
- package/dist/commands/run.js.map +1 -1
- package/dist/schemas/watch-pr-schema.d.ts +2 -2
- package/dist/services/ci-providers/github-actions.d.ts.map +1 -1
- package/dist/services/ci-providers/github-actions.js +3 -2
- package/dist/services/ci-providers/github-actions.js.map +1 -1
- package/dist/utils/git-detection.d.ts.map +1 -1
- package/dist/utils/git-detection.js +18 -18
- package/dist/utils/git-detection.js.map +1 -1
- package/dist/utils/project-id.d.ts +1 -2
- package/dist/utils/project-id.d.ts.map +1 -1
- package/dist/utils/project-id.js +6 -11
- package/dist/utils/project-id.js.map +1 -1
- package/dist/utils/runner-adapter.d.ts.map +1 -1
- package/dist/utils/runner-adapter.js +1 -0
- package/dist/utils/runner-adapter.js.map +1 -1
- package/dist/utils/secret-scanning.d.ts +72 -0
- package/dist/utils/secret-scanning.d.ts.map +1 -0
- package/dist/utils/secret-scanning.js +205 -0
- package/dist/utils/secret-scanning.js.map +1 -0
- package/dist/utils/validate-workflow.d.ts.map +1 -1
- package/dist/utils/validate-workflow.js +9 -1
- package/dist/utils/validate-workflow.js.map +1 -1
- package/package.json +8 -6
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Interactive scaffold generator for vibe-validate extractor plugins.
|
|
5
5
|
* Creates a fully-functional plugin directory with tests, samples, and documentation.
|
|
6
6
|
*/
|
|
7
|
-
import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
8
|
-
import { join } from 'node:path';
|
|
7
|
+
import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { join, dirname } from 'node:path';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
9
10
|
import chalk from 'chalk';
|
|
10
11
|
import prompts from 'prompts';
|
|
11
12
|
export function createExtractorCommand(program) {
|
|
@@ -14,6 +15,7 @@ export function createExtractorCommand(program) {
|
|
|
14
15
|
.description('Create a new extractor plugin from template')
|
|
15
16
|
.option('--description <desc>', 'Plugin description')
|
|
16
17
|
.option('--author <author>', 'Author name and email')
|
|
18
|
+
.option('--detection-pattern <pattern>', 'Detection keyword or pattern')
|
|
17
19
|
.option('--priority <number>', 'Detection priority (higher = check first)', '70')
|
|
18
20
|
.option('-f, --force', 'Overwrite existing plugin directory')
|
|
19
21
|
.action(async (name, options) => {
|
|
@@ -78,7 +80,7 @@ async function gatherContext(name, options) {
|
|
|
78
80
|
: '',
|
|
79
81
|
},
|
|
80
82
|
{
|
|
81
|
-
type: 'text',
|
|
83
|
+
type: options.detectionPattern ? null : 'text',
|
|
82
84
|
name: 'detectionPattern',
|
|
83
85
|
message: 'Detection keyword (e.g., "ERROR:", "[FAIL]"):',
|
|
84
86
|
validate: (value) => value.length > 0 || 'Detection keyword is required',
|
|
@@ -92,7 +94,7 @@ async function gatherContext(name, options) {
|
|
|
92
94
|
const pluginName = name ?? responses.pluginName;
|
|
93
95
|
const description = options.description ?? responses.description;
|
|
94
96
|
const author = options.author ?? responses.author ?? 'Unknown';
|
|
95
|
-
const detectionPattern = responses.detectionPattern;
|
|
97
|
+
const detectionPattern = options.detectionPattern ?? responses.detectionPattern;
|
|
96
98
|
const priority = typeof options.priority === 'number'
|
|
97
99
|
? options.priority
|
|
98
100
|
: Number.parseInt(options.priority ?? '70', 10);
|
|
@@ -538,10 +540,41 @@ If false positives/negatives occur:
|
|
|
538
540
|
4. Adjust hints or detection logic
|
|
539
541
|
`;
|
|
540
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Get CLI version from package.json
|
|
545
|
+
*/
|
|
546
|
+
function getCliVersion() {
|
|
547
|
+
try {
|
|
548
|
+
// Get the path to the CLI's package.json
|
|
549
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
550
|
+
const __dirname = dirname(__filename);
|
|
551
|
+
// Go up from dist/commands/ to package.json
|
|
552
|
+
const packageJsonPath = join(__dirname, '..', '..', 'package.json');
|
|
553
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
554
|
+
return packageJson.version;
|
|
555
|
+
}
|
|
556
|
+
catch {
|
|
557
|
+
// Fallback to a known version if reading fails
|
|
558
|
+
return '0.17.0';
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Get version range for package.json (e.g., "0.17.0-rc4" -> "^0.17.0-rc4")
|
|
563
|
+
*/
|
|
564
|
+
function getVersionRange(version) {
|
|
565
|
+
// For RC versions, use exact version to avoid issues
|
|
566
|
+
if (version.includes('-rc')) {
|
|
567
|
+
return version;
|
|
568
|
+
}
|
|
569
|
+
// For stable versions, use caret range
|
|
570
|
+
return `^${version}`;
|
|
571
|
+
}
|
|
541
572
|
/**
|
|
542
573
|
* Generate package.json
|
|
543
574
|
*/
|
|
544
575
|
function generatePackageJson(context) {
|
|
576
|
+
const cliVersion = getCliVersion();
|
|
577
|
+
const versionRange = getVersionRange(cliVersion);
|
|
545
578
|
return `{
|
|
546
579
|
"name": "vibe-validate-plugin-${context.pluginName}",
|
|
547
580
|
"version": "1.0.0",
|
|
@@ -568,11 +601,11 @@ function generatePackageJson(context) {
|
|
|
568
601
|
"author": "${context.author}",
|
|
569
602
|
"license": "MIT",
|
|
570
603
|
"peerDependencies": {
|
|
571
|
-
"@vibe-validate/extractors": "
|
|
604
|
+
"@vibe-validate/extractors": "${versionRange}"
|
|
572
605
|
},
|
|
573
606
|
"devDependencies": {
|
|
574
607
|
"@types/node": "^20.0.0",
|
|
575
|
-
"@vibe-validate/extractors": "
|
|
608
|
+
"@vibe-validate/extractors": "${versionRange}",
|
|
576
609
|
"typescript": "^5.3.0",
|
|
577
610
|
"vitest": "^2.0.0"
|
|
578
611
|
}
|
|
@@ -662,6 +695,7 @@ The \`create-extractor\` command generates a fully-functional extractor plugin d
|
|
|
662
695
|
- \`[name]\` - Plugin name (kebab-case, e.g., "my-tool")
|
|
663
696
|
- \`--description <desc>\` - Plugin description
|
|
664
697
|
- \`--author <author>\` - Author name and email
|
|
698
|
+
- \`--detection-pattern <pattern>\` - Detection keyword or pattern
|
|
665
699
|
- \`--priority <number>\` - Detection priority (default: 70)
|
|
666
700
|
- \`-f, --force\` - Overwrite existing plugin directory
|
|
667
701
|
|
|
@@ -694,6 +728,7 @@ vibe-validate create-extractor my-tool
|
|
|
694
728
|
vibe-validate create-extractor my-tool \\
|
|
695
729
|
--description "Extracts errors from my tool" \\
|
|
696
730
|
--author "John Doe <john@example.com>" \\
|
|
731
|
+
--detection-pattern "ERROR:" \\
|
|
697
732
|
--priority 70
|
|
698
733
|
|
|
699
734
|
# Overwrite existing plugin
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-extractor.js","sourceRoot":"","sources":["../../src/commands/create-extractor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"create-extractor.js","sourceRoot":"","sources":["../../src/commands/create-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,sCAAsC;IACtC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uCAAuC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAq2BD;;GAEG;AACH,wBAAsB,SAAS,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAyDlF;AAgED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsBpD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuH5C"}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { existsSync, readFileSync } from 'node:fs';
|
|
14
14
|
import { execSync } from 'node:child_process';
|
|
15
|
+
import * as semver from 'semver';
|
|
15
16
|
import { stringify as stringifyYaml } from 'yaml';
|
|
16
17
|
import { loadConfig, findConfigPath, loadConfigWithErrors } from '../utils/config-loader.js';
|
|
17
18
|
import { formatDoctorConfigError } from '../utils/config-error-reporter.js';
|
|
@@ -19,6 +20,8 @@ import { checkSync, ciConfigToWorkflowOptions } from './generate-workflow.js';
|
|
|
19
20
|
import { getMainBranch, getRemoteOrigin } from '@vibe-validate/config';
|
|
20
21
|
import { formatTemplateList } from '../utils/template-discovery.js';
|
|
21
22
|
import { checkHistoryHealth as checkValidationHistoryHealth } from '@vibe-validate/history';
|
|
23
|
+
import { detectSecretScanningTools, selectToolsToRun } from '../utils/secret-scanning.js';
|
|
24
|
+
import { executeGitCommand, isGitRepository, verifyRef } from '@vibe-validate/git';
|
|
22
25
|
/** @deprecated State file deprecated in v0.12.0 - validation now uses git notes */
|
|
23
26
|
const DEPRECATED_STATE_FILE = '.vibe-validate-state.yaml';
|
|
24
27
|
/**
|
|
@@ -54,10 +57,11 @@ function checkNodeVersion() {
|
|
|
54
57
|
*/
|
|
55
58
|
function checkGitInstalled() {
|
|
56
59
|
try {
|
|
57
|
-
const
|
|
60
|
+
const result = executeGitCommand(['--version']);
|
|
61
|
+
const version = result.success ? result.stdout.trim() : '';
|
|
58
62
|
return {
|
|
59
63
|
name: 'Git installed',
|
|
60
|
-
passed:
|
|
64
|
+
passed: result.success,
|
|
61
65
|
message: version,
|
|
62
66
|
};
|
|
63
67
|
}
|
|
@@ -76,19 +80,29 @@ function checkGitInstalled() {
|
|
|
76
80
|
*/
|
|
77
81
|
function checkGitRepository() {
|
|
78
82
|
try {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
const isGitRepo = isGitRepository();
|
|
84
|
+
if (isGitRepo) {
|
|
85
|
+
return {
|
|
86
|
+
name: 'Git repository',
|
|
87
|
+
passed: true,
|
|
88
|
+
message: 'Current directory is a git repository',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
return {
|
|
93
|
+
name: 'Git repository',
|
|
94
|
+
passed: false,
|
|
95
|
+
message: 'Current directory is not a git repository',
|
|
96
|
+
suggestion: 'Run: git init',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
100
|
catch (error) {
|
|
87
101
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
88
102
|
return {
|
|
89
103
|
name: 'Git repository',
|
|
90
104
|
passed: false,
|
|
91
|
-
message: `
|
|
105
|
+
message: `Error checking git repository: ${errorMessage}`,
|
|
92
106
|
suggestion: 'Run: git init',
|
|
93
107
|
};
|
|
94
108
|
}
|
|
@@ -336,6 +350,26 @@ async function checkPreCommitHook(config) {
|
|
|
336
350
|
};
|
|
337
351
|
}
|
|
338
352
|
}
|
|
353
|
+
/**
|
|
354
|
+
* Get context label for version display
|
|
355
|
+
*/
|
|
356
|
+
function getContextLabel(context) {
|
|
357
|
+
if (context === 'dev')
|
|
358
|
+
return ' (dev)';
|
|
359
|
+
if (context === 'local')
|
|
360
|
+
return ' (local)';
|
|
361
|
+
if (context === 'global')
|
|
362
|
+
return ' (global)';
|
|
363
|
+
return '';
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Get upgrade command based on context
|
|
367
|
+
*/
|
|
368
|
+
function getUpgradeCommand(context) {
|
|
369
|
+
return context === 'local'
|
|
370
|
+
? 'npm install -D vibe-validate@latest (or pnpm add -D vibe-validate@latest)'
|
|
371
|
+
: 'npm install -g vibe-validate@latest';
|
|
372
|
+
}
|
|
339
373
|
/**
|
|
340
374
|
* Check if vibe-validate version is up to date
|
|
341
375
|
*/
|
|
@@ -345,30 +379,24 @@ async function checkVersion() {
|
|
|
345
379
|
const packageJsonPath = new URL('../../package.json', import.meta.url);
|
|
346
380
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
347
381
|
const currentVersion = packageJson.version;
|
|
382
|
+
// Determine context (set by wrapper)
|
|
383
|
+
const context = process.env.VV_CONTEXT ?? 'unknown';
|
|
348
384
|
// Fetch latest version from npm registry
|
|
349
385
|
try {
|
|
350
386
|
const latestVersion = execSync('npm view vibe-validate version', {
|
|
351
387
|
encoding: 'utf8',
|
|
352
388
|
stdio: 'pipe',
|
|
353
389
|
}).trim();
|
|
354
|
-
// Compare versions
|
|
355
|
-
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
if (current[i] < latest[i]) {
|
|
360
|
-
isOutdated = true;
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
|
-
else if (current[i] > latest[i]) {
|
|
364
|
-
break; // Current is newer
|
|
365
|
-
}
|
|
366
|
-
}
|
|
390
|
+
// Compare versions using semver library (handles prereleases correctly)
|
|
391
|
+
// semver.lt() returns true if currentVersion < latestVersion
|
|
392
|
+
const isOutdated = semver.lt(currentVersion, latestVersion);
|
|
393
|
+
// Build context-aware message
|
|
394
|
+
const contextLabel = getContextLabel(context);
|
|
367
395
|
if (currentVersion === latestVersion) {
|
|
368
396
|
return {
|
|
369
397
|
name: 'vibe-validate version',
|
|
370
398
|
passed: true,
|
|
371
|
-
message: `Current
|
|
399
|
+
message: `Current: ${currentVersion}${contextLabel} — up to date with npm`,
|
|
372
400
|
};
|
|
373
401
|
}
|
|
374
402
|
else if (isOutdated) {
|
|
@@ -376,8 +404,8 @@ async function checkVersion() {
|
|
|
376
404
|
return {
|
|
377
405
|
name: 'vibe-validate version',
|
|
378
406
|
passed: true, // Warning only, not a failure
|
|
379
|
-
message: `Current: ${currentVersion}, Latest: ${latestVersion} available`,
|
|
380
|
-
suggestion: `Upgrade:
|
|
407
|
+
message: `Current: ${currentVersion}${contextLabel}, Latest: ${latestVersion} available`,
|
|
408
|
+
suggestion: `Upgrade: ${getUpgradeCommand(context)}\n 💡 After upgrade: Run 'vibe-validate doctor' to verify setup`,
|
|
381
409
|
};
|
|
382
410
|
}
|
|
383
411
|
else {
|
|
@@ -385,7 +413,7 @@ async function checkVersion() {
|
|
|
385
413
|
return {
|
|
386
414
|
name: 'vibe-validate version',
|
|
387
415
|
passed: true,
|
|
388
|
-
message: `Current: ${currentVersion} (ahead of npm: ${latestVersion})`,
|
|
416
|
+
message: `Current: ${currentVersion}${contextLabel} (ahead of npm: ${latestVersion})`,
|
|
389
417
|
};
|
|
390
418
|
}
|
|
391
419
|
}
|
|
@@ -480,41 +508,54 @@ function checkValidationState() {
|
|
|
480
508
|
}
|
|
481
509
|
}
|
|
482
510
|
/**
|
|
483
|
-
* Check for v0.15.0
|
|
511
|
+
* Check for old validation history format (pre-v0.15.0)
|
|
484
512
|
*
|
|
485
|
-
* v0.15.0
|
|
486
|
-
*
|
|
487
|
-
*
|
|
513
|
+
* Pre-v0.15.0 used refs under: refs/notes/vibe-validate/runs/*
|
|
514
|
+
* v0.15.0+ uses two systems:
|
|
515
|
+
* - Validation history: refs/notes/vibe-validate/validate (current format)
|
|
516
|
+
* - Run cache: refs/notes/vibe-validate/run/{treeHash}/{commandHash}
|
|
517
|
+
*
|
|
518
|
+
* Only warn if the OLD "runs" namespace exists.
|
|
488
519
|
*/
|
|
489
520
|
function checkCacheMigration() {
|
|
490
521
|
try {
|
|
491
|
-
// Check if
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
522
|
+
// Check if the EXACT old validation history ref exists (singular "runs", not "run/")
|
|
523
|
+
// Using git for-each-ref with exact ref name to avoid matching "run/" subdirectories
|
|
524
|
+
const result = executeGitCommand(['for-each-ref', '--format=%(refname)', 'refs/notes/vibe-validate/runs'], { ignoreErrors: true, suppressStderr: true });
|
|
525
|
+
if (result.success && result.stdout.trim() === 'refs/notes/vibe-validate/runs') {
|
|
526
|
+
// Old validation history namespace exists - automatically clean it up
|
|
527
|
+
try {
|
|
528
|
+
executeGitCommand(['update-ref', '-d', 'refs/notes/vibe-validate/runs']);
|
|
529
|
+
return {
|
|
530
|
+
name: 'Validation history migration',
|
|
531
|
+
passed: true,
|
|
532
|
+
message: 'Automatically removed old validation history format (pre-v0.15.0)',
|
|
533
|
+
};
|
|
534
|
+
// eslint-disable-next-line sonarjs/no-ignored-exceptions -- Auto-cleanup failure handled with manual suggestion
|
|
535
|
+
}
|
|
536
|
+
catch (_error) {
|
|
537
|
+
// Fallback to manual suggestion if auto-cleanup fails
|
|
538
|
+
return {
|
|
539
|
+
name: 'Validation history migration',
|
|
540
|
+
passed: true, // Not a failure, just informational
|
|
541
|
+
message: 'Old validation history format detected (pre-v0.15.0)',
|
|
542
|
+
suggestion: `Manual cleanup:\n git update-ref -d refs/notes/vibe-validate/runs\n ℹ️ This removes the deprecated "runs" namespace`,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
504
545
|
}
|
|
505
546
|
return {
|
|
506
|
-
name: '
|
|
547
|
+
name: 'Validation history migration',
|
|
507
548
|
passed: true,
|
|
508
|
-
message: '
|
|
549
|
+
message: 'Using current validation history format',
|
|
509
550
|
};
|
|
510
551
|
// eslint-disable-next-line sonarjs/no-ignored-exceptions -- Git command failure is non-critical for migration check
|
|
511
552
|
}
|
|
512
553
|
catch (_error) {
|
|
513
554
|
// Git command failed or no git notes - that's fine
|
|
514
555
|
return {
|
|
515
|
-
name: '
|
|
556
|
+
name: 'Validation history migration',
|
|
516
557
|
passed: true,
|
|
517
|
-
message: 'No
|
|
558
|
+
message: 'No validation history to migrate',
|
|
518
559
|
};
|
|
519
560
|
}
|
|
520
561
|
}
|
|
@@ -564,35 +605,29 @@ async function checkMainBranch(config) {
|
|
|
564
605
|
const mainBranch = getMainBranch(config.git);
|
|
565
606
|
const remoteOrigin = getRemoteOrigin(config.git);
|
|
566
607
|
// Check for local branch first
|
|
567
|
-
|
|
568
|
-
|
|
608
|
+
const localResult = verifyRef(mainBranch);
|
|
609
|
+
if (localResult) {
|
|
569
610
|
return {
|
|
570
611
|
name: 'Git main branch',
|
|
571
612
|
passed: true,
|
|
572
613
|
message: `Branch '${mainBranch}' exists locally`,
|
|
573
614
|
};
|
|
574
615
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
message: `Branch '${mainBranch}' exists on remote '${remoteOrigin}' (fetch-depth: 0 required in CI)`,
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
catch (remoteError) {
|
|
587
|
-
const remoteErrorMsg = remoteError instanceof Error ? remoteError.message : String(remoteError);
|
|
588
|
-
return {
|
|
589
|
-
name: 'Git main branch',
|
|
590
|
-
passed: false,
|
|
591
|
-
message: `Configured main branch '${mainBranch}' does not exist locally (${localErrorMsg}) or on remote '${remoteOrigin}' (${remoteErrorMsg})`,
|
|
592
|
-
suggestion: `Create branch: git checkout -b ${mainBranch} OR update config to use existing branch (e.g., 'master', 'develop')`,
|
|
593
|
-
};
|
|
594
|
-
}
|
|
616
|
+
// Local branch doesn't exist, check for remote branch
|
|
617
|
+
const remoteResult = verifyRef(`${remoteOrigin}/${mainBranch}`);
|
|
618
|
+
if (remoteResult) {
|
|
619
|
+
return {
|
|
620
|
+
name: 'Git main branch',
|
|
621
|
+
passed: true,
|
|
622
|
+
message: `Branch '${mainBranch}' exists on remote '${remoteOrigin}' (fetch-depth: 0 required in CI)`,
|
|
623
|
+
};
|
|
595
624
|
}
|
|
625
|
+
return {
|
|
626
|
+
name: 'Git main branch',
|
|
627
|
+
passed: false,
|
|
628
|
+
message: `Configured main branch '${mainBranch}' does not exist locally or on remote '${remoteOrigin}'`,
|
|
629
|
+
suggestion: `Create branch: git checkout -b ${mainBranch} OR update config to use existing branch (e.g., 'master', 'develop')`,
|
|
630
|
+
};
|
|
596
631
|
}
|
|
597
632
|
catch (error) {
|
|
598
633
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -617,10 +652,10 @@ async function checkRemoteOrigin(config) {
|
|
|
617
652
|
}
|
|
618
653
|
const remoteOrigin = getRemoteOrigin(config.git);
|
|
619
654
|
try {
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
.split('\n')
|
|
623
|
-
|
|
655
|
+
const result = executeGitCommand(['remote']);
|
|
656
|
+
const remotes = result.success
|
|
657
|
+
? result.stdout.trim().split('\n').filter(Boolean)
|
|
658
|
+
: [];
|
|
624
659
|
if (remotes.includes(remoteOrigin)) {
|
|
625
660
|
return {
|
|
626
661
|
name: 'Git remote origin',
|
|
@@ -673,10 +708,10 @@ async function checkRemoteMainBranch(config) {
|
|
|
673
708
|
const remoteOrigin = getRemoteOrigin(config.git);
|
|
674
709
|
try {
|
|
675
710
|
// First check if remote exists
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
.split('\n')
|
|
679
|
-
|
|
711
|
+
const remotesResult = executeGitCommand(['remote']);
|
|
712
|
+
const remotes = remotesResult.success
|
|
713
|
+
? remotesResult.stdout.trim().split('\n').filter(Boolean)
|
|
714
|
+
: [];
|
|
680
715
|
if (!remotes.includes(remoteOrigin)) {
|
|
681
716
|
return {
|
|
682
717
|
name: 'Git remote main branch',
|
|
@@ -685,7 +720,10 @@ async function checkRemoteMainBranch(config) {
|
|
|
685
720
|
};
|
|
686
721
|
}
|
|
687
722
|
// Check if remote branch exists
|
|
688
|
-
|
|
723
|
+
const lsRemoteResult = executeGitCommand(['ls-remote', '--heads', remoteOrigin, mainBranch]);
|
|
724
|
+
if (!lsRemoteResult.success) {
|
|
725
|
+
throw new Error(`Failed to check remote branch: ${lsRemoteResult.stderr}`);
|
|
726
|
+
}
|
|
689
727
|
return {
|
|
690
728
|
name: 'Git remote main branch',
|
|
691
729
|
passed: true,
|
|
@@ -711,48 +749,6 @@ async function checkRemoteMainBranch(config) {
|
|
|
711
749
|
};
|
|
712
750
|
}
|
|
713
751
|
}
|
|
714
|
-
/**
|
|
715
|
-
* Get tool version by trying multiple version flag variants
|
|
716
|
-
*/
|
|
717
|
-
function getToolVersion(toolName) {
|
|
718
|
-
try {
|
|
719
|
-
return execSync(`${toolName} version`, { encoding: 'utf8', stdio: 'pipe' }).trim();
|
|
720
|
-
}
|
|
721
|
-
catch {
|
|
722
|
-
// Fallback to --version flag
|
|
723
|
-
return execSync(`${toolName} --version`, { encoding: 'utf8', stdio: 'pipe' }).trim();
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Check if scanning tool is available
|
|
728
|
-
*/
|
|
729
|
-
function checkScanningToolAvailable(toolName) {
|
|
730
|
-
try {
|
|
731
|
-
const version = getToolVersion(toolName);
|
|
732
|
-
return {
|
|
733
|
-
name: 'Pre-commit secret scanning',
|
|
734
|
-
passed: true,
|
|
735
|
-
message: `Secret scanning enabled with ${toolName} ${version}`,
|
|
736
|
-
};
|
|
737
|
-
}
|
|
738
|
-
catch (error) {
|
|
739
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
740
|
-
const isCI = process.env.CI === 'true' || process.env.CI === '1';
|
|
741
|
-
if (isCI) {
|
|
742
|
-
return {
|
|
743
|
-
name: 'Pre-commit secret scanning',
|
|
744
|
-
passed: true,
|
|
745
|
-
message: `Secret scanning enabled (pre-commit only, not needed in CI)`,
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
return {
|
|
749
|
-
name: 'Pre-commit secret scanning',
|
|
750
|
-
passed: true,
|
|
751
|
-
message: `Secret scanning enabled but '${toolName}' not found: ${errorMessage}`,
|
|
752
|
-
suggestion: `Install ${toolName}:\n • gitleaks: brew install gitleaks\n • Or disable: set hooks.preCommit.secretScanning.enabled=false in config`,
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
752
|
/**
|
|
757
753
|
* Check if secret scanning is configured and tool is available
|
|
758
754
|
*/
|
|
@@ -771,7 +767,7 @@ async function checkSecretScanning(config) {
|
|
|
771
767
|
name: 'Pre-commit secret scanning',
|
|
772
768
|
passed: true,
|
|
773
769
|
message: 'Secret scanning not configured',
|
|
774
|
-
suggestion: 'Recommended: Enable secret scanning to prevent credential leaks\n • Add to config: hooks.preCommit.secretScanning.enabled=true\n •
|
|
770
|
+
suggestion: 'Recommended: Enable secret scanning to prevent credential leaks\n • Add to config: hooks.preCommit.secretScanning.enabled=true\n • Install gitleaks: brew install gitleaks\n • Or add .secretlintrc.json for npm-based scanning',
|
|
775
771
|
};
|
|
776
772
|
}
|
|
777
773
|
if (secretScanning.enabled === false) {
|
|
@@ -781,16 +777,66 @@ async function checkSecretScanning(config) {
|
|
|
781
777
|
message: 'Secret scanning disabled in config (user preference)',
|
|
782
778
|
};
|
|
783
779
|
}
|
|
784
|
-
|
|
780
|
+
// Detect available tools and what would be run
|
|
781
|
+
const toolsToRun = selectToolsToRun(secretScanning.scanCommand);
|
|
782
|
+
const availableTools = detectSecretScanningTools();
|
|
783
|
+
if (toolsToRun.length === 0) {
|
|
785
784
|
return {
|
|
786
785
|
name: 'Pre-commit secret scanning',
|
|
787
786
|
passed: true,
|
|
788
|
-
message: 'Secret scanning enabled but no
|
|
789
|
-
suggestion: '
|
|
787
|
+
message: 'Secret scanning enabled but no tools available',
|
|
788
|
+
suggestion: 'Install a secret scanning tool:\n • gitleaks: brew install gitleaks\n • secretlint: npm install --save-dev @secretlint/secretlint-rule-preset-recommend\n • Or add config files: .gitleaks.toml or .secretlintrc.json',
|
|
790
789
|
};
|
|
791
790
|
}
|
|
792
|
-
|
|
793
|
-
|
|
791
|
+
// Build status message
|
|
792
|
+
const toolStatuses = availableTools.map(tool => {
|
|
793
|
+
if (tool.tool === 'gitleaks') {
|
|
794
|
+
if (tool.available && tool.hasConfig) {
|
|
795
|
+
return 'gitleaks (configured, available)';
|
|
796
|
+
}
|
|
797
|
+
else if (tool.available) {
|
|
798
|
+
return 'gitleaks (available, no config)';
|
|
799
|
+
}
|
|
800
|
+
else if (tool.hasConfig) {
|
|
801
|
+
return 'gitleaks (configured, NOT available)';
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
else if (tool.tool === 'secretlint') {
|
|
805
|
+
if (tool.hasConfig) {
|
|
806
|
+
return 'secretlint (configured, via npx)';
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
return 'secretlint (available via npx, no config)';
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return null;
|
|
813
|
+
}).filter(Boolean);
|
|
814
|
+
const message = `Secret scanning enabled: ${toolStatuses.join(', ')}`;
|
|
815
|
+
// Check if gitleaks is configured but not available
|
|
816
|
+
const gitleaks = availableTools.find(t => t.tool === 'gitleaks');
|
|
817
|
+
if (gitleaks?.hasConfig && !gitleaks.available) {
|
|
818
|
+
return {
|
|
819
|
+
name: 'Pre-commit secret scanning',
|
|
820
|
+
passed: true,
|
|
821
|
+
message,
|
|
822
|
+
suggestion: 'Install gitleaks for better performance: brew install gitleaks',
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
// Check if only secretlint is available (suggest gitleaks for performance)
|
|
826
|
+
const hasGitleaksAvailable = availableTools.some(t => t.tool === 'gitleaks' && t.available);
|
|
827
|
+
if (!hasGitleaksAvailable && toolsToRun.some(t => t.tool === 'secretlint')) {
|
|
828
|
+
return {
|
|
829
|
+
name: 'Pre-commit secret scanning',
|
|
830
|
+
passed: true,
|
|
831
|
+
message,
|
|
832
|
+
suggestion: 'Consider installing gitleaks for faster scanning: brew install gitleaks',
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
return {
|
|
836
|
+
name: 'Pre-commit secret scanning',
|
|
837
|
+
passed: true,
|
|
838
|
+
message,
|
|
839
|
+
};
|
|
794
840
|
}
|
|
795
841
|
catch (error) {
|
|
796
842
|
const errorMessage = error instanceof Error ? error.message : String(error);
|