sync-cf-secrets 0.1.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/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +116 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/copy.d.ts +9 -0
- package/dist/commands/copy.js +84 -0
- package/dist/commands/copy.js.map +1 -0
- package/dist/commands/diff.d.ts +7 -0
- package/dist/commands/diff.js +63 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +128 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.js +21 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/pull.d.ts +8 -0
- package/dist/commands/pull.js +42 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +8 -0
- package/dist/commands/push.js +68 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +136 -0
- package/dist/config.js.map +1 -0
- package/dist/providers/bitwarden.d.ts +10 -0
- package/dist/providers/bitwarden.js +98 -0
- package/dist/providers/bitwarden.js.map +1 -0
- package/dist/providers/index.d.ts +14 -0
- package/dist/providers/index.js +47 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/onepassword.d.ts +15 -0
- package/dist/providers/onepassword.js +84 -0
- package/dist/providers/onepassword.js.map +1 -0
- package/dist/providers/types.d.ts +25 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +29 -0
- package/dist/utils.js.map +1 -0
- package/dist/wrangler.d.ts +19 -0
- package/dist/wrangler.js +87 -0
- package/dist/wrangler.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { log, warn } from "../utils.js";
|
|
2
|
+
import { listSecrets, validateWrangler } from "../wrangler.js";
|
|
3
|
+
export async function list(config, opts) {
|
|
4
|
+
const envConfig = config.environments[opts.env];
|
|
5
|
+
if (!envConfig) {
|
|
6
|
+
throw new Error(`Unknown environment "${opts.env}". ` +
|
|
7
|
+
`Available: ${Object.keys(config.environments).join(", ")}`);
|
|
8
|
+
}
|
|
9
|
+
validateWrangler();
|
|
10
|
+
log(`Secrets deployed to ${opts.env}:\n`);
|
|
11
|
+
const names = listSecrets(opts.env, config.wranglerConfig);
|
|
12
|
+
if (names.length === 0) {
|
|
13
|
+
warn("No secrets found (or wrangler returned an unexpected format).");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
for (const name of names) {
|
|
17
|
+
log(` ${name}`);
|
|
18
|
+
}
|
|
19
|
+
log(`\n${names.length} secret(s) total.`);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAM/D,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,MAAc,EAAE,IAAiB;IAC1D,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,wBAAwB,IAAI,CAAC,GAAG,KAAK;YACnC,cAAc,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;IACJ,CAAC;IAED,gBAAgB,EAAE,CAAC;IAEnB,GAAG,CAAC,uBAAuB,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;IAE3D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,+DAA+D,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACnB,CAAC;IAED,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,mBAAmB,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Config } from "../config.js";
|
|
2
|
+
import type { SecretProvider } from "../providers/types.js";
|
|
3
|
+
export interface PullOptions {
|
|
4
|
+
env: string;
|
|
5
|
+
dryRun: boolean;
|
|
6
|
+
verbose: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function pull(provider: SecretProvider, config: Config, opts: PullOptions): Promise<void>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
import { log, success, warn } from "../utils.js";
|
|
3
|
+
export async function pull(provider, config, opts) {
|
|
4
|
+
const envConfig = config.environments[opts.env];
|
|
5
|
+
if (!envConfig) {
|
|
6
|
+
throw new Error(`Unknown environment "${opts.env}". ` +
|
|
7
|
+
`Available: ${Object.keys(config.environments).join(", ")}`);
|
|
8
|
+
}
|
|
9
|
+
log(`Fetching secrets from ${provider.name} (${envConfig.item})...`);
|
|
10
|
+
const secrets = await provider.fetch({
|
|
11
|
+
vault: config.vault,
|
|
12
|
+
item: envConfig.item,
|
|
13
|
+
});
|
|
14
|
+
if (secrets.size === 0) {
|
|
15
|
+
warn(`No secrets found in ${provider.name} item "${envConfig.item}".`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
log(`Found ${secrets.size} secret(s).`);
|
|
19
|
+
// Build .dev.vars content
|
|
20
|
+
const timestamp = new Date().toISOString();
|
|
21
|
+
const lines = [
|
|
22
|
+
`# Generated by sync-cf-secrets from ${provider.name} at ${timestamp}`,
|
|
23
|
+
`# Source: vault="${config.vault}" item="${envConfig.item}"`,
|
|
24
|
+
"# Do not commit this file.",
|
|
25
|
+
"",
|
|
26
|
+
];
|
|
27
|
+
for (const [name, value] of secrets) {
|
|
28
|
+
lines.push(`${name}=${value}`);
|
|
29
|
+
}
|
|
30
|
+
lines.push(""); // trailing newline
|
|
31
|
+
const content = lines.join("\n");
|
|
32
|
+
if (opts.dryRun) {
|
|
33
|
+
log(`\nDry run — would write to ${config.devVarsPath}:`);
|
|
34
|
+
for (const name of secrets.keys()) {
|
|
35
|
+
log(` ${name}`);
|
|
36
|
+
}
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
writeFileSync(config.devVarsPath, content, "utf-8");
|
|
40
|
+
success(`Wrote ${secrets.size} secret(s) to ${config.devVarsPath}`);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGxC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAQjD,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,QAAwB,EACxB,MAAc,EACd,IAAiB;IAEjB,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,wBAAwB,IAAI,CAAC,GAAG,KAAK;YACnC,cAAc,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,yBAAyB,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,MAAM,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC;QACnC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,SAAS,CAAC,IAAI;KACrB,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,uBAAuB,QAAQ,CAAC,IAAI,UAAU,SAAS,CAAC,IAAI,IAAI,CAAC,CAAC;QACvE,OAAO;IACT,CAAC;IAED,GAAG,CAAC,SAAS,OAAO,CAAC,IAAI,aAAa,CAAC,CAAC;IAExC,0BAA0B;IAC1B,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG;QACZ,uCAAuC,QAAQ,CAAC,IAAI,OAAO,SAAS,EAAE;QACtE,oBAAoB,MAAM,CAAC,KAAK,WAAW,SAAS,CAAC,IAAI,GAAG;QAC5D,4BAA4B;QAC5B,EAAE;KACH,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB;IACnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,GAAG,CAAC,8BAA8B,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC;QACzD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACnB,CAAC;QACD,OAAO;IACT,CAAC;IAED,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,OAAO,CAAC,SAAS,OAAO,CAAC,IAAI,iBAAiB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Config } from "../config.js";
|
|
2
|
+
import type { SecretProvider } from "../providers/types.js";
|
|
3
|
+
export interface PushOptions {
|
|
4
|
+
env: string;
|
|
5
|
+
dryRun: boolean;
|
|
6
|
+
verbose: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function push(provider: SecretProvider, config: Config, opts: PushOptions): Promise<void>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { error, log, success, warn } from "../utils.js";
|
|
2
|
+
import { getWranglerVars, putSecret, validateWrangler } from "../wrangler.js";
|
|
3
|
+
export async function push(provider, config, opts) {
|
|
4
|
+
const envConfig = config.environments[opts.env];
|
|
5
|
+
if (!envConfig) {
|
|
6
|
+
throw new Error(`Unknown environment "${opts.env}". ` +
|
|
7
|
+
`Available: ${Object.keys(config.environments).join(", ")}`);
|
|
8
|
+
}
|
|
9
|
+
if (!opts.dryRun) {
|
|
10
|
+
validateWrangler();
|
|
11
|
+
}
|
|
12
|
+
log(`Fetching secrets from ${provider.name} (${envConfig.item})...`);
|
|
13
|
+
const secrets = await provider.fetch({
|
|
14
|
+
vault: config.vault,
|
|
15
|
+
item: envConfig.item,
|
|
16
|
+
});
|
|
17
|
+
if (secrets.size === 0) {
|
|
18
|
+
warn(`No secrets found in ${provider.name} item "${envConfig.item}".`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// Filter out names already defined as vars in wrangler config
|
|
22
|
+
const wranglerVars = getWranglerVars(opts.env, config.wranglerConfig);
|
|
23
|
+
const skipped = [];
|
|
24
|
+
for (const name of secrets.keys()) {
|
|
25
|
+
if (wranglerVars.has(name)) {
|
|
26
|
+
skipped.push(name);
|
|
27
|
+
secrets.delete(name);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (skipped.length > 0) {
|
|
31
|
+
log(`Skipping ${skipped.length} var(s) already in wrangler config: ${skipped.join(", ")}`);
|
|
32
|
+
}
|
|
33
|
+
log(`Found ${secrets.size} secret(s) to push.`);
|
|
34
|
+
if (opts.dryRun) {
|
|
35
|
+
log("\nDry run — would push these secrets:");
|
|
36
|
+
for (const name of secrets.keys()) {
|
|
37
|
+
log(` ${name}`);
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
let succeeded = 0;
|
|
42
|
+
let failed = 0;
|
|
43
|
+
const total = secrets.size;
|
|
44
|
+
const failures = [];
|
|
45
|
+
for (const [name, value] of secrets) {
|
|
46
|
+
const index = succeeded + failed + 1;
|
|
47
|
+
try {
|
|
48
|
+
process.stdout.write(`[${index}/${total}] ${name} ... `);
|
|
49
|
+
putSecret(name, value, opts.env, config.wranglerConfig);
|
|
50
|
+
log("done");
|
|
51
|
+
succeeded++;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
log("FAILED");
|
|
55
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
56
|
+
error(` ${msg}`);
|
|
57
|
+
failures.push(name);
|
|
58
|
+
failed++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
log("");
|
|
62
|
+
if (failed > 0) {
|
|
63
|
+
error(`${failed} secret(s) failed: ${failures.join(", ")}`);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
success(`${succeeded}/${total} secret(s) pushed to ${opts.env}.`);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface EnvironmentConfig {
|
|
2
|
+
item: string;
|
|
3
|
+
}
|
|
4
|
+
export interface Config {
|
|
5
|
+
provider?: string;
|
|
6
|
+
vault: string;
|
|
7
|
+
prefix: string;
|
|
8
|
+
wranglerConfig: string;
|
|
9
|
+
devVarsPath: string;
|
|
10
|
+
environments: Record<string, EnvironmentConfig>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Load config from .sync-cf-secrets.json (if present) merged with defaults.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadConfig(overrides?: Partial<Config>): Config;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
const CONFIG_FILENAME = ".sync-cf-secrets.json";
|
|
4
|
+
const WRANGLER_FILENAMES = [
|
|
5
|
+
"wrangler.jsonc",
|
|
6
|
+
"wrangler.json",
|
|
7
|
+
"wrangler.toml",
|
|
8
|
+
];
|
|
9
|
+
/**
|
|
10
|
+
* Search upward from cwd for a file.
|
|
11
|
+
*/
|
|
12
|
+
function findUp(filename, from = process.cwd()) {
|
|
13
|
+
let dir = resolve(from);
|
|
14
|
+
while (true) {
|
|
15
|
+
const candidate = join(dir, filename);
|
|
16
|
+
if (existsSync(candidate))
|
|
17
|
+
return candidate;
|
|
18
|
+
const parent = dirname(dir);
|
|
19
|
+
if (parent === dir)
|
|
20
|
+
return null;
|
|
21
|
+
dir = parent;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Find the wrangler config file, searching common locations.
|
|
26
|
+
*/
|
|
27
|
+
function findWranglerConfig() {
|
|
28
|
+
// Direct in cwd
|
|
29
|
+
for (const name of WRANGLER_FILENAMES) {
|
|
30
|
+
const found = findUp(name);
|
|
31
|
+
if (found)
|
|
32
|
+
return found;
|
|
33
|
+
}
|
|
34
|
+
// Common monorepo patterns
|
|
35
|
+
const cwd = process.cwd();
|
|
36
|
+
const searchDirs = ["apps/web", "apps/worker", "worker", "workers"];
|
|
37
|
+
for (const dir of searchDirs) {
|
|
38
|
+
for (const name of WRANGLER_FILENAMES) {
|
|
39
|
+
const candidate = join(cwd, dir, name);
|
|
40
|
+
if (existsSync(candidate))
|
|
41
|
+
return candidate;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Read project name from nearest package.json.
|
|
48
|
+
*/
|
|
49
|
+
function getProjectName() {
|
|
50
|
+
const pkgPath = findUp("package.json");
|
|
51
|
+
if (!pkgPath)
|
|
52
|
+
return "project";
|
|
53
|
+
try {
|
|
54
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
55
|
+
// Strip scope (e.g. @org/name → name)
|
|
56
|
+
const name = pkg.name ?? "project";
|
|
57
|
+
return name.replace(/^@[^/]+\//, "");
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return "project";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parse wrangler config to discover environments.
|
|
65
|
+
*/
|
|
66
|
+
function discoverEnvironments(wranglerConfig, prefix) {
|
|
67
|
+
const envs = {
|
|
68
|
+
local: { item: `${prefix} local` },
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
const raw = readFileSync(wranglerConfig, "utf-8");
|
|
72
|
+
if (wranglerConfig.endsWith(".toml")) {
|
|
73
|
+
// Basic TOML env detection: [env.staging], [env.production]
|
|
74
|
+
const matches = raw.matchAll(/\[env\.(\w+)\]/g);
|
|
75
|
+
for (const match of matches) {
|
|
76
|
+
envs[match[1]] = { item: `${prefix} ${match[1]}` };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// JSON/JSONC: strip comments and trailing commas
|
|
81
|
+
const json = raw
|
|
82
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
83
|
+
.replace(/^(\s*)\/\/.*/gm, "$1")
|
|
84
|
+
.replace(/,(\s*[}\]])/g, "$1");
|
|
85
|
+
const config = JSON.parse(json);
|
|
86
|
+
if (config.env && typeof config.env === "object") {
|
|
87
|
+
for (const envName of Object.keys(config.env)) {
|
|
88
|
+
envs[envName] = { item: `${prefix} ${envName}` };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Fall back to just local
|
|
95
|
+
}
|
|
96
|
+
return envs;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Load config from .sync-cf-secrets.json (if present) merged with defaults.
|
|
100
|
+
*/
|
|
101
|
+
export function loadConfig(overrides) {
|
|
102
|
+
const configPath = findUp(CONFIG_FILENAME);
|
|
103
|
+
let fileConfig = {};
|
|
104
|
+
if (configPath) {
|
|
105
|
+
try {
|
|
106
|
+
fileConfig = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
throw new Error(`Invalid ${CONFIG_FILENAME}: ${err}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const projectName = getProjectName();
|
|
113
|
+
const prefix = overrides?.prefix ?? fileConfig.prefix ?? projectName;
|
|
114
|
+
const wranglerConfig = overrides?.wranglerConfig ??
|
|
115
|
+
fileConfig.wranglerConfig ??
|
|
116
|
+
findWranglerConfig() ??
|
|
117
|
+
"wrangler.toml";
|
|
118
|
+
const resolvedWranglerConfig = resolve(wranglerConfig);
|
|
119
|
+
const devVarsPath = overrides?.devVarsPath ??
|
|
120
|
+
fileConfig.devVarsPath ??
|
|
121
|
+
join(dirname(resolvedWranglerConfig), ".dev.vars");
|
|
122
|
+
const environments = overrides?.environments ??
|
|
123
|
+
fileConfig.environments ??
|
|
124
|
+
(existsSync(resolvedWranglerConfig)
|
|
125
|
+
? discoverEnvironments(resolvedWranglerConfig, prefix)
|
|
126
|
+
: { local: { item: `${prefix} local` } });
|
|
127
|
+
return {
|
|
128
|
+
provider: overrides?.provider ?? fileConfig.provider,
|
|
129
|
+
vault: overrides?.vault ?? fileConfig.vault ?? prefix,
|
|
130
|
+
prefix,
|
|
131
|
+
wranglerConfig: resolvedWranglerConfig,
|
|
132
|
+
devVarsPath: resolve(devVarsPath),
|
|
133
|
+
environments,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FetchOpts, SaveOpts, SecretProvider } from "./types.js";
|
|
2
|
+
export declare class BitwardenProvider implements SecretProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
cli: string;
|
|
5
|
+
validate(): Promise<void>;
|
|
6
|
+
fetch(opts: FetchOpts): Promise<Map<string, string>>;
|
|
7
|
+
exists(opts: FetchOpts): Promise<boolean>;
|
|
8
|
+
save(opts: SaveOpts): Promise<void>;
|
|
9
|
+
listFields(opts: FetchOpts): Promise<string[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { cliExists, exec } from "../utils.js";
|
|
3
|
+
export class BitwardenProvider {
|
|
4
|
+
name = "Bitwarden";
|
|
5
|
+
cli = "bw";
|
|
6
|
+
async validate() {
|
|
7
|
+
if (!cliExists("bw")) {
|
|
8
|
+
throw new Error("Bitwarden CLI (bw) not found.\n" +
|
|
9
|
+
"Install: https://bitwarden.com/help/cli/");
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const raw = exec("bw status", { stdio: ["pipe", "pipe", "pipe"] });
|
|
13
|
+
const status = JSON.parse(raw);
|
|
14
|
+
if (status.status !== "unlocked") {
|
|
15
|
+
throw new Error("locked");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (err instanceof Error && err.message.includes("locked")) {
|
|
20
|
+
throw new Error("Bitwarden vault is locked.\n" +
|
|
21
|
+
'Run: export BW_SESSION=$(bw unlock --raw)\n' +
|
|
22
|
+
"Or: bw login (if not logged in yet)");
|
|
23
|
+
}
|
|
24
|
+
throw new Error("Not logged in to Bitwarden.\n" +
|
|
25
|
+
"Run: bw login");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async fetch(opts) {
|
|
29
|
+
// Bitwarden doesn't have per-vault item get; use search + filter
|
|
30
|
+
const json = exec(`bw get item "${opts.item}" --organizationid "${opts.vault}"`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
31
|
+
const item = JSON.parse(json);
|
|
32
|
+
const secrets = new Map();
|
|
33
|
+
// Prefer custom fields
|
|
34
|
+
if (item.fields && item.fields.length > 0) {
|
|
35
|
+
for (const field of item.fields) {
|
|
36
|
+
if (field.name && field.value !== undefined) {
|
|
37
|
+
secrets.set(field.name, field.value);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return secrets;
|
|
42
|
+
}
|
|
43
|
+
async exists(opts) {
|
|
44
|
+
try {
|
|
45
|
+
exec(`bw get item "${opts.item}"`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async save(opts) {
|
|
53
|
+
// Build the item template
|
|
54
|
+
const fields = Array.from(opts.secrets.entries()).map(([name, value]) => ({
|
|
55
|
+
name,
|
|
56
|
+
value,
|
|
57
|
+
type: 1, // hidden field
|
|
58
|
+
}));
|
|
59
|
+
const template = {
|
|
60
|
+
type: 2, // Secure Note
|
|
61
|
+
name: opts.item,
|
|
62
|
+
notes: "",
|
|
63
|
+
secureNote: { type: 0 },
|
|
64
|
+
fields,
|
|
65
|
+
organizationId: opts.vault !== "null" ? opts.vault : undefined,
|
|
66
|
+
};
|
|
67
|
+
const encoded = Buffer.from(JSON.stringify(template)).toString("base64");
|
|
68
|
+
// Check if item exists
|
|
69
|
+
let existingId = null;
|
|
70
|
+
try {
|
|
71
|
+
const raw = exec(`bw get item "${opts.item}"`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
72
|
+
const existing = JSON.parse(raw);
|
|
73
|
+
existingId = existing.id;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Item doesn't exist
|
|
77
|
+
}
|
|
78
|
+
if (existingId) {
|
|
79
|
+
execSync(`echo '${encoded}' | bw edit item ${existingId}`, {
|
|
80
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
81
|
+
shell: "/bin/sh",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
execSync(`echo '${encoded}' | bw create item`, {
|
|
86
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
87
|
+
shell: "/bin/sh",
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// Sync to server
|
|
91
|
+
execSync("bw sync", { stdio: ["pipe", "pipe", "pipe"] });
|
|
92
|
+
}
|
|
93
|
+
async listFields(opts) {
|
|
94
|
+
const secrets = await this.fetch(opts);
|
|
95
|
+
return Array.from(secrets.keys());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=bitwarden.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitwarden.js","sourceRoot":"","sources":["../../src/providers/bitwarden.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SecretProvider } from "./types.js";
|
|
2
|
+
export type { SecretProvider } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Get a provider by explicit name (from config or CLI flag).
|
|
5
|
+
*/
|
|
6
|
+
export declare function getProvider(name: string): SecretProvider;
|
|
7
|
+
/**
|
|
8
|
+
* Auto-detect which provider is available by checking for CLI tools.
|
|
9
|
+
*/
|
|
10
|
+
export declare function detectProvider(): SecretProvider;
|
|
11
|
+
/**
|
|
12
|
+
* Resolve a provider from an optional name — explicit lookup or auto-detect.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveProvider(name?: string): SecretProvider;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { cliExists } from "../utils.js";
|
|
2
|
+
import { BitwardenProvider } from "./bitwarden.js";
|
|
3
|
+
import { OnePasswordProvider } from "./onepassword.js";
|
|
4
|
+
const PROVIDERS = [
|
|
5
|
+
() => new OnePasswordProvider(),
|
|
6
|
+
() => new BitwardenProvider(),
|
|
7
|
+
];
|
|
8
|
+
const PROVIDER_MAP = {
|
|
9
|
+
"1password": () => new OnePasswordProvider(),
|
|
10
|
+
onepassword: () => new OnePasswordProvider(),
|
|
11
|
+
op: () => new OnePasswordProvider(),
|
|
12
|
+
bitwarden: () => new BitwardenProvider(),
|
|
13
|
+
bw: () => new BitwardenProvider(),
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Get a provider by explicit name (from config or CLI flag).
|
|
17
|
+
*/
|
|
18
|
+
export function getProvider(name) {
|
|
19
|
+
const factory = PROVIDER_MAP[name.toLowerCase()];
|
|
20
|
+
if (!factory) {
|
|
21
|
+
const valid = Object.keys(PROVIDER_MAP).join(", ");
|
|
22
|
+
throw new Error(`Unknown provider "${name}". Valid providers: ${valid}`);
|
|
23
|
+
}
|
|
24
|
+
return factory();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Auto-detect which provider is available by checking for CLI tools.
|
|
28
|
+
*/
|
|
29
|
+
export function detectProvider() {
|
|
30
|
+
for (const factory of PROVIDERS) {
|
|
31
|
+
const provider = factory();
|
|
32
|
+
if (cliExists(provider.cli)) {
|
|
33
|
+
return provider;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw new Error("No supported password manager CLI found.\n" +
|
|
37
|
+
"Install one of:\n" +
|
|
38
|
+
" - 1Password CLI (op): https://developer.1password.com/docs/cli/\n" +
|
|
39
|
+
" - Bitwarden CLI (bw): https://bitwarden.com/help/cli/");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a provider from an optional name — explicit lookup or auto-detect.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveProvider(name) {
|
|
45
|
+
return name ? getProvider(name) : detectProvider();
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAKvD,MAAM,SAAS,GAAgC;IAC7C,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IAC/B,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;CAC9B,CAAC;AAEF,MAAM,YAAY,GAAyC;IACzD,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IAC5C,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IAC5C,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,mBAAmB,EAAE;IACnC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;IACxC,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;CAClC,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,uBAAuB,KAAK,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,OAAO,EAAE,CAAC;QAC3B,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,4CAA4C;QAC1C,mBAAmB;QACnB,qEAAqE;QACrE,yDAAyD,CAC5D,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,OAAO,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FetchOpts, SaveOpts, SecretProvider } from "./types.js";
|
|
2
|
+
export declare class OnePasswordProvider implements SecretProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
cli: string;
|
|
5
|
+
validate(): Promise<void>;
|
|
6
|
+
fetch(opts: FetchOpts): Promise<Map<string, string>>;
|
|
7
|
+
/**
|
|
8
|
+
* Find all item IDs matching a title in a vault.
|
|
9
|
+
* Uses `op item list` to avoid ambiguity with duplicate names.
|
|
10
|
+
*/
|
|
11
|
+
private findItemIds;
|
|
12
|
+
exists(opts: FetchOpts): Promise<boolean>;
|
|
13
|
+
save(opts: SaveOpts): Promise<void>;
|
|
14
|
+
listFields(opts: FetchOpts): Promise<string[]>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { cliExists, exec } from "../utils.js";
|
|
3
|
+
/** Built-in field IDs that 1Password adds automatically */
|
|
4
|
+
const BUILTIN_FIELD_IDS = new Set([
|
|
5
|
+
"username",
|
|
6
|
+
"password",
|
|
7
|
+
"notesPlain",
|
|
8
|
+
]);
|
|
9
|
+
export class OnePasswordProvider {
|
|
10
|
+
name = "1Password";
|
|
11
|
+
cli = "op";
|
|
12
|
+
async validate() {
|
|
13
|
+
if (!cliExists("op")) {
|
|
14
|
+
throw new Error("1Password CLI (op) not found.\n" +
|
|
15
|
+
"Install: https://developer.1password.com/docs/cli/get-started/");
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
exec("op whoami", { stdio: ["pipe", "pipe", "pipe"] });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw new Error("Not signed in to 1Password.\n" +
|
|
22
|
+
"Run: eval $(op signin)");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async fetch(opts) {
|
|
26
|
+
const json = exec(`op item get "${opts.item}" --vault "${opts.vault}" --format json`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
27
|
+
const item = JSON.parse(json);
|
|
28
|
+
const secrets = new Map();
|
|
29
|
+
for (const field of item.fields ?? []) {
|
|
30
|
+
if (BUILTIN_FIELD_IDS.has(field.id))
|
|
31
|
+
continue;
|
|
32
|
+
if (field.purpose === "NOTES")
|
|
33
|
+
continue;
|
|
34
|
+
if (!field.label || field.value === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
secrets.set(field.label, field.value);
|
|
37
|
+
}
|
|
38
|
+
return secrets;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Find all item IDs matching a title in a vault.
|
|
42
|
+
* Uses `op item list` to avoid ambiguity with duplicate names.
|
|
43
|
+
*/
|
|
44
|
+
findItemIds(opts) {
|
|
45
|
+
try {
|
|
46
|
+
const json = exec(`op item list --vault "${opts.vault}" --format json`, { stdio: ["pipe", "pipe", "pipe"] });
|
|
47
|
+
const items = JSON.parse(json);
|
|
48
|
+
return items
|
|
49
|
+
.filter((i) => i.title === opts.item)
|
|
50
|
+
.map((i) => i.id);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async exists(opts) {
|
|
57
|
+
return this.findItemIds(opts).length > 0;
|
|
58
|
+
}
|
|
59
|
+
async save(opts) {
|
|
60
|
+
// Delete ALL existing items with this name — caller is responsible for confirming
|
|
61
|
+
const existingIds = this.findItemIds(opts);
|
|
62
|
+
for (const id of existingIds) {
|
|
63
|
+
execFileSync("op", [
|
|
64
|
+
"item", "delete", id, "--vault", opts.vault,
|
|
65
|
+
], { stdio: ["pipe", "pipe", "pipe"] });
|
|
66
|
+
}
|
|
67
|
+
// Create Secure Note with all fields as positional args (no shell escaping needed)
|
|
68
|
+
// Format: op item create --category "Secure Note" 'label[password]=value' ...
|
|
69
|
+
const fieldArgs = Array.from(opts.secrets.entries())
|
|
70
|
+
.map(([label, value]) => `${label}[password]=${value}`);
|
|
71
|
+
execFileSync("op", [
|
|
72
|
+
"item", "create",
|
|
73
|
+
"--category", "Secure Note",
|
|
74
|
+
"--vault", opts.vault,
|
|
75
|
+
"--title", opts.item,
|
|
76
|
+
...fieldArgs,
|
|
77
|
+
], { stdio: ["pipe", "pipe", "pipe"] });
|
|
78
|
+
}
|
|
79
|
+
async listFields(opts) {
|
|
80
|
+
const secrets = await this.fetch(opts);
|
|
81
|
+
return Array.from(secrets.keys());
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=onepassword.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onepassword.js","sourceRoot":"","sources":["../../src/providers/onepassword.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface FetchOpts {
|
|
2
|
+
vault: string;
|
|
3
|
+
item: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SaveOpts {
|
|
6
|
+
vault: string;
|
|
7
|
+
item: string;
|
|
8
|
+
secrets: Map<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export interface SecretProvider {
|
|
11
|
+
/** Human-readable name (e.g. "1Password") */
|
|
12
|
+
name: string;
|
|
13
|
+
/** CLI command name (e.g. "op") */
|
|
14
|
+
cli: string;
|
|
15
|
+
/** Check if the CLI is installed and the user is authenticated. Throws on failure. */
|
|
16
|
+
validate(): Promise<void>;
|
|
17
|
+
/** Fetch all secrets for an environment. Returns Map<envVarName, value>. */
|
|
18
|
+
fetch(opts: FetchOpts): Promise<Map<string, string>>;
|
|
19
|
+
/** Check if an item exists. */
|
|
20
|
+
exists(opts: FetchOpts): Promise<boolean>;
|
|
21
|
+
/** Create or replace an item with the given secrets. Deletes existing item first. */
|
|
22
|
+
save(opts: SaveOpts): Promise<void>;
|
|
23
|
+
/** List field names in an item (no values). */
|
|
24
|
+
listFields(opts: FetchOpts): Promise<string[]>;
|
|
25
|
+
}
|