@chriscode/hush 2.0.0 → 2.2.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/dist/cli.js +81 -14
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +77 -0
- package/dist/commands/set.d.ts +3 -0
- package/dist/commands/set.d.ts.map +1 -0
- package/dist/commands/set.js +87 -0
- package/dist/commands/skill.d.ts +3 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +1077 -0
- package/dist/core/sops.d.ts +5 -0
- package/dist/core/sops.d.ts.map +1 -1
- package/dist/core/sops.js +49 -1
- package/dist/formats/index.d.ts +2 -1
- package/dist/formats/index.d.ts.map +1 -1
- package/dist/formats/index.js +4 -1
- package/dist/formats/yaml.d.ts +13 -0
- package/dist/formats/yaml.d.ts.map +1 -0
- package/dist/formats/yaml.js +50 -0
- package/dist/types.d.ts +19 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -0
- package/package.json +1 -1
package/dist/core/sops.d.ts
CHANGED
|
@@ -3,4 +3,9 @@ export declare function isAgeKeyConfigured(): boolean;
|
|
|
3
3
|
export declare function decrypt(filePath: string): string;
|
|
4
4
|
export declare function encrypt(inputPath: string, outputPath: string): void;
|
|
5
5
|
export declare function edit(filePath: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Set a single key in an encrypted file.
|
|
8
|
+
* Decrypts to memory, updates the key, re-encrypts.
|
|
9
|
+
*/
|
|
10
|
+
export declare function setKey(filePath: string, key: string, value: string): void;
|
|
6
11
|
//# sourceMappingURL=sops.d.ts.map
|
package/dist/core/sops.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sops.d.ts","sourceRoot":"","sources":["../../src/core/sops.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sops.d.ts","sourceRoot":"","sources":["../../src/core/sops.ts"],"names":[],"mappings":"AA0BA,wBAAgB,eAAe,IAAI,OAAO,CAOzC;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA6BhD;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAuBnE;AAED,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAqB3C;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAqDzE"}
|
package/dist/core/sops.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execSync, spawnSync } from 'node:child_process';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
2
|
+
import { existsSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
4
5
|
function getAgeKeyFile() {
|
|
5
6
|
if (process.env.SOPS_AGE_KEY_FILE) {
|
|
6
7
|
return process.env.SOPS_AGE_KEY_FILE;
|
|
@@ -89,3 +90,50 @@ export function edit(filePath) {
|
|
|
89
90
|
throw new Error(`SOPS edit failed with exit code ${result.status}`);
|
|
90
91
|
}
|
|
91
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Set a single key in an encrypted file.
|
|
95
|
+
* Decrypts to memory, updates the key, re-encrypts.
|
|
96
|
+
*/
|
|
97
|
+
export function setKey(filePath, key, value) {
|
|
98
|
+
if (!isSopsInstalled()) {
|
|
99
|
+
throw new Error('SOPS is not installed. Install with: brew install sops');
|
|
100
|
+
}
|
|
101
|
+
let content = '';
|
|
102
|
+
// If file exists, decrypt it first
|
|
103
|
+
if (existsSync(filePath)) {
|
|
104
|
+
content = decrypt(filePath);
|
|
105
|
+
}
|
|
106
|
+
// Parse existing content into lines
|
|
107
|
+
const lines = content.split('\n').filter(line => line.trim() !== '');
|
|
108
|
+
// Find and update or add the key
|
|
109
|
+
let found = false;
|
|
110
|
+
const updatedLines = lines.map(line => {
|
|
111
|
+
const match = line.match(/^([^=]+)=/);
|
|
112
|
+
if (match && match[1] === key) {
|
|
113
|
+
found = true;
|
|
114
|
+
return `${key}=${value}`;
|
|
115
|
+
}
|
|
116
|
+
return line;
|
|
117
|
+
});
|
|
118
|
+
if (!found) {
|
|
119
|
+
updatedLines.push(`${key}=${value}`);
|
|
120
|
+
}
|
|
121
|
+
const newContent = updatedLines.join('\n') + '\n';
|
|
122
|
+
const tempFile = join(tmpdir(), `hush-temp-${Date.now()}.env`);
|
|
123
|
+
try {
|
|
124
|
+
writeFileSync(tempFile, newContent, 'utf-8');
|
|
125
|
+
// Encrypt temp file to the target
|
|
126
|
+
execSync(`sops --input-type dotenv --output-type dotenv --encrypt "${tempFile}" > "${filePath}"`, {
|
|
127
|
+
encoding: 'utf-8',
|
|
128
|
+
shell: '/bin/bash',
|
|
129
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
130
|
+
env: getSopsEnv(),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
// Always clean up temp file
|
|
135
|
+
if (existsSync(tempFile)) {
|
|
136
|
+
unlinkSync(tempFile);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
package/dist/formats/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { formatDotenv } from './dotenv.js';
|
|
|
3
3
|
import { formatJson } from './json.js';
|
|
4
4
|
import { formatShell } from './shell.js';
|
|
5
5
|
import { formatWrangler } from './wrangler.js';
|
|
6
|
+
import { formatYaml } from './yaml.js';
|
|
6
7
|
export declare function formatVars(vars: EnvVar[], format: OutputFormat): string;
|
|
7
|
-
export { formatDotenv, formatJson, formatShell, formatWrangler };
|
|
8
|
+
export { formatDotenv, formatJson, formatShell, formatWrangler, formatYaml };
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formats/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formats/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAavE;AAED,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/formats/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { formatDotenv } from './dotenv.js';
|
|
|
2
2
|
import { formatJson } from './json.js';
|
|
3
3
|
import { formatShell } from './shell.js';
|
|
4
4
|
import { formatWrangler } from './wrangler.js';
|
|
5
|
+
import { formatYaml } from './yaml.js';
|
|
5
6
|
export function formatVars(vars, format) {
|
|
6
7
|
switch (format) {
|
|
7
8
|
case 'dotenv':
|
|
@@ -12,6 +13,8 @@ export function formatVars(vars, format) {
|
|
|
12
13
|
return formatJson(vars);
|
|
13
14
|
case 'shell':
|
|
14
15
|
return formatShell(vars);
|
|
16
|
+
case 'yaml':
|
|
17
|
+
return formatYaml(vars);
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
|
-
export { formatDotenv, formatJson, formatShell, formatWrangler };
|
|
20
|
+
export { formatDotenv, formatJson, formatShell, formatWrangler, formatYaml };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EnvVar } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Format environment variables as YAML.
|
|
4
|
+
* Useful for Kubernetes ConfigMaps, Docker Compose, and other YAML-based configs.
|
|
5
|
+
*
|
|
6
|
+
* Output format:
|
|
7
|
+
* ```yaml
|
|
8
|
+
* DATABASE_URL: "postgres://localhost/db"
|
|
9
|
+
* API_KEY: "sk_test_xxx"
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatYaml(vars: EnvVar[]): string;
|
|
13
|
+
//# sourceMappingURL=yaml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../../src/formats/yaml.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CA6CjD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format environment variables as YAML.
|
|
3
|
+
* Useful for Kubernetes ConfigMaps, Docker Compose, and other YAML-based configs.
|
|
4
|
+
*
|
|
5
|
+
* Output format:
|
|
6
|
+
* ```yaml
|
|
7
|
+
* DATABASE_URL: "postgres://localhost/db"
|
|
8
|
+
* API_KEY: "sk_test_xxx"
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export function formatYaml(vars) {
|
|
12
|
+
if (vars.length === 0) {
|
|
13
|
+
return '{}\n';
|
|
14
|
+
}
|
|
15
|
+
return (vars
|
|
16
|
+
.map(({ key, value }) => {
|
|
17
|
+
// YAML string escaping rules:
|
|
18
|
+
// - Simple alphanumeric values don't need quotes
|
|
19
|
+
// - Values with special chars need double quotes
|
|
20
|
+
// - Double quotes inside values need escaping
|
|
21
|
+
const needsQuotes = value === '' ||
|
|
22
|
+
value.includes(':') ||
|
|
23
|
+
value.includes('#') ||
|
|
24
|
+
value.includes("'") ||
|
|
25
|
+
value.includes('"') ||
|
|
26
|
+
value.includes('\n') ||
|
|
27
|
+
value.includes('\\') ||
|
|
28
|
+
value.startsWith(' ') ||
|
|
29
|
+
value.endsWith(' ') ||
|
|
30
|
+
value.startsWith('!') ||
|
|
31
|
+
value.startsWith('&') ||
|
|
32
|
+
value.startsWith('*') ||
|
|
33
|
+
value.startsWith('|') ||
|
|
34
|
+
value.startsWith('>') ||
|
|
35
|
+
value.startsWith('%') ||
|
|
36
|
+
value.startsWith('@') ||
|
|
37
|
+
value.startsWith('`') ||
|
|
38
|
+
/^(true|false|yes|no|on|off|null|~)$/i.test(value) ||
|
|
39
|
+
/^-?\d+(\.\d+)?$/.test(value) ||
|
|
40
|
+
/^0x[0-9a-fA-F]+$/.test(value) ||
|
|
41
|
+
/^0o[0-7]+$/.test(value);
|
|
42
|
+
if (needsQuotes) {
|
|
43
|
+
// Escape backslashes and double quotes for YAML double-quoted strings
|
|
44
|
+
const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
|
|
45
|
+
return `${key}: "${escaped}"`;
|
|
46
|
+
}
|
|
47
|
+
return `${key}: ${value}`;
|
|
48
|
+
})
|
|
49
|
+
.join('\n') + '\n');
|
|
50
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type OutputFormat = 'dotenv' | 'wrangler' | 'json' | 'shell';
|
|
1
|
+
export type OutputFormat = 'dotenv' | 'wrangler' | 'json' | 'shell' | 'yaml';
|
|
2
2
|
export type Environment = 'development' | 'production';
|
|
3
3
|
export interface Target {
|
|
4
4
|
name: string;
|
|
@@ -11,6 +11,7 @@ export interface SourceFiles {
|
|
|
11
11
|
shared: string;
|
|
12
12
|
development: string;
|
|
13
13
|
production: string;
|
|
14
|
+
local: string;
|
|
14
15
|
}
|
|
15
16
|
export interface HushConfig {
|
|
16
17
|
sources: SourceFiles;
|
|
@@ -29,7 +30,18 @@ export interface EncryptOptions {
|
|
|
29
30
|
}
|
|
30
31
|
export interface EditOptions {
|
|
31
32
|
root: string;
|
|
32
|
-
file?: 'shared' | 'development' | 'production';
|
|
33
|
+
file?: 'shared' | 'development' | 'production' | 'local';
|
|
34
|
+
}
|
|
35
|
+
export interface SetOptions {
|
|
36
|
+
root: string;
|
|
37
|
+
file?: 'shared' | 'development' | 'production' | 'local';
|
|
38
|
+
key?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface RunOptions {
|
|
41
|
+
root: string;
|
|
42
|
+
env: Environment;
|
|
43
|
+
target?: string;
|
|
44
|
+
command: string[];
|
|
33
45
|
}
|
|
34
46
|
export interface PushOptions {
|
|
35
47
|
root: string;
|
|
@@ -67,6 +79,11 @@ export interface CheckResult {
|
|
|
67
79
|
status: 'ok' | 'drift' | 'error';
|
|
68
80
|
files: CheckFileResult[];
|
|
69
81
|
}
|
|
82
|
+
export interface SkillOptions {
|
|
83
|
+
root: string;
|
|
84
|
+
global?: boolean;
|
|
85
|
+
local?: boolean;
|
|
86
|
+
}
|
|
70
87
|
export declare const DEFAULT_SOURCES: SourceFiles;
|
|
71
88
|
export declare const FORMAT_OUTPUT_FILES: Record<OutputFormat, Record<Environment, string>>;
|
|
72
89
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAC7E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,YAAY,CAAC;AAEvD,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,OAAO,CAAC;CAC1D;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,aAAa,GAAG,YAAY,GAAG,OAAO,CAAC;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,WAAW,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,mBAAmB,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AAE9G,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC;IACjC,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,MAAM,eAAe,EAAE,WAK7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAqBjF,CAAC"}
|
package/dist/types.js
CHANGED
|
@@ -2,6 +2,7 @@ export const DEFAULT_SOURCES = {
|
|
|
2
2
|
shared: '.env',
|
|
3
3
|
development: '.env.development',
|
|
4
4
|
production: '.env.production',
|
|
5
|
+
local: '.env.local',
|
|
5
6
|
};
|
|
6
7
|
export const FORMAT_OUTPUT_FILES = {
|
|
7
8
|
dotenv: {
|
|
@@ -20,4 +21,8 @@ export const FORMAT_OUTPUT_FILES = {
|
|
|
20
21
|
development: '.env.development.sh',
|
|
21
22
|
production: '.env.production.sh',
|
|
22
23
|
},
|
|
24
|
+
yaml: {
|
|
25
|
+
development: '.env.development.yaml',
|
|
26
|
+
production: '.env.production.yaml',
|
|
27
|
+
},
|
|
23
28
|
};
|