@heyditto/cli 2.5.2 → 2.7.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/README.md +47 -19
- package/dist/api.d.ts +13 -0
- package/dist/api.js +20 -0
- package/dist/api.js.map +1 -1
- package/dist/commands.d.ts +41 -3
- package/dist/commands.js +237 -61
- package/dist/commands.js.map +1 -1
- package/dist/secret-stores/aws.d.ts +8 -0
- package/dist/secret-stores/aws.js +59 -0
- package/dist/secret-stores/aws.js.map +1 -0
- package/dist/secret-stores/azure.d.ts +7 -0
- package/dist/secret-stores/azure.js +63 -0
- package/dist/secret-stores/azure.js.map +1 -0
- package/dist/secret-stores/cloudflare.d.ts +7 -0
- package/dist/secret-stores/cloudflare.js +46 -0
- package/dist/secret-stores/cloudflare.js.map +1 -0
- package/dist/secret-stores/doppler.d.ts +7 -0
- package/dist/secret-stores/doppler.js +52 -0
- package/dist/secret-stores/doppler.js.map +1 -0
- package/dist/secret-stores/exec.d.ts +55 -0
- package/dist/secret-stores/exec.js +132 -0
- package/dist/secret-stores/exec.js.map +1 -0
- package/dist/secret-stores/fly.d.ts +7 -0
- package/dist/secret-stores/fly.js +54 -0
- package/dist/secret-stores/fly.js.map +1 -0
- package/dist/secret-stores/gcloud.d.ts +7 -0
- package/dist/secret-stores/gcloud.js +62 -0
- package/dist/secret-stores/gcloud.js.map +1 -0
- package/dist/secret-stores/github.d.ts +9 -0
- package/dist/secret-stores/github.js +74 -0
- package/dist/secret-stores/github.js.map +1 -0
- package/dist/secret-stores/gitlab.d.ts +7 -0
- package/dist/secret-stores/gitlab.js +82 -0
- package/dist/secret-stores/gitlab.js.map +1 -0
- package/dist/secret-stores/index.d.ts +42 -0
- package/dist/secret-stores/index.js +106 -0
- package/dist/secret-stores/index.js.map +1 -0
- package/dist/secret-stores/kubernetes.d.ts +8 -0
- package/dist/secret-stores/kubernetes.js +76 -0
- package/dist/secret-stores/kubernetes.js.map +1 -0
- package/dist/secret-stores/naming.d.ts +20 -0
- package/dist/secret-stores/naming.js +62 -0
- package/dist/secret-stores/naming.js.map +1 -0
- package/dist/secret-stores/onepassword.d.ts +7 -0
- package/dist/secret-stores/onepassword.js +50 -0
- package/dist/secret-stores/onepassword.js.map +1 -0
- package/dist/secret-stores/types.d.ts +108 -0
- package/dist/secret-stores/types.js +25 -0
- package/dist/secret-stores/types.js.map +1 -0
- package/dist/secret-stores/vault.d.ts +7 -0
- package/dist/secret-stores/vault.js +47 -0
- package/dist/secret-stores/vault.js.map +1 -0
- package/dist/secret-stores/vercel.d.ts +9 -0
- package/dist/secret-stores/vercel.js +49 -0
- package/dist/secret-stores/vercel.js.map +1 -0
- package/package.json +1 -1
- package/dist/gh-secret.d.ts +0 -31
- package/dist/gh-secret.js +0 -94
- package/dist/gh-secret.js.map +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { preflight, run, trimmedStderr } from "./exec.js";
|
|
2
|
+
import { validateRepo, validateSecretName } from "./naming.js";
|
|
3
|
+
export const GH_INSTALL_HINT = "install the GitHub CLI from https://cli.github.com (brew install gh / winget install GitHub.cli), then run `gh auth login`";
|
|
4
|
+
/** Resolves owner/repo for the current directory the same way `gh` does (git remotes + gh config). */
|
|
5
|
+
export function resolveRepoFromCwd() {
|
|
6
|
+
const res = run("gh", ["repo", "view", "--json", "nameWithOwner", "-q", ".nameWithOwner"]);
|
|
7
|
+
const repo = res.stdout.trim();
|
|
8
|
+
if (res.status !== 0 || !repo) {
|
|
9
|
+
const detail = trimmedStderr(res);
|
|
10
|
+
throw new Error(`could not determine the GitHub repository from the current directory${detail ? ` (${detail})` : ""}. Pass --repo owner/repo, or run from inside a clone with a GitHub remote.`);
|
|
11
|
+
}
|
|
12
|
+
return repo;
|
|
13
|
+
}
|
|
14
|
+
/** Where the secret lands: a repository, one of its environments, or an organization. */
|
|
15
|
+
function target(options) {
|
|
16
|
+
const org = options.org?.trim();
|
|
17
|
+
const env = options.env?.trim();
|
|
18
|
+
if (org) {
|
|
19
|
+
if (options.repo || env) {
|
|
20
|
+
throw new Error("--org cannot be combined with --repo or --env (organization secrets are not scoped to one repository)");
|
|
21
|
+
}
|
|
22
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(org))
|
|
23
|
+
throw new Error(`--org must be an organization login, got "${options.org}"`);
|
|
24
|
+
return { describe: `organization ${org}`, fields: { kind: "org", org } };
|
|
25
|
+
}
|
|
26
|
+
const repo = options.repo ? validateRepo(options.repo) : resolveRepoFromCwd();
|
|
27
|
+
if (env)
|
|
28
|
+
return { describe: `${repo}, environment ${env}`, fields: { kind: "env", repo, env } };
|
|
29
|
+
return { describe: `${repo} (repository secret)`, fields: { kind: "repo", repo } };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* GitHub Actions. `gh secret set` reads the value from stdin when `--body` is
|
|
33
|
+
* omitted, so the key never appears in argv, `ps`, shell history or our output.
|
|
34
|
+
*/
|
|
35
|
+
export const github = {
|
|
36
|
+
id: "github",
|
|
37
|
+
label: "GitHub Actions",
|
|
38
|
+
bin: "gh",
|
|
39
|
+
shorthand: "--gh-secret",
|
|
40
|
+
nameLabel: "NAME",
|
|
41
|
+
installHint: GH_INSTALL_HINT,
|
|
42
|
+
options: ["repo", "env", "org"],
|
|
43
|
+
validateName: validateSecretName,
|
|
44
|
+
preflight: () => preflight({
|
|
45
|
+
bin: "gh",
|
|
46
|
+
label: "GitHub Actions",
|
|
47
|
+
installHint: GH_INSTALL_HINT,
|
|
48
|
+
authArgs: ["auth", "status"],
|
|
49
|
+
authHint: "Run `gh auth login` first.",
|
|
50
|
+
}),
|
|
51
|
+
resolveTarget: target,
|
|
52
|
+
deliveries: (name, t) => {
|
|
53
|
+
const args = ["secret", "set", name];
|
|
54
|
+
if (t.fields.kind === "org")
|
|
55
|
+
args.push("--org", t.fields.org);
|
|
56
|
+
else if (t.fields.kind === "env")
|
|
57
|
+
args.push("--repo", t.fields.repo, "--env", t.fields.env);
|
|
58
|
+
else
|
|
59
|
+
args.push("--repo", t.fields.repo);
|
|
60
|
+
return [{ note: "gh secret set", kind: "stdin", args }];
|
|
61
|
+
},
|
|
62
|
+
// Both predate the multi-store registry and are part of the published
|
|
63
|
+
// contract: key labels in the app and the `snippet` field in --output json.
|
|
64
|
+
keyName: (name, t) => (t.fields.kind === "org" ? `gh-secret:${name}` : `gh:${t.fields.repo}:${name}`),
|
|
65
|
+
snippet: (name) => `\${{ secrets.${name} }}`,
|
|
66
|
+
usage: (name, _t, gateway) => [
|
|
67
|
+
"Use it in a workflow step:",
|
|
68
|
+
" env:",
|
|
69
|
+
` ANTHROPIC_AUTH_TOKEN: \${{ secrets.${name} }}`,
|
|
70
|
+
` ANTHROPIC_BASE_URL: ${gateway.anthropicBaseUrl}`,
|
|
71
|
+
` # OpenAI-compatible clients: OPENAI_API_KEY: \${{ secrets.${name} }} with OPENAI_BASE_URL: ${gateway.openaiBaseUrl}`,
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/secret-stores/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SecretStore } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* GitLab CI/CD variables. `glab variable set KEY` reads the value from stdin
|
|
4
|
+
* when no value argument is given (`cat file | glab variable set KEY`), and
|
|
5
|
+
* `--masked` keeps it out of job logs.
|
|
6
|
+
*/
|
|
7
|
+
export declare const gitlab: SecretStore;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { preflight, run, trimmedStderr } from "./exec.js";
|
|
2
|
+
import { envStyleName, slug } from "./naming.js";
|
|
3
|
+
const INSTALL_HINT = "install the GitLab CLI from https://gitlab.com/gitlab-org/cli (brew install glab), then run `glab auth login`";
|
|
4
|
+
/** Resolves the project for the current directory the way glab itself does. */
|
|
5
|
+
function resolveProjectFromCwd() {
|
|
6
|
+
const res = run("glab", ["repo", "view", "-F", "json"]);
|
|
7
|
+
if (res.status === 0) {
|
|
8
|
+
try {
|
|
9
|
+
const parsed = JSON.parse(res.stdout);
|
|
10
|
+
if (parsed.path_with_namespace)
|
|
11
|
+
return parsed.path_with_namespace;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// Fall through to the shared error below.
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const detail = trimmedStderr(res);
|
|
18
|
+
throw new Error(`could not determine the GitLab project from the current directory${detail ? ` (${detail})` : ""}. Pass --project group/project, or run from inside a clone with a GitLab remote.`);
|
|
19
|
+
}
|
|
20
|
+
function target(options) {
|
|
21
|
+
const group = options.org?.trim();
|
|
22
|
+
const env = options.env?.trim();
|
|
23
|
+
if (group) {
|
|
24
|
+
if (options.project)
|
|
25
|
+
throw new Error("--org (GitLab group) cannot be combined with --project");
|
|
26
|
+
const g = slug("--org", group, /^[A-Za-z0-9_.\-/]+$/);
|
|
27
|
+
return { describe: `group ${g}`, fields: { kind: "group", group: g, ...(env ? { env } : {}) } };
|
|
28
|
+
}
|
|
29
|
+
const project = options.project ? slug("--project", options.project, /^[A-Za-z0-9_.\-/]+$/) : resolveProjectFromCwd();
|
|
30
|
+
return {
|
|
31
|
+
describe: `${project}${env ? `, environment scope ${env}` : ""} (CI/CD variable)`,
|
|
32
|
+
fields: { kind: "project", project, ...(env ? { env } : {}) },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* GitLab CI/CD variables. `glab variable set KEY` reads the value from stdin
|
|
37
|
+
* when no value argument is given (`cat file | glab variable set KEY`), and
|
|
38
|
+
* `--masked` keeps it out of job logs.
|
|
39
|
+
*/
|
|
40
|
+
export const gitlab = {
|
|
41
|
+
id: "gitlab",
|
|
42
|
+
label: "GitLab CI/CD",
|
|
43
|
+
bin: "glab",
|
|
44
|
+
shorthand: "--gitlab-var",
|
|
45
|
+
nameLabel: "NAME",
|
|
46
|
+
installHint: INSTALL_HINT,
|
|
47
|
+
options: ["project", "org", "env"],
|
|
48
|
+
validateName: (name) => envStyleName("GitLab CI/CD variable", name),
|
|
49
|
+
preflight: () => preflight({
|
|
50
|
+
bin: "glab",
|
|
51
|
+
label: "GitLab CI/CD",
|
|
52
|
+
installHint: INSTALL_HINT,
|
|
53
|
+
authArgs: ["auth", "status"],
|
|
54
|
+
authHint: "Run `glab auth login` first.",
|
|
55
|
+
}),
|
|
56
|
+
resolveTarget: target,
|
|
57
|
+
deliveries: (name, t) => {
|
|
58
|
+
const scope = (verb) => {
|
|
59
|
+
const args = ["variable", verb, name, "--masked"];
|
|
60
|
+
if (t.fields.kind === "group")
|
|
61
|
+
args.push("--group", t.fields.group);
|
|
62
|
+
else
|
|
63
|
+
args.push("--repo", t.fields.project);
|
|
64
|
+
if (t.fields.env)
|
|
65
|
+
args.push("--scope", t.fields.env);
|
|
66
|
+
return args;
|
|
67
|
+
};
|
|
68
|
+
// `set` refuses an existing variable, so fall back to `update`.
|
|
69
|
+
return [
|
|
70
|
+
{ note: "glab variable set", kind: "stdin", args: scope("set") },
|
|
71
|
+
{ note: "glab variable update", kind: "stdin", args: scope("update") },
|
|
72
|
+
];
|
|
73
|
+
},
|
|
74
|
+
usage: (name, _t, gateway) => [
|
|
75
|
+
"Use it in .gitlab-ci.yml:",
|
|
76
|
+
" variables:",
|
|
77
|
+
` ANTHROPIC_BASE_URL: ${gateway.anthropicBaseUrl}`,
|
|
78
|
+
` # ${name} is injected into every job; for OpenAI-compatible clients set`,
|
|
79
|
+
` # OPENAI_API_KEY: $${name} with OPENAI_BASE_URL: ${gateway.openaiBaseUrl}`,
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=gitlab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/secret-stores/gitlab.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type SecretStore, type StoreId, type StoreOptions } from "./types.js";
|
|
2
|
+
export { deliver, installed, resolveBin } from "./exec.js";
|
|
3
|
+
export { GH_INSTALL_HINT, resolveRepoFromCwd } from "./github.js";
|
|
4
|
+
export { validateRepo, validateSecretName } from "./naming.js";
|
|
5
|
+
export { STORE_IDS } from "./types.js";
|
|
6
|
+
export type { Delivery, Gateway, SecretStore, StoreId, StoreOptions, StoreTarget } from "./types.js";
|
|
7
|
+
export { VERCEL_TARGETS } from "./vercel.js";
|
|
8
|
+
/** Every store, in the order they are listed to the operator. */
|
|
9
|
+
export declare const STORES: readonly SecretStore[];
|
|
10
|
+
export declare function storeById(id: string): SecretStore;
|
|
11
|
+
/** `--store <id>` is the canonical selector; every store also has a shorthand. */
|
|
12
|
+
export interface StoreSelection {
|
|
13
|
+
store: SecretStore;
|
|
14
|
+
/** Secret / variable / item / path name. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** The flag the operator actually used, for error messages. */
|
|
17
|
+
flag: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolves which store gets the key from `--store`/`--secret` or exactly one
|
|
21
|
+
* shorthand, and rejects flags that belong to a different store — silently
|
|
22
|
+
* ignoring `--repo` on an AWS run would store the secret somewhere the
|
|
23
|
+
* operator did not intend.
|
|
24
|
+
*/
|
|
25
|
+
export declare function selectStore(options: StoreOptions & {
|
|
26
|
+
store?: string;
|
|
27
|
+
shorthands: Partial<Record<StoreId, string>>;
|
|
28
|
+
}): StoreSelection;
|
|
29
|
+
export interface StoreProbe {
|
|
30
|
+
id: StoreId;
|
|
31
|
+
label: string;
|
|
32
|
+
bin: string;
|
|
33
|
+
/** The binary actually found on PATH (fly vs flyctl). */
|
|
34
|
+
resolvedBin: string;
|
|
35
|
+
installed: boolean;
|
|
36
|
+
shorthand: string;
|
|
37
|
+
nameLabel: string;
|
|
38
|
+
flags: string[];
|
|
39
|
+
installHint: string;
|
|
40
|
+
}
|
|
41
|
+
/** Which platform CLIs this machine has — the answer to "what can I delegate to?". */
|
|
42
|
+
export declare function probeStores(): StoreProbe[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { aws } from "./aws.js";
|
|
2
|
+
import { azure } from "./azure.js";
|
|
3
|
+
import { cloudflare } from "./cloudflare.js";
|
|
4
|
+
import { doppler } from "./doppler.js";
|
|
5
|
+
import { installed, resolveBin } from "./exec.js";
|
|
6
|
+
import { fly } from "./fly.js";
|
|
7
|
+
import { gcloud } from "./gcloud.js";
|
|
8
|
+
import { github } from "./github.js";
|
|
9
|
+
import { gitlab } from "./gitlab.js";
|
|
10
|
+
import { kubernetes } from "./kubernetes.js";
|
|
11
|
+
import { onepassword } from "./onepassword.js";
|
|
12
|
+
import { vault } from "./vault.js";
|
|
13
|
+
import { vercel } from "./vercel.js";
|
|
14
|
+
import { STORE_IDS } from "./types.js";
|
|
15
|
+
export { deliver, installed, resolveBin } from "./exec.js";
|
|
16
|
+
export { GH_INSTALL_HINT, resolveRepoFromCwd } from "./github.js";
|
|
17
|
+
export { validateRepo, validateSecretName } from "./naming.js";
|
|
18
|
+
export { STORE_IDS } from "./types.js";
|
|
19
|
+
export { VERCEL_TARGETS } from "./vercel.js";
|
|
20
|
+
/** Every store, in the order they are listed to the operator. */
|
|
21
|
+
export const STORES = [
|
|
22
|
+
github,
|
|
23
|
+
gitlab,
|
|
24
|
+
aws,
|
|
25
|
+
gcloud,
|
|
26
|
+
azure,
|
|
27
|
+
onepassword,
|
|
28
|
+
vault,
|
|
29
|
+
doppler,
|
|
30
|
+
cloudflare,
|
|
31
|
+
vercel,
|
|
32
|
+
kubernetes,
|
|
33
|
+
fly,
|
|
34
|
+
];
|
|
35
|
+
/** Human label for every flag, so "unsupported flag" errors name the flag the operator typed. */
|
|
36
|
+
const OPTION_FLAGS = {
|
|
37
|
+
repo: "--repo",
|
|
38
|
+
env: "--env",
|
|
39
|
+
org: "--org",
|
|
40
|
+
region: "--region",
|
|
41
|
+
project: "--project",
|
|
42
|
+
keyVault: "--key-vault",
|
|
43
|
+
opVault: "--op-vault",
|
|
44
|
+
mount: "--mount",
|
|
45
|
+
field: "--field",
|
|
46
|
+
dopplerConfig: "--doppler-config",
|
|
47
|
+
worker: "--worker",
|
|
48
|
+
vercelTarget: "--vercel-target",
|
|
49
|
+
namespace: "--namespace",
|
|
50
|
+
k8sKey: "--k8s-key",
|
|
51
|
+
app: "--app",
|
|
52
|
+
};
|
|
53
|
+
const OPTION_KEYS = Object.keys(OPTION_FLAGS);
|
|
54
|
+
export function storeById(id) {
|
|
55
|
+
const store = STORES.find((s) => s.id === id);
|
|
56
|
+
if (!store)
|
|
57
|
+
throw new Error(`unknown --store "${id}". Available: ${STORE_IDS.join(", ")}`);
|
|
58
|
+
return store;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolves which store gets the key from `--store`/`--secret` or exactly one
|
|
62
|
+
* shorthand, and rejects flags that belong to a different store — silently
|
|
63
|
+
* ignoring `--repo` on an AWS run would store the secret somewhere the
|
|
64
|
+
* operator did not intend.
|
|
65
|
+
*/
|
|
66
|
+
export function selectStore(options) {
|
|
67
|
+
const used = STORES.filter((s) => options.shorthands[s.id] !== undefined);
|
|
68
|
+
if (used.length > 1) {
|
|
69
|
+
throw new Error(`pick one destination: ${used.map((s) => s.shorthand).join(" and ")} cannot both be set`);
|
|
70
|
+
}
|
|
71
|
+
const shorthand = used[0];
|
|
72
|
+
if (shorthand && options.store && options.store !== shorthand.id) {
|
|
73
|
+
throw new Error(`--store ${options.store} contradicts ${shorthand.shorthand} (which implies --store ${shorthand.id})`);
|
|
74
|
+
}
|
|
75
|
+
const store = shorthand ?? (options.store ? storeById(options.store) : undefined);
|
|
76
|
+
if (!store) {
|
|
77
|
+
throw new Error(`pick a destination: --store <${STORE_IDS.join("|")}> with --secret <NAME>, or a shorthand such as ${github.shorthand} NAME. See \`heyditto endpoints keys stores\`.`);
|
|
78
|
+
}
|
|
79
|
+
const raw = shorthand ? options.shorthands[store.id] : options.secret;
|
|
80
|
+
const flag = shorthand ? store.shorthand : "--secret";
|
|
81
|
+
if (!raw)
|
|
82
|
+
throw new Error(`--store ${store.id} needs --secret <${store.nameLabel}>`);
|
|
83
|
+
const stray = OPTION_KEYS.filter((key) => options[key] !== undefined && !store.options.includes(key));
|
|
84
|
+
if (stray.length > 0) {
|
|
85
|
+
throw new Error(`${stray.map((key) => OPTION_FLAGS[key]).join(", ")} ${stray.length > 1 ? "do" : "does"} not apply to ${store.label}; it accepts ${store.options.map((key) => OPTION_FLAGS[key]).join(", ") || "no scoping flags"}`);
|
|
86
|
+
}
|
|
87
|
+
return { store, name: store.validateName(raw), flag };
|
|
88
|
+
}
|
|
89
|
+
/** Which platform CLIs this machine has — the answer to "what can I delegate to?". */
|
|
90
|
+
export function probeStores() {
|
|
91
|
+
return STORES.map((store) => {
|
|
92
|
+
const bin = resolveBin(store);
|
|
93
|
+
return {
|
|
94
|
+
id: store.id,
|
|
95
|
+
label: store.label,
|
|
96
|
+
bin: store.bin,
|
|
97
|
+
resolvedBin: bin,
|
|
98
|
+
installed: installed(bin, store.versionArgs),
|
|
99
|
+
shorthand: store.shorthand,
|
|
100
|
+
nameLabel: store.nameLabel,
|
|
101
|
+
flags: store.options.map((key) => OPTION_FLAGS[key]),
|
|
102
|
+
installHint: store.installHint,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/secret-stores/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SecretStore } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Kubernetes. The manifest is built here and piped in, so the plaintext never
|
|
4
|
+
* reaches argv (`--from-literal` would) and never touches disk. A merge patch
|
|
5
|
+
* comes first because it leaves the secret's other keys alone; `apply` is the
|
|
6
|
+
* fallback that creates the secret when it does not exist yet.
|
|
7
|
+
*/
|
|
8
|
+
export declare const kubernetes: SecretStore;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { PATH_PLACEHOLDER, preflight } from "./exec.js";
|
|
2
|
+
import { resourceName, slug } from "./naming.js";
|
|
3
|
+
/** The merge patch the first attempt sends: adds this key, leaves the rest. */
|
|
4
|
+
function mergePatch(key, value) {
|
|
5
|
+
return `${JSON.stringify({ stringData: { [key]: value } })}\n`;
|
|
6
|
+
}
|
|
7
|
+
const INSTALL_HINT = "install kubectl from https://kubernetes.io/docs/tasks/tools (brew install kubectl), then point it at a cluster with `kubectl config use-context`";
|
|
8
|
+
function target(options) {
|
|
9
|
+
const namespace = options.namespace ? slug("--namespace", options.namespace, /^[a-z0-9-]+$/) : "default";
|
|
10
|
+
const key = options.k8sKey ? slug("--k8s-key", options.k8sKey, /^[A-Za-z0-9_.-]+$/) : "key";
|
|
11
|
+
return { describe: `Kubernetes secret in namespace ${namespace} (key ${key})`, fields: { namespace, key } };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Kubernetes. The manifest is built here and piped in, so the plaintext never
|
|
15
|
+
* reaches argv (`--from-literal` would) and never touches disk. A merge patch
|
|
16
|
+
* comes first because it leaves the secret's other keys alone; `apply` is the
|
|
17
|
+
* fallback that creates the secret when it does not exist yet.
|
|
18
|
+
*/
|
|
19
|
+
export const kubernetes = {
|
|
20
|
+
id: "kubernetes",
|
|
21
|
+
label: "Kubernetes",
|
|
22
|
+
bin: "kubectl",
|
|
23
|
+
shorthand: "--k8s-secret",
|
|
24
|
+
nameLabel: "NAME",
|
|
25
|
+
installHint: INSTALL_HINT,
|
|
26
|
+
versionArgs: ["version", "--client=true"],
|
|
27
|
+
options: ["namespace", "k8sKey"],
|
|
28
|
+
validateName: (name) => {
|
|
29
|
+
const trimmed = name.trim();
|
|
30
|
+
if (trimmed !== trimmed.toLowerCase()) {
|
|
31
|
+
throw new Error(`"${name}" is not a valid Kubernetes secret name (lowercase letters, digits, dashes and dots only)`);
|
|
32
|
+
}
|
|
33
|
+
return resourceName("Kubernetes secret", trimmed, ".");
|
|
34
|
+
},
|
|
35
|
+
preflight: () => preflight({
|
|
36
|
+
bin: "kubectl",
|
|
37
|
+
label: "Kubernetes",
|
|
38
|
+
installHint: INSTALL_HINT,
|
|
39
|
+
versionArgs: kubernetes.versionArgs,
|
|
40
|
+
authArgs: ["config", "current-context"],
|
|
41
|
+
authHint: "Select a cluster with `kubectl config use-context <name>` first.",
|
|
42
|
+
}),
|
|
43
|
+
resolveTarget: target,
|
|
44
|
+
deliveries: (name, t) => {
|
|
45
|
+
const { namespace, key } = t.fields;
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
note: "kubectl patch secret",
|
|
49
|
+
kind: "path",
|
|
50
|
+
args: ["patch", "secret", name, "--namespace", namespace, "--type", "merge", "--patch-file", PATH_PLACEHOLDER],
|
|
51
|
+
payload: (value) => mergePatch(key, value),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
note: "kubectl apply",
|
|
55
|
+
kind: "stdin",
|
|
56
|
+
args: ["apply", "--namespace", namespace, "-f", "-"],
|
|
57
|
+
payload: (value) => `${JSON.stringify({
|
|
58
|
+
apiVersion: "v1",
|
|
59
|
+
kind: "Secret",
|
|
60
|
+
type: "Opaque",
|
|
61
|
+
metadata: { name, namespace },
|
|
62
|
+
stringData: { [key]: value },
|
|
63
|
+
})}\n`,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
},
|
|
67
|
+
usage: (name, t, gateway) => [
|
|
68
|
+
"Mount it into a pod:",
|
|
69
|
+
" env:",
|
|
70
|
+
" - name: OPENAI_API_KEY",
|
|
71
|
+
` valueFrom: { secretKeyRef: { name: ${name}, key: ${t.fields.key} } }`,
|
|
72
|
+
` - name: OPENAI_BASE_URL`,
|
|
73
|
+
` value: ${gateway.openaiBaseUrl}`,
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=kubernetes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kubernetes.js","sourceRoot":"","sources":["../../src/secret-stores/kubernetes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-platform name rules. Each store rejects names its platform would refuse
|
|
3
|
+
* anyway, before a key is minted, with a message that says what is allowed.
|
|
4
|
+
*/
|
|
5
|
+
/** Env-var style: letters, digits, underscores; not leading with a digit. */
|
|
6
|
+
export declare function envStyleName(label: string, name: string): string;
|
|
7
|
+
/** GitHub Actions additionally reserves the GITHUB_ prefix. */
|
|
8
|
+
export declare function validateSecretName(name: string): string;
|
|
9
|
+
export declare function validateRepo(repo: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* RFC 1123-ish resource names used by Google Secret Manager, Azure Key Vault
|
|
12
|
+
* and Kubernetes: letters, digits, dashes (Google also allows underscores).
|
|
13
|
+
*/
|
|
14
|
+
export declare function resourceName(label: string, name: string, extra?: string): string;
|
|
15
|
+
/** Free-form single-line title (1Password items). */
|
|
16
|
+
export declare function titleName(label: string, name: string): string;
|
|
17
|
+
/** A Vault kv path: slash-separated segments, no leading or trailing slash. */
|
|
18
|
+
export declare function secretPath(label: string, name: string): string;
|
|
19
|
+
/** Rejects a scoping flag's value that the platform would not accept. */
|
|
20
|
+
export declare function slug(flag: string, value: string, pattern?: RegExp): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-platform name rules. Each store rejects names its platform would refuse
|
|
3
|
+
* anyway, before a key is minted, with a message that says what is allowed.
|
|
4
|
+
*/
|
|
5
|
+
/** Env-var style: letters, digits, underscores; not leading with a digit. */
|
|
6
|
+
export function envStyleName(label, name) {
|
|
7
|
+
const trimmed = name.trim();
|
|
8
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(trimmed)) {
|
|
9
|
+
throw new Error(`"${name}" is not a valid ${label} name (letters, digits and underscores; cannot start with a digit)`);
|
|
10
|
+
}
|
|
11
|
+
return trimmed;
|
|
12
|
+
}
|
|
13
|
+
/** GitHub Actions additionally reserves the GITHUB_ prefix. */
|
|
14
|
+
export function validateSecretName(name) {
|
|
15
|
+
const trimmed = envStyleName("GitHub Actions secret", name);
|
|
16
|
+
if (/^GITHUB_/i.test(trimmed)) {
|
|
17
|
+
throw new Error(`"${name}" is reserved: GitHub Actions secret names cannot start with GITHUB_`);
|
|
18
|
+
}
|
|
19
|
+
return trimmed;
|
|
20
|
+
}
|
|
21
|
+
export function validateRepo(repo) {
|
|
22
|
+
const trimmed = repo.trim();
|
|
23
|
+
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(trimmed)) {
|
|
24
|
+
throw new Error(`--repo must be owner/repo, got "${repo}"`);
|
|
25
|
+
}
|
|
26
|
+
return trimmed;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* RFC 1123-ish resource names used by Google Secret Manager, Azure Key Vault
|
|
30
|
+
* and Kubernetes: letters, digits, dashes (Google also allows underscores).
|
|
31
|
+
*/
|
|
32
|
+
export function resourceName(label, name, extra = "") {
|
|
33
|
+
const trimmed = name.trim();
|
|
34
|
+
const pattern = new RegExp(`^[A-Za-z0-9][A-Za-z0-9${extra}-]{0,253}$`);
|
|
35
|
+
if (!pattern.test(trimmed)) {
|
|
36
|
+
throw new Error(`"${name}" is not a valid ${label} name (letters, digits${extra.includes("_") ? ", underscores" : ""} and dashes, starting with a letter or digit)`);
|
|
37
|
+
}
|
|
38
|
+
return trimmed;
|
|
39
|
+
}
|
|
40
|
+
/** Free-form single-line title (1Password items). */
|
|
41
|
+
export function titleName(label, name) {
|
|
42
|
+
const trimmed = name.trim();
|
|
43
|
+
if (!trimmed || /[\n\r]/.test(trimmed))
|
|
44
|
+
throw new Error(`"${name}" is not a valid ${label} (one non-empty line)`);
|
|
45
|
+
return trimmed;
|
|
46
|
+
}
|
|
47
|
+
/** A Vault kv path: slash-separated segments, no leading or trailing slash. */
|
|
48
|
+
export function secretPath(label, name) {
|
|
49
|
+
const trimmed = name.trim().replace(/^\/+|\/+$/g, "");
|
|
50
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_.\-/]*$/.test(trimmed)) {
|
|
51
|
+
throw new Error(`"${name}" is not a valid ${label} (letters, digits, dashes, dots, underscores and slashes)`);
|
|
52
|
+
}
|
|
53
|
+
return trimmed;
|
|
54
|
+
}
|
|
55
|
+
/** Rejects a scoping flag's value that the platform would not accept. */
|
|
56
|
+
export function slug(flag, value, pattern = /^[A-Za-z0-9_.-]+$/) {
|
|
57
|
+
const trimmed = value.trim();
|
|
58
|
+
if (!pattern.test(trimmed))
|
|
59
|
+
throw new Error(`${flag} must be a valid name, got "${value}"`);
|
|
60
|
+
return trimmed;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../../src/secret-stores/naming.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,6EAA6E;AAC7E,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,IAAY;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,oBAAoB,KAAK,oEAAoE,CAAC,CAAC;IACzH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;IAC5D,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,sEAAsE,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,oCAAoC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,GAAG,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,IAAY,EAAE,KAAK,GAAG,EAAE;IAClE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,yBAAyB,KAAK,YAAY,CAAC,CAAC;IACvE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,oBAAoB,KAAK,yBAAyB,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,+CAA+C,CAAC,CAAC;IACvK,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,SAAS,CAAC,KAAa,EAAE,IAAY;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,oBAAoB,KAAK,uBAAuB,CAAC,CAAC;IAClH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,IAAY;IACpD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACtD,IAAI,CAAC,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,IAAI,IAAI,oBAAoB,KAAK,2DAA2D,CAAC,CAAC;IAChH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,KAAa,EAAE,OAAO,GAAG,mBAAmB;IAC7E,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,+BAA+B,KAAK,GAAG,CAAC,CAAC;IAC5F,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SecretStore } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 1Password. Assignment statements (`credential=…`) put the value in argv and
|
|
4
|
+
* the docs say so explicitly, so this pipes an item JSON template into
|
|
5
|
+
* `op item create -` instead: the plaintext only ever crosses stdin.
|
|
6
|
+
*/
|
|
7
|
+
export declare const onepassword: SecretStore;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { preflight } from "./exec.js";
|
|
2
|
+
import { slug, titleName } from "./naming.js";
|
|
3
|
+
const INSTALL_HINT = "install the 1Password CLI from https://developer.1password.com/docs/cli/get-started (brew install 1password-cli), then sign in with `op signin`";
|
|
4
|
+
function target(options) {
|
|
5
|
+
const vault = options.opVault ? slug("--op-vault", options.opVault, /^[^\n\r]+$/) : "Private";
|
|
6
|
+
return { describe: `1Password vault ${vault}`, fields: { vault } };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 1Password. Assignment statements (`credential=…`) put the value in argv and
|
|
10
|
+
* the docs say so explicitly, so this pipes an item JSON template into
|
|
11
|
+
* `op item create -` instead: the plaintext only ever crosses stdin.
|
|
12
|
+
*/
|
|
13
|
+
export const onepassword = {
|
|
14
|
+
id: "1password",
|
|
15
|
+
label: "1Password",
|
|
16
|
+
bin: "op",
|
|
17
|
+
shorthand: "--op-item",
|
|
18
|
+
nameLabel: "TITLE",
|
|
19
|
+
installHint: INSTALL_HINT,
|
|
20
|
+
options: ["opVault"],
|
|
21
|
+
validateName: (name) => titleName("1Password item title", name),
|
|
22
|
+
preflight: () => preflight({
|
|
23
|
+
bin: "op",
|
|
24
|
+
label: "1Password",
|
|
25
|
+
installHint: INSTALL_HINT,
|
|
26
|
+
authArgs: ["whoami"],
|
|
27
|
+
authHint: "Run `op signin` first (or enable the desktop app's CLI integration).",
|
|
28
|
+
}),
|
|
29
|
+
resolveTarget: target,
|
|
30
|
+
deliveries: (title, t) => [
|
|
31
|
+
{
|
|
32
|
+
note: "op item create",
|
|
33
|
+
kind: "stdin",
|
|
34
|
+
args: ["item", "create", "--vault", t.fields.vault, "-"],
|
|
35
|
+
payload: (value) => `${JSON.stringify({
|
|
36
|
+
title,
|
|
37
|
+
category: "API_CREDENTIAL",
|
|
38
|
+
fields: [{ id: "credential", label: "credential", type: "CONCEALED", value }],
|
|
39
|
+
})}\n`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
usage: (title, t, gateway) => [
|
|
43
|
+
"Read it back without ever printing it:",
|
|
44
|
+
` op read "op://${t.fields.vault}/${title}/credential"`,
|
|
45
|
+
` # op run --env-file=.env -- your-command, with .env holding`,
|
|
46
|
+
` # OPENAI_API_KEY=op://${t.fields.vault}/${title}/credential`,
|
|
47
|
+
` # OPENAI_BASE_URL=${gateway.openaiBaseUrl}`,
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=onepassword.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onepassword.js","sourceRoot":"","sources":["../../src/secret-stores/onepassword.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,YAAY,GAChB,iJAAiJ,CAAC;AAEpJ,SAAS,MAAM,CAAC,OAAqB;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9F,OAAO,EAAE,QAAQ,EAAE,mBAAmB,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAgB;IACtC,EAAE,EAAE,WAAW;IACf,KAAK,EAAE,WAAW;IAClB,GAAG,EAAE,IAAI;IACT,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,OAAO;IAClB,WAAW,EAAE,YAAY;IACzB,OAAO,EAAE,CAAC,SAAS,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,sBAAsB,EAAE,IAAI,CAAC;IAC/D,SAAS,EAAE,GAAG,EAAE,CACd,SAAS,CAAC;QACR,GAAG,EAAE,IAAI;QACT,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,YAAY;QACzB,QAAQ,EAAE,CAAC,QAAQ,CAAC;QACpB,QAAQ,EAAE,sEAAsE;KACjF,CAAC;IACJ,aAAa,EAAE,MAAM;IACrB,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QACxB;YACE,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC;YACxD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,GAAG,IAAI,CAAC,SAAS,CAAC;gBAChB,KAAK;gBACL,QAAQ,EAAE,gBAAgB;gBAC1B,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;aAC9E,CAAC,IAAI;SACT;KACF;IACD,KAAK,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC5B,wCAAwC;QACxC,mBAAmB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,cAAc;QACxD,+DAA+D;QAC/D,6BAA6B,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,aAAa;QACjE,yBAAyB,OAAO,CAAC,aAAa,EAAE;KACjD;CACF,CAAC"}
|