@danielszlaski/envguard 0.1.4 → 0.1.5

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/README.md CHANGED
@@ -44,6 +44,43 @@ npx @danielszlaski/envguard scan
44
44
 
45
45
  > **Note:** The examples below use `envguard` (short form), which works after installation. If using npx without installation, use `npx @danielszlaski/envguard` instead.
46
46
 
47
+ ### Git Hook Integration (Pre-commit/Pre-push)
48
+
49
+ Automatically run envguard before every commit or push to catch environment variable issues early:
50
+
51
+ ```bash
52
+ # Install a pre-commit hook (runs before each commit)
53
+ envguard install-hook
54
+
55
+ # Or install a pre-push hook (runs before each push)
56
+ envguard install-hook --type pre-push
57
+
58
+ # Force overwrite existing hook
59
+ envguard install-hook --force
60
+ ```
61
+
62
+ Once installed, the hook will automatically run `envguard check` before each commit (or push). If issues are found, the commit/push will be blocked until you fix them.
63
+
64
+ **Bypass the hook** when needed:
65
+ ```bash
66
+ git commit --no-verify
67
+ git push --no-verify
68
+ ```
69
+
70
+ **Remove the hook:**
71
+ ```bash
72
+ envguard uninstall-hook
73
+
74
+ # Or for pre-push hook
75
+ envguard uninstall-hook --type pre-push
76
+ ```
77
+
78
+ **How it works:**
79
+ - The hook creates a script in `.git/hooks/pre-commit` (or `pre-push`)
80
+ - Before each commit/push, it runs `envguard check`
81
+ - If issues are found, the operation is blocked
82
+ - Team members need to install the hook individually (it's not tracked in git)
83
+
47
84
  ### Scan for issues
48
85
 
49
86
  ```bash
@@ -514,6 +551,11 @@ Checking src/lambda/serverless.yml
514
551
  - `envguard check` - Alias for `scan --ci`
515
552
  - `envguard check --strict` - Check with strict mode enabled
516
553
  - `envguard check --no-detect-fallbacks` - Check without fallback detection
554
+ - `envguard install-hook` - Install a Git pre-commit hook to run checks automatically
555
+ - `envguard install-hook --type pre-push` - Install a pre-push hook instead
556
+ - `envguard install-hook --force` - Overwrite existing hook if present
557
+ - `envguard uninstall-hook` - Remove the envguard Git hook
558
+ - `envguard uninstall-hook --type pre-push` - Remove the pre-push hook
517
559
 
518
560
  ### Strict Mode
519
561
 
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const commander_1 = require("commander");
5
5
  const scan_1 = require("./commands/scan");
6
6
  const fix_1 = require("./commands/fix");
7
+ const install_hook_1 = require("./commands/install-hook");
7
8
  const logger_1 = require("./utils/logger");
8
9
  const program = new commander_1.Command();
9
10
  program
@@ -71,5 +72,37 @@ program
71
72
  process.exit(1);
72
73
  }
73
74
  });
75
+ program
76
+ .command('install-hook')
77
+ .description('Install a Git hook to run envguard automatically')
78
+ .option('--type <type>', 'Hook type: pre-commit or pre-push (default: pre-commit)')
79
+ .option('--force', 'Overwrite existing hook if present')
80
+ .action(async (cmd) => {
81
+ try {
82
+ await (0, install_hook_1.installHookCommand)({
83
+ type: cmd.type,
84
+ force: cmd.force
85
+ });
86
+ }
87
+ catch (error) {
88
+ logger_1.Logger.error(`${error}`);
89
+ process.exit(1);
90
+ }
91
+ });
92
+ program
93
+ .command('uninstall-hook')
94
+ .description('Remove the envguard Git hook')
95
+ .option('--type <type>', 'Hook type: pre-commit or pre-push (default: pre-commit)')
96
+ .action(async (cmd) => {
97
+ try {
98
+ await (0, install_hook_1.uninstallHookCommand)({
99
+ type: cmd.type
100
+ });
101
+ }
102
+ catch (error) {
103
+ logger_1.Logger.error(`${error}`);
104
+ process.exit(1);
105
+ }
106
+ });
74
107
  program.parse();
75
108
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ declare const HOOK_TYPES: readonly ["pre-commit", "pre-push"];
2
+ type HookType = typeof HOOK_TYPES[number];
3
+ interface InstallHookOptions {
4
+ type?: HookType;
5
+ force?: boolean;
6
+ }
7
+ /**
8
+ * Install a Git hook that runs envguard before commits or pushes
9
+ */
10
+ export declare function installHookCommand(options?: InstallHookOptions): Promise<void>;
11
+ /**
12
+ * Uninstall a Git hook
13
+ */
14
+ export declare function uninstallHookCommand(options?: {
15
+ type?: HookType;
16
+ }): Promise<void>;
17
+ export {};
18
+ //# sourceMappingURL=install-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hook.d.ts","sourceRoot":"","sources":["../../src/commands/install-hook.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,UAAU,qCAAsC,CAAC;AACvD,KAAK,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAE1C,UAAU,kBAAkB;IAC1B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,kBAAuB,iBA8CxE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,QAAQ,CAAA;CAAO,iBA6B3E"}
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.installHookCommand = installHookCommand;
37
+ exports.uninstallHookCommand = uninstallHookCommand;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const logger_1 = require("../utils/logger");
41
+ const HOOK_TYPES = ['pre-commit', 'pre-push'];
42
+ /**
43
+ * Install a Git hook that runs envguard before commits or pushes
44
+ */
45
+ async function installHookCommand(options = {}) {
46
+ const rootDir = process.cwd();
47
+ const gitDir = path.join(rootDir, '.git');
48
+ const hooksDir = path.join(gitDir, 'hooks');
49
+ // Check if this is a git repository
50
+ if (!fs.existsSync(gitDir)) {
51
+ logger_1.Logger.error('Not a git repository. Please run this command in a git repository.');
52
+ logger_1.Logger.blank();
53
+ process.exit(1);
54
+ }
55
+ // Ensure hooks directory exists
56
+ if (!fs.existsSync(hooksDir)) {
57
+ fs.mkdirSync(hooksDir, { recursive: true });
58
+ logger_1.Logger.success('Created .git/hooks directory');
59
+ }
60
+ const hookType = options.type || 'pre-commit';
61
+ const hookPath = path.join(hooksDir, hookType);
62
+ // Check if hook already exists
63
+ if (fs.existsSync(hookPath) && !options.force) {
64
+ logger_1.Logger.warning(`${hookType} hook already exists.`);
65
+ logger_1.Logger.info('Use --force to overwrite the existing hook', true);
66
+ logger_1.Logger.blank();
67
+ process.exit(1);
68
+ }
69
+ // Create the hook script
70
+ const hookContent = generateHookScript(hookType);
71
+ try {
72
+ fs.writeFileSync(hookPath, hookContent, { mode: 0o755 });
73
+ logger_1.Logger.success(`Installed ${hookType} hook successfully!`);
74
+ logger_1.Logger.blank();
75
+ logger_1.Logger.info('The hook will run `envguard check` automatically before each ' +
76
+ (hookType === 'pre-commit' ? 'commit' : 'push'), true);
77
+ logger_1.Logger.info('To bypass the hook, use: git ' +
78
+ (hookType === 'pre-commit' ? 'commit' : 'push') + ' --no-verify', true);
79
+ logger_1.Logger.blank();
80
+ }
81
+ catch (error) {
82
+ logger_1.Logger.error(`Failed to install hook: ${error}`);
83
+ logger_1.Logger.blank();
84
+ process.exit(1);
85
+ }
86
+ }
87
+ /**
88
+ * Uninstall a Git hook
89
+ */
90
+ async function uninstallHookCommand(options = {}) {
91
+ const rootDir = process.cwd();
92
+ const hookType = options.type || 'pre-commit';
93
+ const hookPath = path.join(rootDir, '.git', 'hooks', hookType);
94
+ if (!fs.existsSync(hookPath)) {
95
+ logger_1.Logger.warning(`No ${hookType} hook found.`);
96
+ logger_1.Logger.blank();
97
+ return;
98
+ }
99
+ // Check if it's our hook
100
+ const hookContent = fs.readFileSync(hookPath, 'utf-8');
101
+ if (!hookContent.includes('envguard check')) {
102
+ logger_1.Logger.warning(`The ${hookType} hook exists but was not created by envguard.`);
103
+ logger_1.Logger.info('Manual removal required if you want to delete it.', true);
104
+ logger_1.Logger.blank();
105
+ return;
106
+ }
107
+ try {
108
+ fs.unlinkSync(hookPath);
109
+ logger_1.Logger.success(`Removed ${hookType} hook successfully!`);
110
+ logger_1.Logger.blank();
111
+ }
112
+ catch (error) {
113
+ logger_1.Logger.error(`Failed to remove hook: ${error}`);
114
+ logger_1.Logger.blank();
115
+ process.exit(1);
116
+ }
117
+ }
118
+ /**
119
+ * Generate the hook script content
120
+ */
121
+ function generateHookScript(hookType) {
122
+ const hookMessage = hookType === 'pre-commit' ? 'commit' : 'push';
123
+ return `#!/bin/sh
124
+ # EnvGuard ${hookType} hook
125
+ # This hook runs envguard to check environment variables before ${hookMessage}
126
+ # To bypass this hook, use: git ${hookMessage} --no-verify
127
+
128
+ echo "Running EnvGuard environment variable check..."
129
+
130
+ # Run envguard check
131
+ npx envguard check
132
+
133
+ # Capture the exit code
134
+ EXIT_CODE=$?
135
+
136
+ if [ $EXIT_CODE -ne 0 ]; then
137
+ echo ""
138
+ echo "❌ EnvGuard check failed. Please fix the issues above before ${hookMessage}ing."
139
+ echo " Or run: git ${hookMessage} --no-verify to bypass this check."
140
+ echo ""
141
+ exit 1
142
+ fi
143
+
144
+ echo "✓ EnvGuard check passed!"
145
+ exit 0
146
+ `;
147
+ }
148
+ //# sourceMappingURL=install-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hook.js","sourceRoot":"","sources":["../../src/commands/install-hook.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielszlaski/envguard",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tool to keep environment variables in sync with your codebase",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -4,6 +4,7 @@ import { Command } from 'commander';
4
4
  import { scanCommand } from './commands/scan';
5
5
  import { fixCommand } from './commands/fix';
6
6
  import { checkCommand } from './commands/check';
7
+ import { installHookCommand, uninstallHookCommand } from './commands/install-hook';
7
8
  import { Logger } from './utils/logger';
8
9
 
9
10
  const program = new Command();
@@ -78,4 +79,36 @@ program
78
79
  }
79
80
  });
80
81
 
82
+ program
83
+ .command('install-hook')
84
+ .description('Install a Git hook to run envguard automatically')
85
+ .option('--type <type>', 'Hook type: pre-commit or pre-push (default: pre-commit)')
86
+ .option('--force', 'Overwrite existing hook if present')
87
+ .action(async (cmd) => {
88
+ try {
89
+ await installHookCommand({
90
+ type: cmd.type,
91
+ force: cmd.force
92
+ });
93
+ } catch (error) {
94
+ Logger.error(`${error}`);
95
+ process.exit(1);
96
+ }
97
+ });
98
+
99
+ program
100
+ .command('uninstall-hook')
101
+ .description('Remove the envguard Git hook')
102
+ .option('--type <type>', 'Hook type: pre-commit or pre-push (default: pre-commit)')
103
+ .action(async (cmd) => {
104
+ try {
105
+ await uninstallHookCommand({
106
+ type: cmd.type
107
+ });
108
+ } catch (error) {
109
+ Logger.error(`${error}`);
110
+ process.exit(1);
111
+ }
112
+ });
113
+
81
114
  program.parse();
@@ -0,0 +1,128 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { Logger } from '../utils/logger';
4
+
5
+ const HOOK_TYPES = ['pre-commit', 'pre-push'] as const;
6
+ type HookType = typeof HOOK_TYPES[number];
7
+
8
+ interface InstallHookOptions {
9
+ type?: HookType;
10
+ force?: boolean;
11
+ }
12
+
13
+ /**
14
+ * Install a Git hook that runs envguard before commits or pushes
15
+ */
16
+ export async function installHookCommand(options: InstallHookOptions = {}) {
17
+ const rootDir = process.cwd();
18
+ const gitDir = path.join(rootDir, '.git');
19
+ const hooksDir = path.join(gitDir, 'hooks');
20
+
21
+ // Check if this is a git repository
22
+ if (!fs.existsSync(gitDir)) {
23
+ Logger.error('Not a git repository. Please run this command in a git repository.');
24
+ Logger.blank();
25
+ process.exit(1);
26
+ }
27
+
28
+ // Ensure hooks directory exists
29
+ if (!fs.existsSync(hooksDir)) {
30
+ fs.mkdirSync(hooksDir, { recursive: true });
31
+ Logger.success('Created .git/hooks directory');
32
+ }
33
+
34
+ const hookType = options.type || 'pre-commit';
35
+ const hookPath = path.join(hooksDir, hookType);
36
+
37
+ // Check if hook already exists
38
+ if (fs.existsSync(hookPath) && !options.force) {
39
+ Logger.warning(`${hookType} hook already exists.`);
40
+ Logger.info('Use --force to overwrite the existing hook', true);
41
+ Logger.blank();
42
+ process.exit(1);
43
+ }
44
+
45
+ // Create the hook script
46
+ const hookContent = generateHookScript(hookType);
47
+
48
+ try {
49
+ fs.writeFileSync(hookPath, hookContent, { mode: 0o755 });
50
+ Logger.success(`Installed ${hookType} hook successfully!`);
51
+ Logger.blank();
52
+ Logger.info('The hook will run `envguard check` automatically before each ' +
53
+ (hookType === 'pre-commit' ? 'commit' : 'push'), true);
54
+ Logger.info('To bypass the hook, use: git ' +
55
+ (hookType === 'pre-commit' ? 'commit' : 'push') + ' --no-verify', true);
56
+ Logger.blank();
57
+ } catch (error) {
58
+ Logger.error(`Failed to install hook: ${error}`);
59
+ Logger.blank();
60
+ process.exit(1);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Uninstall a Git hook
66
+ */
67
+ export async function uninstallHookCommand(options: { type?: HookType } = {}) {
68
+ const rootDir = process.cwd();
69
+ const hookType = options.type || 'pre-commit';
70
+ const hookPath = path.join(rootDir, '.git', 'hooks', hookType);
71
+
72
+ if (!fs.existsSync(hookPath)) {
73
+ Logger.warning(`No ${hookType} hook found.`);
74
+ Logger.blank();
75
+ return;
76
+ }
77
+
78
+ // Check if it's our hook
79
+ const hookContent = fs.readFileSync(hookPath, 'utf-8');
80
+ if (!hookContent.includes('envguard check')) {
81
+ Logger.warning(`The ${hookType} hook exists but was not created by envguard.`);
82
+ Logger.info('Manual removal required if you want to delete it.', true);
83
+ Logger.blank();
84
+ return;
85
+ }
86
+
87
+ try {
88
+ fs.unlinkSync(hookPath);
89
+ Logger.success(`Removed ${hookType} hook successfully!`);
90
+ Logger.blank();
91
+ } catch (error) {
92
+ Logger.error(`Failed to remove hook: ${error}`);
93
+ Logger.blank();
94
+ process.exit(1);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Generate the hook script content
100
+ */
101
+ function generateHookScript(hookType: HookType): string {
102
+ const hookMessage = hookType === 'pre-commit' ? 'commit' : 'push';
103
+
104
+ return `#!/bin/sh
105
+ # EnvGuard ${hookType} hook
106
+ # This hook runs envguard to check environment variables before ${hookMessage}
107
+ # To bypass this hook, use: git ${hookMessage} --no-verify
108
+
109
+ echo "Running EnvGuard environment variable check..."
110
+
111
+ # Run envguard check
112
+ npx envguard check
113
+
114
+ # Capture the exit code
115
+ EXIT_CODE=$?
116
+
117
+ if [ $EXIT_CODE -ne 0 ]; then
118
+ echo ""
119
+ echo "❌ EnvGuard check failed. Please fix the issues above before ${hookMessage}ing."
120
+ echo " Or run: git ${hookMessage} --no-verify to bypass this check."
121
+ echo ""
122
+ exit 1
123
+ fi
124
+
125
+ echo "✓ EnvGuard check passed!"
126
+ exit 0
127
+ `;
128
+ }