@sponson/adapters 0.0.0-stage → 0.5.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 +202 -0
- package/README.md +4 -2
- package/dist/algolia.d.ts +6 -0
- package/dist/algolia.js +151 -0
- package/dist/algolia.js.map +1 -0
- package/dist/clerk.d.ts +8 -0
- package/dist/clerk.js +107 -0
- package/dist/clerk.js.map +1 -0
- package/dist/cloudflare.d.ts +25 -0
- package/dist/cloudflare.js +310 -0
- package/dist/cloudflare.js.map +1 -0
- package/dist/common.d.ts +73 -0
- package/dist/common.js +140 -0
- package/dist/common.js.map +1 -0
- package/dist/digest.d.ts +46 -0
- package/dist/digest.js +129 -0
- package/dist/digest.js.map +1 -0
- package/dist/digitalocean.d.ts +5 -0
- package/dist/digitalocean.js +243 -0
- package/dist/digitalocean.js.map +1 -0
- package/dist/http-adapter-action.d.ts +63 -0
- package/dist/http-adapter-action.js +369 -0
- package/dist/http-adapter-action.js.map +1 -0
- package/dist/http-adapter-auth.d.ts +88 -0
- package/dist/http-adapter-auth.js +437 -0
- package/dist/http-adapter-auth.js.map +1 -0
- package/dist/http-adapter-client.d.ts +51 -0
- package/dist/http-adapter-client.js +156 -0
- package/dist/http-adapter-client.js.map +1 -0
- package/dist/http-adapter-graphql.d.ts +39 -0
- package/dist/http-adapter-graphql.js +157 -0
- package/dist/http-adapter-graphql.js.map +1 -0
- package/dist/http-adapter-list.d.ts +33 -0
- package/dist/http-adapter-list.js +421 -0
- package/dist/http-adapter-list.js.map +1 -0
- package/dist/http-adapter-resource.d.ts +29 -0
- package/dist/http-adapter-resource.js +462 -0
- package/dist/http-adapter-resource.js.map +1 -0
- package/dist/http-adapter-spec.d.ts +216 -0
- package/dist/http-adapter-spec.js +660 -0
- package/dist/http-adapter-spec.js.map +1 -0
- package/dist/http-adapter.d.ts +16 -0
- package/dist/http-adapter.js +28 -0
- package/dist/http-adapter.js.map +1 -0
- package/dist/http.d.ts +179 -0
- package/dist/http.js +352 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/launchdarkly.d.ts +15 -0
- package/dist/launchdarkly.js +337 -0
- package/dist/launchdarkly.js.map +1 -0
- package/dist/manual.d.ts +13 -0
- package/dist/manual.js +201 -0
- package/dist/manual.js.map +1 -0
- package/dist/neon.d.ts +8 -0
- package/dist/neon.js +167 -0
- package/dist/neon.js.map +1 -0
- package/dist/netlify.d.ts +18 -0
- package/dist/netlify.js +436 -0
- package/dist/netlify.js.map +1 -0
- package/dist/planetscale.d.ts +10 -0
- package/dist/planetscale.js +311 -0
- package/dist/planetscale.js.map +1 -0
- package/dist/providers.d.ts +26 -0
- package/dist/providers.js +36 -0
- package/dist/providers.js.map +1 -0
- package/dist/recipes.d.ts +167 -0
- package/dist/recipes.js +246 -0
- package/dist/recipes.js.map +1 -0
- package/dist/secrets.d.ts +72 -0
- package/dist/secrets.js +476 -0
- package/dist/secrets.js.map +1 -0
- package/dist/sigv4.d.ts +56 -0
- package/dist/sigv4.js +118 -0
- package/dist/sigv4.js.map +1 -0
- package/dist/supabase.d.ts +9 -0
- package/dist/supabase.js +385 -0
- package/dist/supabase.js.map +1 -0
- package/dist/vercel.d.ts +8 -0
- package/dist/vercel.js +475 -0
- package/dist/vercel.js.map +1 -0
- package/dist/xata.d.ts +8 -0
- package/dist/xata.js +142 -0
- package/dist/xata.js.map +1 -0
- package/dist/xml.d.ts +25 -0
- package/dist/xml.js +211 -0
- package/dist/xml.js.map +1 -0
- package/package.json +58 -3
- package/recipes/amplify.yaml +147 -0
- package/recipes/auth0.yaml +178 -0
- package/recipes/azure_swa.yaml +116 -0
- package/recipes/cloud_run.yaml +97 -0
- package/recipes/cloudflare.yaml +108 -0
- package/recipes/cockroachdb.yaml +132 -0
- package/recipes/configcat.yaml +123 -0
- package/recipes/datadog.yaml +136 -0
- package/recipes/firebase.yaml +84 -0
- package/recipes/flagsmith.yaml +98 -0
- package/recipes/fly.yaml +97 -0
- package/recipes/fly_machines.yaml +67 -0
- package/recipes/gcs.yaml +102 -0
- package/recipes/github.yaml +123 -0
- package/recipes/growthbook.yaml +124 -0
- package/recipes/heroku.yaml +98 -0
- package/recipes/honeycomb.yaml +89 -0
- package/recipes/inngest.yaml +97 -0
- package/recipes/kinde.yaml +120 -0
- package/recipes/mongodb_atlas.yaml +119 -0
- package/recipes/okta.yaml +177 -0
- package/recipes/posthog.yaml +127 -0
- package/recipes/postmark.yaml +105 -0
- package/recipes/postmark_server.yaml +93 -0
- package/recipes/prisma.yaml +150 -0
- package/recipes/qstash.yaml +134 -0
- package/recipes/railway.yaml +130 -0
- package/recipes/render.yaml +103 -0
- package/recipes/resend.yaml +130 -0
- package/recipes/s3.yaml +108 -0
- package/recipes/sendgrid.yaml +165 -0
- package/recipes/sentry.yaml +158 -0
- package/recipes/split.yaml +121 -0
- package/recipes/statsig.yaml +124 -0
- package/recipes/stripe.yaml +310 -0
- package/recipes/stytch.yaml +113 -0
- package/recipes/svix.yaml +109 -0
- package/recipes/turso.yaml +98 -0
- package/recipes/unleash.yaml +149 -0
- package/recipes/upstash.yaml +130 -0
- package/recipes/vercel.yaml +116 -0
- package/recipes/workos.yaml +70 -0
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { SponsonError } from "@sponson/core";
|
|
3
|
+
import { apiClient, isProviderError } from "./http.js";
|
|
4
|
+
/**
|
|
5
|
+
* Runs the real binary from PATH; rejects with its stderr when it fails. A binary that cannot be started keeps the
|
|
6
|
+
* system error's `code` (`ENOENT`, `EACCES`), so the caller can say what is wrong instead of echoing it.
|
|
7
|
+
*/
|
|
8
|
+
export const defaultExec = (file, args, env) => new Promise((resolve, reject) => {
|
|
9
|
+
execFile(file, args, { env, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
|
10
|
+
if (!err)
|
|
11
|
+
return resolve(stdout);
|
|
12
|
+
const spawnCode = typeof err.code === "string" ? err.code : undefined;
|
|
13
|
+
const failure = new Error(`${file} ${args[0] ?? ""} failed: ${String(stderr || err.message).trim()}`);
|
|
14
|
+
if (spawnCode)
|
|
15
|
+
failure.code = spawnCode;
|
|
16
|
+
reject(failure);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* The one shape of every SECRET_UNRESOLVED a built-in source throws: the reason only. The engine prefixes the
|
|
21
|
+
* reference when it reports the line (`aws-sm://x: <reason>`), so the message never names the ref twice; the ref is
|
|
22
|
+
* in `details.ref` for callers that use a source directly. Never put the value, or any part of it, in `why`.
|
|
23
|
+
*/
|
|
24
|
+
function unresolved(ref, why, details = {}) {
|
|
25
|
+
return new SponsonError("SECRET_UNRESOLVED", why, { ref, ...details });
|
|
26
|
+
}
|
|
27
|
+
function stripScheme(ref, scheme) {
|
|
28
|
+
const prefix = `${scheme}://`;
|
|
29
|
+
if (!ref.startsWith(prefix))
|
|
30
|
+
throw unresolved(ref, `expected ${prefix}…`);
|
|
31
|
+
return ref.slice(prefix.length);
|
|
32
|
+
}
|
|
33
|
+
/** CLIs end their output with one newline (LF or CRLF); the secret is what comes before it. */
|
|
34
|
+
function stripTrailingNewline(out) {
|
|
35
|
+
return out.replace(/(\r\n|\n|\r)$/, "");
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run a secret CLI; any failure is SECRET_UNRESOLVED. Every CLI-backed source goes through here, so a missing binary
|
|
39
|
+
* reads the same for all of them ("the `aws` CLI is not installed or not on PATH"), and any other failure (not signed
|
|
40
|
+
* in, unknown item) carries the CLI's own error text, which never contains the value it failed to read.
|
|
41
|
+
*
|
|
42
|
+
* `fromRef` lists every argument taken from the reference. A plan is reviewed as data, so none of them may read as an
|
|
43
|
+
* option to the CLI: one starting with `-` is refused before anything runs.
|
|
44
|
+
*/
|
|
45
|
+
async function runCli(exec, ref, file, args, env, fromRef) {
|
|
46
|
+
const flag = fromRef.find((a) => a.startsWith("-"));
|
|
47
|
+
if (flag !== undefined)
|
|
48
|
+
throw unresolved(ref, `a reference segment may not start with "-" (it would reach the \`${file}\` CLI as an option)`);
|
|
49
|
+
try {
|
|
50
|
+
return stripTrailingNewline(await exec(file, args, env));
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
const code = e.code;
|
|
54
|
+
if (code === "ENOENT")
|
|
55
|
+
throw unresolved(ref, `the \`${file}\` CLI is not installed or not on PATH`);
|
|
56
|
+
if (code === "EACCES")
|
|
57
|
+
throw unresolved(ref, `the \`${file}\` CLI on PATH is not executable`);
|
|
58
|
+
throw unresolved(ref, e.message);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** `env://NAME` → process environment. Zero configuration; the CI default. */
|
|
62
|
+
export const envSecretSource = {
|
|
63
|
+
scheme: "env",
|
|
64
|
+
form: "`env://NAME`",
|
|
65
|
+
resolvedBy: "the process environment; unset or empty is `SECRET_UNRESOLVED`",
|
|
66
|
+
async resolve(ref, env) {
|
|
67
|
+
const name = stripScheme(ref, "env");
|
|
68
|
+
const v = env[name];
|
|
69
|
+
if (v === undefined || v === "")
|
|
70
|
+
throw unresolved(ref, `environment variable ${name} is not set`, { variable: name });
|
|
71
|
+
return v;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
/** `doppler://project/config/NAME` → `doppler secrets get`. Uses the CLI's login or DOPPLER_TOKEN from the env. */
|
|
75
|
+
export function dopplerSecretSource(exec = defaultExec) {
|
|
76
|
+
return {
|
|
77
|
+
scheme: "doppler",
|
|
78
|
+
form: "`doppler://project/config/NAME`",
|
|
79
|
+
resolvedBy: "`doppler secrets get NAME --project project --config config --plain` (Doppler CLI)",
|
|
80
|
+
async resolve(ref, env) {
|
|
81
|
+
const parts = stripScheme(ref, "doppler").split("/");
|
|
82
|
+
if (parts.length !== 3 || parts.some((p) => p === ""))
|
|
83
|
+
throw unresolved(ref, "expected doppler://project/config/NAME");
|
|
84
|
+
const [project, config, name] = parts;
|
|
85
|
+
return runCli(exec, ref, "doppler", ["secrets", "get", name, "--project", project, "--config", config, "--plain"], env, [name, project, config]);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** `op://vault/item/field` → `op read`, which accepts the reference as-is. */
|
|
90
|
+
export function opSecretSource(exec = defaultExec) {
|
|
91
|
+
return {
|
|
92
|
+
scheme: "op",
|
|
93
|
+
form: "`op://vault/item/field`",
|
|
94
|
+
resolvedBy: "`op read op://vault/item/field --no-newline` (1Password CLI)",
|
|
95
|
+
async resolve(ref, env) {
|
|
96
|
+
const path = stripScheme(ref, "op");
|
|
97
|
+
if (path.split("/").length < 3)
|
|
98
|
+
throw unresolved(ref, "expected op://vault/item/field");
|
|
99
|
+
// The reference is passed whole and always starts with `op://`, so it can never read as an option.
|
|
100
|
+
return runCli(exec, ref, "op", ["read", ref, "--no-newline"], env, [ref]);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* `aws-sm://<secret-id>` → `aws secretsmanager get-secret-value`, through the `aws` CLI so the AWS SDK stays out of
|
|
106
|
+
* the dependency tree. The secret id is a name or an ARN; region, profile and credentials come from the CLI's own
|
|
107
|
+
* conventions (`AWS_REGION`, `AWS_PROFILE`, ...). `aws-sm://<secret-id>#<key>` picks one key of a JSON secret, the
|
|
108
|
+
* shape the AWS console creates for key/value secrets.
|
|
109
|
+
*/
|
|
110
|
+
export function awsSecretsManagerSource(exec = defaultExec) {
|
|
111
|
+
return {
|
|
112
|
+
scheme: "aws-sm",
|
|
113
|
+
form: "`aws-sm://secret-id` or `aws-sm://secret-id#KEY`",
|
|
114
|
+
resolvedBy: "`aws secretsmanager get-secret-value --secret-id secret-id --query SecretString --output json` (AWS CLI; region and credentials from `AWS_REGION`, `AWS_PROFILE` and the CLI's other conventions). `secret-id` is a name or an ARN; `#KEY` picks one key of a JSON key/value secret. Binary secrets are not supported.",
|
|
115
|
+
async resolve(ref, env) {
|
|
116
|
+
const path = stripScheme(ref, "aws-sm");
|
|
117
|
+
const hash = path.indexOf("#");
|
|
118
|
+
const id = hash < 0 ? path : path.slice(0, hash);
|
|
119
|
+
const key = hash < 0 ? undefined : path.slice(hash + 1);
|
|
120
|
+
if (id === "" || key === "")
|
|
121
|
+
throw unresolved(ref, "expected aws-sm://<secret-id> or aws-sm://<secret-id>#<key>");
|
|
122
|
+
// JSON output, not text: text prints a binary secret's missing SecretString as the word "None".
|
|
123
|
+
const out = await runCli(exec, ref, "aws", ["secretsmanager", "get-secret-value", "--secret-id", id, "--query", "SecretString", "--output", "json"], env, [id]);
|
|
124
|
+
const value = parseJson(out);
|
|
125
|
+
if (typeof value !== "string")
|
|
126
|
+
throw unresolved(ref, "the secret has no string value (binary secrets are not supported)");
|
|
127
|
+
if (key === undefined)
|
|
128
|
+
return value;
|
|
129
|
+
// Never echo the secret (or a fragment of it) in these messages: they end up in the receipt.
|
|
130
|
+
const fields = parseJson(value);
|
|
131
|
+
if (typeof fields !== "object" || fields === null || Array.isArray(fields))
|
|
132
|
+
throw unresolved(ref, `#${key} needs a JSON object secret, and this one is not`);
|
|
133
|
+
const picked = fields[key];
|
|
134
|
+
if (picked === undefined)
|
|
135
|
+
throw unresolved(ref, `the secret has no key ${key}`);
|
|
136
|
+
if (typeof picked !== "string" && typeof picked !== "number" && typeof picked !== "boolean")
|
|
137
|
+
throw unresolved(ref, `key ${key} is not a string, number or boolean`);
|
|
138
|
+
return String(picked);
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const GCP_SM_FORM = "expected gcp-sm://<project>/<secret> or gcp-sm://<project>/<secret>/<version>";
|
|
143
|
+
/** Project ids (including domain-scoped `example.com:proj`) and project numbers; no leading `-`, so never a flag. */
|
|
144
|
+
const GCP_PROJECT = /^[a-z0-9][a-z0-9.:-]*$/;
|
|
145
|
+
/** Secret Manager's own rule for secret ids. */
|
|
146
|
+
const GCP_SECRET = /^[A-Za-z0-9_-]{1,255}$/;
|
|
147
|
+
const GCP_VERSION = /^(latest|[1-9][0-9]*)$/;
|
|
148
|
+
/**
|
|
149
|
+
* `gcp-sm://<project>/<secret>[/<version>]` → `gcloud secrets versions access`, through the `gcloud` CLI so the Google
|
|
150
|
+
* SDK stays out of the dependency tree. The version defaults to `latest`; credentials come from the CLI's own
|
|
151
|
+
* conventions (`gcloud auth`, `CLOUDSDK_*`, `GOOGLE_APPLICATION_CREDENTIALS`). The project is part of the reference
|
|
152
|
+
* so a plan never depends on whichever project the runner's gcloud happens to have configured.
|
|
153
|
+
*/
|
|
154
|
+
export function gcpSecretManagerSource(exec = defaultExec) {
|
|
155
|
+
return {
|
|
156
|
+
scheme: "gcp-sm",
|
|
157
|
+
form: "`gcp-sm://project/secret` or `gcp-sm://project/secret/version`",
|
|
158
|
+
resolvedBy: "`gcloud secrets versions access version --secret=secret --project=project --format=json` (Google Cloud CLI; credentials from `gcloud auth` and the CLI's other conventions). `version` is a number or `latest` (the default). The payload must be UTF-8 text.",
|
|
159
|
+
async resolve(ref, env) {
|
|
160
|
+
const parts = stripScheme(ref, "gcp-sm").split("/");
|
|
161
|
+
if (parts.length < 2 || parts.length > 3)
|
|
162
|
+
throw unresolved(ref, GCP_SM_FORM);
|
|
163
|
+
const [project, secret, version = "latest"] = parts;
|
|
164
|
+
if (!GCP_PROJECT.test(project) || !GCP_SECRET.test(secret) || !GCP_VERSION.test(version))
|
|
165
|
+
throw unresolved(ref, GCP_SM_FORM);
|
|
166
|
+
// JSON, not the default raw output: the payload arrives base64-encoded, so a value ending in a newline survives
|
|
167
|
+
// and a binary payload is recognised instead of being passed on as mangled text.
|
|
168
|
+
const out = await runCli(exec, ref, "gcloud", ["secrets", "versions", "access", version, `--secret=${secret}`, `--project=${project}`, "--format=json"], env, [version, secret, project]);
|
|
169
|
+
const response = parseJson(out);
|
|
170
|
+
const data = isRecord(response) && isRecord(response.payload) ? response.payload.data : undefined;
|
|
171
|
+
if (typeof data !== "string")
|
|
172
|
+
throw unresolved(ref, "gcloud returned no payload");
|
|
173
|
+
// Never echo the payload (or a fragment of it) in these messages: they end up in the receipt.
|
|
174
|
+
let value;
|
|
175
|
+
try {
|
|
176
|
+
value = new TextDecoder("utf-8", { fatal: true }).decode(Buffer.from(data, "base64"));
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
throw unresolved(ref, "the secret is not UTF-8 text (binary secrets are not supported)");
|
|
180
|
+
}
|
|
181
|
+
if (value === "")
|
|
182
|
+
throw unresolved(ref, "the secret is empty");
|
|
183
|
+
return value;
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const INFISICAL_FORM = "expected infisical://<projectId>/<env>/<NAME> or infisical://<projectId>/<env>/<folder>/…/<NAME>";
|
|
188
|
+
/**
|
|
189
|
+
* What `infisical secrets get` prints for a name the folder does not hold, in place of a value (Infisical CLI,
|
|
190
|
+
* packages/cmd/secrets.go `getSecretsByNames`). It exits 0 with it, so it must be recognised here, never passed on.
|
|
191
|
+
*/
|
|
192
|
+
const INFISICAL_NOT_FOUND = "*not found*";
|
|
193
|
+
/**
|
|
194
|
+
* `infisical://<projectId>/<env>/[<folder>/…/]<NAME>` → `infisical secrets get`, through the Infisical CLI
|
|
195
|
+
* (https://infisical.com/docs/cli/commands/secrets). The folders become `--path` (default `/`). Credentials come
|
|
196
|
+
* from the CLI's own conventions: `INFISICAL_TOKEN` (or `INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN`) for a machine
|
|
197
|
+
* identity, else the CLI's login; `INFISICAL_DOMAIN` for EU Cloud or a self-hosted instance. The project id is part of
|
|
198
|
+
* the reference because a machine identity has no `.infisical.json` to take it from.
|
|
199
|
+
*
|
|
200
|
+
* JSON output, not `--plain`: with `--plain` an unknown name prints nothing at all (exit 0), indistinguishable from
|
|
201
|
+
* an empty secret; with `--output json` it prints the entry with the value `*not found*`, which is refused here.
|
|
202
|
+
*/
|
|
203
|
+
export function infisicalSecretSource(exec = defaultExec) {
|
|
204
|
+
return {
|
|
205
|
+
scheme: "infisical",
|
|
206
|
+
form: "`infisical://projectId/env/NAME` or `infisical://projectId/env/folder/…/NAME`",
|
|
207
|
+
resolvedBy: "`infisical secrets get NAME --projectId projectId --env env --path /folder/… --output json --silent` (Infisical CLI; credentials from `INFISICAL_TOKEN` or the CLI's login, the instance from `INFISICAL_DOMAIN`). A name the folder does not hold is `SECRET_UNRESOLVED`, never a value.",
|
|
208
|
+
async resolve(ref, env) {
|
|
209
|
+
const parts = stripScheme(ref, "infisical").split("/");
|
|
210
|
+
if (parts.length < 3 || parts.some((p) => p === ""))
|
|
211
|
+
throw unresolved(ref, INFISICAL_FORM);
|
|
212
|
+
const [projectId, environment, ...rest] = parts;
|
|
213
|
+
const name = rest.pop();
|
|
214
|
+
const path = `/${rest.join("/")}`;
|
|
215
|
+
const args = ["secrets", "get", name, "--projectId", projectId, "--env", environment, "--path", path, "--output", "json", "--silent"];
|
|
216
|
+
const out = await runCli(exec, ref, "infisical", args, env, [name, projectId, environment, ...rest]);
|
|
217
|
+
// Never echo the output (or a fragment of it) in these messages: it holds the value.
|
|
218
|
+
const entries = parseJson(out);
|
|
219
|
+
const entry = Array.isArray(entries) ? entries.find((e) => isRecord(e) && e.secretKey === name) : undefined;
|
|
220
|
+
const value = isRecord(entry) ? entry.secretValue : undefined;
|
|
221
|
+
if (entry === undefined || value === INFISICAL_NOT_FOUND)
|
|
222
|
+
throw unresolved(ref, `no secret ${name} in environment ${environment} at ${path}`);
|
|
223
|
+
if (typeof value !== "string")
|
|
224
|
+
throw unresolved(ref, "the Infisical CLI returned no value");
|
|
225
|
+
return value;
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const AZURE_KV_FORM = "expected azure-kv://<vault>/<name> or azure-kv://<vault>/<name>/<version>";
|
|
230
|
+
/** Key Vault's own rules: vault names 3-24 of 0-9 a-z A-Z and non-consecutive `-`; secret names 1-127 of 0-9 a-z A-Z `-`; versions 32 characters. */
|
|
231
|
+
const AZURE_VAULT = /^(?!.*--)[A-Za-z0-9-]{3,24}$/;
|
|
232
|
+
const AZURE_SECRET = /^[A-Za-z0-9-]{1,127}$/;
|
|
233
|
+
const AZURE_VERSION = /^[A-Za-z0-9]{32}$/;
|
|
234
|
+
/**
|
|
235
|
+
* `azure-kv://<vault>/<name>[/<version>]` → `az keyvault secret show`, through the Azure CLI so neither the Azure SDK
|
|
236
|
+
* nor an Entra ID token flow enters the dependency tree. The CLI rather than `GET {vault}/secrets/{name}` with a token
|
|
237
|
+
* from `az account get-access-token`: one process instead of two, and the CLI already knows the vault DNS suffix of
|
|
238
|
+
* the signed-in cloud (`vault.azure.net`, `vault.azure.cn`, `vault.usgovcloudapi.net`) and every way to sign in
|
|
239
|
+
* (`az login`, a service principal, a managed identity, federated CI credentials).
|
|
240
|
+
* https://learn.microsoft.com/en-us/cli/azure/keyvault/secret#az-keyvault-secret-show
|
|
241
|
+
*/
|
|
242
|
+
export function azureKeyVaultSource(exec = defaultExec) {
|
|
243
|
+
return {
|
|
244
|
+
scheme: "azure-kv",
|
|
245
|
+
form: "`azure-kv://vault/name` or `azure-kv://vault/name/version`",
|
|
246
|
+
resolvedBy: "`az keyvault secret show --vault-name vault --name name [--version version] --query value --output json` (Azure CLI; credentials and cloud from `az login` and the CLI's other conventions). The version defaults to the latest.",
|
|
247
|
+
async resolve(ref, env) {
|
|
248
|
+
const parts = stripScheme(ref, "azure-kv").split("/");
|
|
249
|
+
if (parts.length < 2 || parts.length > 3)
|
|
250
|
+
throw unresolved(ref, AZURE_KV_FORM);
|
|
251
|
+
const [vault, name, version] = parts;
|
|
252
|
+
if (!AZURE_VAULT.test(vault) || !AZURE_SECRET.test(name) || (version !== undefined && !AZURE_VERSION.test(version)))
|
|
253
|
+
throw unresolved(ref, AZURE_KV_FORM);
|
|
254
|
+
const pinned = version === undefined ? [] : [version];
|
|
255
|
+
// JSON, not `-o tsv`: tsv cannot tell a value's own trailing newline from the one the CLI ends its output with.
|
|
256
|
+
const args = ["keyvault", "secret", "show", "--vault-name", vault, "--name", name, ...pinned.flatMap((v) => ["--version", v]), "--query", "value", "--output", "json"];
|
|
257
|
+
const value = parseJson(await runCli(exec, ref, "az", args, env, [vault, name, ...pinned]));
|
|
258
|
+
if (typeof value !== "string")
|
|
259
|
+
throw unresolved(ref, "the secret has no value");
|
|
260
|
+
return value;
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
/** Bitwarden secret ids are UUIDs (`bws secret get` parses its argument as one). */
|
|
265
|
+
const BWS_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
266
|
+
/**
|
|
267
|
+
* `bws://<secret-id>` → `bws secret get`, through the Bitwarden Secrets Manager CLI
|
|
268
|
+
* (https://bitwarden.com/help/secrets-manager-cli/). The machine account's access token comes from
|
|
269
|
+
* `BWS_ACCESS_TOKEN`, a self-hosted server from `BWS_SERVER_URL` (both read by the CLI itself: crates/bws/src/cli.rs
|
|
270
|
+
* in bitwarden/sdk-sm). `--color no`: the CLI colours its JSON whenever it believes the terminal supports colour,
|
|
271
|
+
* which `FORCE_COLOR` in CI makes it believe.
|
|
272
|
+
*/
|
|
273
|
+
export function bitwardenSecretsManagerSource(exec = defaultExec) {
|
|
274
|
+
return {
|
|
275
|
+
scheme: "bws",
|
|
276
|
+
form: "`bws://secret-id`",
|
|
277
|
+
resolvedBy: "`bws secret get secret-id --output json --color no` (Bitwarden Secrets Manager CLI; the machine account's token from `BWS_ACCESS_TOKEN`, a self-hosted server from `BWS_SERVER_URL`). `secret-id` is the secret's UUID.",
|
|
278
|
+
async resolve(ref, env) {
|
|
279
|
+
const id = stripScheme(ref, "bws");
|
|
280
|
+
if (!BWS_ID.test(id))
|
|
281
|
+
throw unresolved(ref, "expected bws://<secret-id>, the secret's UUID");
|
|
282
|
+
const response = parseJson(await runCli(exec, ref, "bws", ["secret", "get", id, "--output", "json", "--color", "no"], env, [id]));
|
|
283
|
+
// Never echo the response (or a fragment of it) in these messages: it holds the value.
|
|
284
|
+
const value = isRecord(response) ? response.value : undefined;
|
|
285
|
+
if (typeof value !== "string")
|
|
286
|
+
throw unresolved(ref, "the Bitwarden CLI returned no value");
|
|
287
|
+
return value;
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// ---------------------------------------------------------------------------
|
|
292
|
+
// HTTP-backed sources: HashiCorp Vault, 1Password Connect
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
/** A variable the source cannot work without; unset or empty is SECRET_UNRESOLVED naming it. */
|
|
295
|
+
function requiredVar(ref, env, name) {
|
|
296
|
+
const v = env[name];
|
|
297
|
+
if (v === undefined || v === "")
|
|
298
|
+
throw unresolved(ref, `${name} is not set`, { variable: name });
|
|
299
|
+
return v;
|
|
300
|
+
}
|
|
301
|
+
/** A server address from the environment: an absolute http(s) URL. */
|
|
302
|
+
function requiredUrl(ref, env, name) {
|
|
303
|
+
const v = requiredVar(ref, env, name);
|
|
304
|
+
let url;
|
|
305
|
+
try {
|
|
306
|
+
url = new URL(v);
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
url = undefined;
|
|
310
|
+
}
|
|
311
|
+
if (url?.protocol !== "http:" && url?.protocol !== "https:")
|
|
312
|
+
throw unresolved(ref, `${name} is not an http(s) URL`, { variable: name });
|
|
313
|
+
return v;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* The adapters' HTTP client for a secret service: its timeout (SPONSON_HTTP_TIMEOUT_MS), its retries of a 5xx or a
|
|
317
|
+
* dropped connection (SPONSON_HTTP_RETRIES), and the token masked in any error text it builds.
|
|
318
|
+
*/
|
|
319
|
+
function secretClient(service, baseUrl, token, authHeader, headers, env) {
|
|
320
|
+
return apiClient({ adapter: service, baseUrl, token, authHeader, headers, env, redact: (s) => s.split(token).join("***") });
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* GET a path; any failure is SECRET_UNRESOLVED. A 404 reads as `notFound`. An answer that is not JSON is reported
|
|
324
|
+
* without its text, which is where the value would be; every other failure keeps the client's message (method,
|
|
325
|
+
* path, status and the service's own error, which never holds the value; the token is masked).
|
|
326
|
+
*/
|
|
327
|
+
async function httpRead(ref, api, path, notFound) {
|
|
328
|
+
try {
|
|
329
|
+
return await api.get(path);
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
if (isProviderError(e, "PROVIDER_NOT_FOUND"))
|
|
333
|
+
throw unresolved(ref, notFound, { status: 404 });
|
|
334
|
+
if (isProviderError(e, "PROVIDER_RESPONSE"))
|
|
335
|
+
throw unresolved(ref, `${api.adapter}: GET ${path} answered with something that is not JSON`);
|
|
336
|
+
if (isProviderError(e))
|
|
337
|
+
throw unresolved(ref, e.message, e.details.status === undefined ? {} : { status: e.details.status });
|
|
338
|
+
throw unresolved(ref, e.message);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const VAULT_FORM = "expected vault://<mount>/<path>#<key>";
|
|
342
|
+
/** `vault://<mount>/<path>#<key>`, split; `.` and `..` segments are refused so a reference cannot climb out of the mount. */
|
|
343
|
+
function vaultRef(ref) {
|
|
344
|
+
const body = stripScheme(ref, "vault");
|
|
345
|
+
const hash = body.indexOf("#");
|
|
346
|
+
const segments = (hash < 0 ? body : body.slice(0, hash)).split("/");
|
|
347
|
+
const key = hash < 0 ? "" : body.slice(hash + 1);
|
|
348
|
+
if (key === "" || segments.length < 2 || segments.some((s) => s === "" || s === "." || s === ".."))
|
|
349
|
+
throw unresolved(ref, VAULT_FORM);
|
|
350
|
+
const [mount, ...path] = segments;
|
|
351
|
+
return { mount, path, key };
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* `vault://<mount>/<path>#<key>` → HashiCorp Vault's KV v2 "read secret version", `GET /v1/<mount>/data/<path>`
|
|
355
|
+
* (https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2), over the adapters' HTTP client, no SDK. The
|
|
356
|
+
* address is `VAULT_ADDR`, the token `VAULT_TOKEN` (sent as `X-Vault-Token`), and `VAULT_NAMESPACE`, when set, is
|
|
357
|
+
* sent as `X-Vault-Namespace` (Vault Enterprise, HCP Vault Dedicated: https://developer.hashicorp.com/vault/api-docs).
|
|
358
|
+
* The mount is the first segment; the latest version is read. `#key` picks one key of the secret's map.
|
|
359
|
+
*/
|
|
360
|
+
export const vaultSecretSource = {
|
|
361
|
+
scheme: "vault",
|
|
362
|
+
form: "`vault://mount/path#KEY`",
|
|
363
|
+
resolvedBy: "HashiCorp Vault KV v2, `GET $VAULT_ADDR/v1/mount/data/path` with `X-Vault-Token: $VAULT_TOKEN` (and `X-Vault-Namespace: $VAULT_NAMESPACE` when set); the latest version's `KEY`. The mount is the first segment.",
|
|
364
|
+
async resolve(ref, env) {
|
|
365
|
+
const { mount, path, key } = vaultRef(ref);
|
|
366
|
+
const addr = requiredUrl(ref, env, "VAULT_ADDR");
|
|
367
|
+
const token = requiredVar(ref, env, "VAULT_TOKEN");
|
|
368
|
+
const namespace = env.VAULT_NAMESPACE;
|
|
369
|
+
const api = secretClient("vault", addr, token, "header:X-Vault-Token", namespace ? { "X-Vault-Namespace": namespace } : {}, env);
|
|
370
|
+
const url = `/v1/${encodeURIComponent(mount)}/data/${path.map(encodeURIComponent).join("/")}`;
|
|
371
|
+
const where = `${mount}/${path.join("/")}`;
|
|
372
|
+
// Vault answers 404 both for a path that does not exist and for one the token may not see.
|
|
373
|
+
const body = await httpRead(ref, api, url, `no secret at ${where} (or the token may not read it; a KV v1 mount is not supported)`);
|
|
374
|
+
// Never echo the body (or a fragment of it) in these messages: it holds the values.
|
|
375
|
+
const data = isRecord(body) && isRecord(body.data) ? body.data.data : undefined;
|
|
376
|
+
if (!isRecord(data))
|
|
377
|
+
throw unresolved(ref, `the latest version of ${where} is deleted or destroyed, or the answer is not a KV v2 secret`);
|
|
378
|
+
return scalarField(ref, data, key, where);
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
/** One key of a secret's map as a string; numbers and booleans are written as JSON writes them. */
|
|
382
|
+
function scalarField(ref, fields, key, where) {
|
|
383
|
+
const v = fields[key];
|
|
384
|
+
if (v === undefined)
|
|
385
|
+
throw unresolved(ref, `${where} has no key ${key}`);
|
|
386
|
+
if (typeof v !== "string" && typeof v !== "number" && typeof v !== "boolean")
|
|
387
|
+
throw unresolved(ref, `key ${key} of ${where} is not a string, number or boolean`);
|
|
388
|
+
return String(v);
|
|
389
|
+
}
|
|
390
|
+
const OP_CONNECT_FORM = "expected op-connect://<vault>/<item>/<field> or op-connect://<vault>/<item>/<section>/<field>";
|
|
391
|
+
/** Vault and item ids as Connect shows them (`ytrfte14kw1uex5txaore1emkz`); anything else is looked up by name. */
|
|
392
|
+
const OP_ID = /^[a-z0-9]{26}$/;
|
|
393
|
+
function opConnectRef(ref) {
|
|
394
|
+
const parts = stripScheme(ref, "op-connect").split("/");
|
|
395
|
+
if (parts.length < 3 || parts.length > 4 || parts.some((p) => p === ""))
|
|
396
|
+
throw unresolved(ref, OP_CONNECT_FORM);
|
|
397
|
+
const [vault, item] = parts;
|
|
398
|
+
return parts.length === 4 ? { vault, item, section: parts[2], field: parts[3] } : { vault, item, field: parts[2] };
|
|
399
|
+
}
|
|
400
|
+
/** A filter value in Connect's SCIM-style `filter` (`name eq "Demo Vault"`), quotes and backslashes escaped. */
|
|
401
|
+
function scimString(s) {
|
|
402
|
+
return `"${s.replace(/[\\"]/g, (c) => `\\${c}`)}"`;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* The id of the one vault (`attr` = `name`) or item (`title`) called `name`. The filter narrows the list; the exact
|
|
406
|
+
* comparison here decides, so a server that ignored the filter would not change the answer.
|
|
407
|
+
*/
|
|
408
|
+
async function opConnectFind(ref, api, list, attr, name, what) {
|
|
409
|
+
const body = await httpRead(ref, api, `${list}?filter=${encodeURIComponent(`${attr} eq ${scimString(name)}`)}`, `no ${what} named ${name}`);
|
|
410
|
+
const found = (Array.isArray(body) ? body : []).filter((e) => isRecord(e) && e[attr] === name && typeof e.id === "string");
|
|
411
|
+
if (found.length === 0)
|
|
412
|
+
throw unresolved(ref, `no ${what} named ${name}`);
|
|
413
|
+
if (found.length > 1)
|
|
414
|
+
throw unresolved(ref, `${found.length} ${what}s are named ${name}; use the id instead`);
|
|
415
|
+
return found[0].id;
|
|
416
|
+
}
|
|
417
|
+
/** The fields of an item's section, matched by the section's id or label. */
|
|
418
|
+
function inSection(ref, item, fields, section) {
|
|
419
|
+
const sections = (Array.isArray(item.sections) ? item.sections : []).filter(isRecord);
|
|
420
|
+
const ids = new Set(sections.filter((s) => s.id === section || s.label === section).map((s) => s.id));
|
|
421
|
+
if (ids.size === 0)
|
|
422
|
+
throw unresolved(ref, `the item has no section ${section}`);
|
|
423
|
+
return fields.filter((f) => isRecord(f.section) && ids.has(f.section.id));
|
|
424
|
+
}
|
|
425
|
+
/** The value of the one field matched by id, else by label, as `op read` matches them. */
|
|
426
|
+
function opConnectField(ref, item, r) {
|
|
427
|
+
if (!isRecord(item) || !Array.isArray(item.fields))
|
|
428
|
+
throw unresolved(ref, "the item has no fields");
|
|
429
|
+
let fields = item.fields.filter(isRecord);
|
|
430
|
+
if (r.section !== undefined)
|
|
431
|
+
fields = inSection(ref, item, fields, r.section);
|
|
432
|
+
const byId = fields.filter((f) => f.id === r.field);
|
|
433
|
+
const matches = byId.length > 0 ? byId : fields.filter((f) => f.label === r.field);
|
|
434
|
+
if (matches.length === 0)
|
|
435
|
+
throw unresolved(ref, `the item has no field ${r.field}`);
|
|
436
|
+
if (matches.length > 1)
|
|
437
|
+
throw unresolved(ref, `${matches.length} fields of the item are labelled ${r.field}; name its section or use the field id`);
|
|
438
|
+
// Never echo the value (or a fragment of it) in these messages.
|
|
439
|
+
const value = matches[0].value;
|
|
440
|
+
if (typeof value !== "string" || value === "")
|
|
441
|
+
throw unresolved(ref, `field ${r.field} has no value`);
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* `op-connect://<vault>/<item>/[<section>/]<field>` → a 1Password Connect server's REST API
|
|
446
|
+
* (https://www.1password.dev/connect/api-reference/): `GET /v1/vaults/{vault}/items/{item}`, bearer
|
|
447
|
+
* `OP_CONNECT_TOKEN`, at `OP_CONNECT_HOST` (the variables 1Password's own Connect SDKs and `op` read). Vaults and
|
|
448
|
+
* items are named by id or by name / title (looked up with `GET /v1/vaults?filter=name eq "…"` and
|
|
449
|
+
* `GET /v1/vaults/{vault}/items?filter=title eq "…"`; a name must be unique); fields by id or label.
|
|
450
|
+
*/
|
|
451
|
+
export const opConnectSecretSource = {
|
|
452
|
+
scheme: "op-connect",
|
|
453
|
+
form: "`op-connect://vault/item/field` or `op-connect://vault/item/section/field`",
|
|
454
|
+
resolvedBy: "a 1Password Connect server, `GET $OP_CONNECT_HOST/v1/vaults/vault/items/item` with `Authorization: Bearer $OP_CONNECT_TOKEN`. `vault` and `item` are ids or unique names (looked up with `?filter=`); `section` and `field` are ids or labels.",
|
|
455
|
+
async resolve(ref, env) {
|
|
456
|
+
const r = opConnectRef(ref);
|
|
457
|
+
const host = requiredUrl(ref, env, "OP_CONNECT_HOST");
|
|
458
|
+
const api = secretClient("1password-connect", host, requiredVar(ref, env, "OP_CONNECT_TOKEN"), "bearer", {}, env);
|
|
459
|
+
const vaultId = OP_ID.test(r.vault) ? r.vault : await opConnectFind(ref, api, "/v1/vaults", "name", r.vault, "vault");
|
|
460
|
+
const itemId = OP_ID.test(r.item) ? r.item : await opConnectFind(ref, api, `/v1/vaults/${vaultId}/items`, "title", r.item, "item");
|
|
461
|
+
const item = await httpRead(ref, api, `/v1/vaults/${vaultId}/items/${itemId}`, `no item ${r.item} in vault ${r.vault} (or the token may not read it)`);
|
|
462
|
+
return opConnectField(ref, item, r);
|
|
463
|
+
},
|
|
464
|
+
};
|
|
465
|
+
function isRecord(v) {
|
|
466
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
467
|
+
}
|
|
468
|
+
function parseJson(text) {
|
|
469
|
+
try {
|
|
470
|
+
return JSON.parse(text);
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
return undefined;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"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"}
|
package/dist/sigv4.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** The credentials a request is signed with. The secret never leaves this module except as an HMAC. */
|
|
2
|
+
export interface SigV4Credentials {
|
|
3
|
+
accessKeyId: string;
|
|
4
|
+
secretAccessKey: string;
|
|
5
|
+
/** Temporary credentials (STS) also send their session token, as `X-Amz-Security-Token`. */
|
|
6
|
+
sessionToken?: string;
|
|
7
|
+
}
|
|
8
|
+
/** One request to sign: everything the signature covers. */
|
|
9
|
+
export interface SigV4Request {
|
|
10
|
+
method: string;
|
|
11
|
+
/** The absolute URL as it will be sent (path already percent-encoded, query included). */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Headers that will be sent (lower-case names); every one of them is signed. */
|
|
14
|
+
headers: Record<string, string>;
|
|
15
|
+
/** The body exactly as sent; empty when there is none. */
|
|
16
|
+
body: string;
|
|
17
|
+
}
|
|
18
|
+
/** Where and how to sign. */
|
|
19
|
+
export interface SigV4Scope {
|
|
20
|
+
region: string;
|
|
21
|
+
service: string;
|
|
22
|
+
/** The signing time; `X-Amz-Date` is derived from it. */
|
|
23
|
+
date: Date;
|
|
24
|
+
/**
|
|
25
|
+
* Send and sign `X-Amz-Content-Sha256` (S3 requires it; other services accept it). Default true; AWS's generic
|
|
26
|
+
* test suite signs without it.
|
|
27
|
+
*/
|
|
28
|
+
contentSha256Header?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** RFC 3986 encoding as SigV4 wants it: unreserved characters as they are, every other UTF-8 byte as `%XX`. */
|
|
31
|
+
export declare function uriEncode(s: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* The canonical URI: each path segment encoded once (S3) or twice (every other service, as the AWS docs require),
|
|
34
|
+
* starting from the path as sent.
|
|
35
|
+
*/
|
|
36
|
+
export declare function canonicalUri(pathname: string, service: string): string;
|
|
37
|
+
/** The canonical query string: every parameter encoded, sorted by name then value; `?cors` is `cors=`. */
|
|
38
|
+
export declare function canonicalQuery(search: string): string;
|
|
39
|
+
/** `YYYYMMDDTHHMMSSZ` */
|
|
40
|
+
export declare function amzDate(d: Date): string;
|
|
41
|
+
/** The canonical request, and the signed-headers list it names. `headers` must include `host`. */
|
|
42
|
+
export declare function canonicalRequest(req: SigV4Request, service: string): {
|
|
43
|
+
request: string;
|
|
44
|
+
signedHeaders: string;
|
|
45
|
+
};
|
|
46
|
+
/** `<date>/<region>/<service>/aws4_request` */
|
|
47
|
+
export declare function credentialScope(scope: Pick<SigV4Scope, "region" | "service" | "date">): string;
|
|
48
|
+
/** The string to sign for a canonical request. */
|
|
49
|
+
export declare function stringToSign(canonical: string, scope: Pick<SigV4Scope, "region" | "service" | "date">): string;
|
|
50
|
+
/** The hex signature of a string to sign. */
|
|
51
|
+
export declare function signature(secretAccessKey: string, scope: Pick<SigV4Scope, "region" | "service" | "date">, toSign: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Sign a request: the headers to add to it (`x-amz-date`, `x-amz-content-sha256`, `x-amz-security-token` when the
|
|
54
|
+
* credentials are temporary, and `authorization`). Every header of `req` is signed, plus `host` from the URL.
|
|
55
|
+
*/
|
|
56
|
+
export declare function signRequest(req: SigV4Request, creds: SigV4Credentials, scope: SigV4Scope): Record<string, string>;
|