@hubble-ventures/infisicml 1.2.1

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/LICENSE +21 -0
  3. package/README.md +316 -0
  4. package/dist/aliases.d.ts +20 -0
  5. package/dist/aliases.d.ts.map +1 -0
  6. package/dist/aliases.js +35 -0
  7. package/dist/aliases.js.map +1 -0
  8. package/dist/ci-skip.d.ts +27 -0
  9. package/dist/ci-skip.d.ts.map +1 -0
  10. package/dist/ci-skip.js +82 -0
  11. package/dist/ci-skip.js.map +1 -0
  12. package/dist/cli.d.ts +3 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +150 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/commands/export-gha.d.ts +11 -0
  17. package/dist/commands/export-gha.d.ts.map +1 -0
  18. package/dist/commands/export-gha.js +79 -0
  19. package/dist/commands/export-gha.js.map +1 -0
  20. package/dist/commands/list.d.ts +2 -0
  21. package/dist/commands/list.d.ts.map +1 -0
  22. package/dist/commands/list.js +35 -0
  23. package/dist/commands/list.js.map +1 -0
  24. package/dist/commands/paths.d.ts +8 -0
  25. package/dist/commands/paths.d.ts.map +1 -0
  26. package/dist/commands/paths.js +30 -0
  27. package/dist/commands/paths.js.map +1 -0
  28. package/dist/commands/pull.d.ts +11 -0
  29. package/dist/commands/pull.d.ts.map +1 -0
  30. package/dist/commands/pull.js +65 -0
  31. package/dist/commands/pull.js.map +1 -0
  32. package/dist/commands/run.d.ts +9 -0
  33. package/dist/commands/run.d.ts.map +1 -0
  34. package/dist/commands/run.js +30 -0
  35. package/dist/commands/run.js.map +1 -0
  36. package/dist/commands/validate.d.ts +2 -0
  37. package/dist/commands/validate.d.ts.map +1 -0
  38. package/dist/commands/validate.js +33 -0
  39. package/dist/commands/validate.js.map +1 -0
  40. package/dist/config.d.ts +58 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +68 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/dotenv.d.ts +6 -0
  45. package/dist/dotenv.d.ts.map +1 -0
  46. package/dist/dotenv.js +31 -0
  47. package/dist/dotenv.js.map +1 -0
  48. package/dist/env-slug.d.ts +3 -0
  49. package/dist/env-slug.d.ts.map +1 -0
  50. package/dist/env-slug.js +7 -0
  51. package/dist/env-slug.js.map +1 -0
  52. package/dist/github-env.d.ts +10 -0
  53. package/dist/github-env.d.ts.map +1 -0
  54. package/dist/github-env.js +37 -0
  55. package/dist/github-env.js.map +1 -0
  56. package/dist/hooks.d.ts +17 -0
  57. package/dist/hooks.d.ts.map +1 -0
  58. package/dist/hooks.js +19 -0
  59. package/dist/hooks.js.map +1 -0
  60. package/dist/include.d.ts +46 -0
  61. package/dist/include.d.ts.map +1 -0
  62. package/dist/include.js +82 -0
  63. package/dist/include.js.map +1 -0
  64. package/dist/index.d.ts +16 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +15 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/manifest.d.ts +105 -0
  69. package/dist/manifest.d.ts.map +1 -0
  70. package/dist/manifest.js +153 -0
  71. package/dist/manifest.js.map +1 -0
  72. package/dist/optional-keys.d.ts +4 -0
  73. package/dist/optional-keys.d.ts.map +1 -0
  74. package/dist/optional-keys.js +11 -0
  75. package/dist/optional-keys.js.map +1 -0
  76. package/dist/providers/local.d.ts +38 -0
  77. package/dist/providers/local.d.ts.map +1 -0
  78. package/dist/providers/local.js +76 -0
  79. package/dist/providers/local.js.map +1 -0
  80. package/dist/providers/remote.d.ts +52 -0
  81. package/dist/providers/remote.d.ts.map +1 -0
  82. package/dist/providers/remote.js +166 -0
  83. package/dist/providers/remote.js.map +1 -0
  84. package/dist/providers/types.d.ts +14 -0
  85. package/dist/providers/types.d.ts.map +1 -0
  86. package/dist/providers/types.js +2 -0
  87. package/dist/providers/types.js.map +1 -0
  88. package/dist/pull.d.ts +15 -0
  89. package/dist/pull.d.ts.map +1 -0
  90. package/dist/pull.js +67 -0
  91. package/dist/pull.js.map +1 -0
  92. package/dist/registry.d.ts +14 -0
  93. package/dist/registry.d.ts.map +1 -0
  94. package/dist/registry.js +35 -0
  95. package/dist/registry.js.map +1 -0
  96. package/package.json +66 -0
  97. package/schema/secrets.schema.json +105 -0
@@ -0,0 +1,153 @@
1
+ import { resolve, sep } from "node:path";
2
+ import { z } from "zod";
3
+ const pathPattern = /^[a-z0-9_/-]+$/;
4
+ const pathsSchema = z
5
+ .array(z.string().regex(pathPattern))
6
+ .min(1, "paths must be a non-empty array");
7
+ const envVarNamePattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
8
+ const aliasSourceSchema = z
9
+ .string()
10
+ .regex(envVarNamePattern, "alias source must be a valid env var name");
11
+ const aliasTargetSchema = z
12
+ .string()
13
+ .regex(envVarNamePattern, "alias target must be a valid env var name");
14
+ // Key-level allowlist. When present, only these env var names are emitted from
15
+ // whatever the folders yielded (after aliases). `.min(1)` because an empty
16
+ // allowlist is almost certainly a mistake — omit the field to emit every key.
17
+ const includeSchema = z
18
+ .array(z.string().regex(envVarNamePattern, "include entry must be a valid env var name"))
19
+ .min(1, "include must be a non-empty array");
20
+ // How secrets are read from the vault. `folder` (default) fetches whole folders
21
+ // and filters locally. `keys` fetches only the exact keys `include` resolves to,
22
+ // so the vault never transmits the rest — wire-level least privilege. `keys`
23
+ // requires an `include` allowlist (enforced by resolveFetchKeys / validate,
24
+ // since the requirement depends on the resolved profile).
25
+ const fetchModeSchema = z.enum(["folder", "keys"]);
26
+ export const secretsManifestSchema = z.object({
27
+ $schema: z.string().optional(),
28
+ paths: pathsSchema,
29
+ profiles: z
30
+ .record(z.string(), z.object({
31
+ paths: pathsSchema,
32
+ // Replaces the root `include` for this profile when set; if omitted,
33
+ // the root `include` applies (same replace-not-merge as `paths`).
34
+ include: includeSchema.optional(),
35
+ // Overrides the root `fetch` for this profile when set (same
36
+ // replace-not-merge as `paths` / `include`).
37
+ fetch: fetchModeSchema.optional(),
38
+ }))
39
+ .optional(),
40
+ ci: z
41
+ .object({
42
+ skipWhenEnv: z.array(z.string()).optional(),
43
+ stubInCi: z.boolean().optional(),
44
+ })
45
+ .optional(),
46
+ output: z
47
+ .string()
48
+ .regex(/^[^/\\]+$/)
49
+ .optional(),
50
+ // Map a pulled secret to the extra env var name(s) a build/runtime expects.
51
+ // The vault names a secret once (e.g. /clerk exposes the publishable key as
52
+ // CLERK_PUBLISHABLE_KEY), but build tools inline it by a tool-specific,
53
+ // convention-prefixed name — Vite reads VITE_*, Next reads NEXT_PUBLIC_*.
54
+ // Declaring the mapping here means every consumer (CI export-gha, local pull)
55
+ // emits the right name instead of each workflow re-deriving it.
56
+ aliases: z
57
+ .record(aliasSourceSchema, z.union([aliasTargetSchema, z.array(aliasTargetSchema).min(1)]))
58
+ .optional(),
59
+ // Emit only these keys from whatever the folders yielded (default-deny key
60
+ // selection). Applied after `aliases`, to the final set of names — so a client
61
+ // can pull a shared vendor folder but emit only its public key. Absent = emit
62
+ // all (backward compatible). A per-profile `include` replaces this one.
63
+ include: includeSchema.optional(),
64
+ // Read strategy: `folder` (default) pulls whole folders and filters locally;
65
+ // `keys` pulls only the keys `include` resolves to (least privilege at the
66
+ // wire). A per-profile `fetch` replaces this one.
67
+ fetch: fetchModeSchema.optional(),
68
+ environments: z
69
+ .record(z.string(), z.object({
70
+ optionalKeys: z.array(z.string()).optional(),
71
+ }))
72
+ .optional(),
73
+ });
74
+ export function loadManifestJson(raw) {
75
+ return secretsManifestSchema.parse(raw);
76
+ }
77
+ /** Profile paths replace default paths when a profile is set. */
78
+ export function resolvePaths(manifest, profile) {
79
+ if (profile) {
80
+ const profileConfig = manifest.profiles?.[profile];
81
+ if (!profileConfig) {
82
+ throw new Error(`Unknown profile '${profile}' in secrets.json`);
83
+ }
84
+ return profileConfig.paths;
85
+ }
86
+ return manifest.paths;
87
+ }
88
+ /**
89
+ * Resolve the effective key allowlist. A profile's `include` replaces the root
90
+ * `include` when the profile defines it; otherwise the root `include` applies.
91
+ * Returns `undefined` when no allowlist is in effect (emit all keys).
92
+ */
93
+ export function resolveInclude(manifest, profile) {
94
+ if (profile) {
95
+ const profileInclude = manifest.profiles?.[profile]?.include;
96
+ if (profileInclude !== undefined)
97
+ return profileInclude;
98
+ }
99
+ return manifest.include;
100
+ }
101
+ /**
102
+ * Resolve the effective fetch mode. A profile's `fetch` replaces the root
103
+ * `fetch` when the profile defines it; otherwise the root `fetch` applies.
104
+ * Defaults to `"folder"` (whole-folder read + local filter) when unset.
105
+ */
106
+ export function resolveFetchMode(manifest, profile) {
107
+ if (profile) {
108
+ const profileFetch = manifest.profiles?.[profile]?.fetch;
109
+ if (profileFetch !== undefined)
110
+ return profileFetch;
111
+ }
112
+ return manifest.fetch ?? "folder";
113
+ }
114
+ /**
115
+ * Cross-field rule: `fetch: "keys"` requires an `include` allowlist, because
116
+ * key mode fetches exactly the keys `include` names. The check spans the root
117
+ * and every profile (a profile's `fetch`/`include` each replace the root's), so
118
+ * every runnable combination is covered. Returns human-readable issue strings
119
+ * (empty when consistent) for `validate` to surface. Zod can't express this —
120
+ * the requirement depends on the resolved profile.
121
+ */
122
+ export function checkFetchIncludeConsistency(manifest) {
123
+ const issues = [];
124
+ const check = (profile, label) => {
125
+ if (resolveFetchMode(manifest, profile) === "keys" &&
126
+ resolveInclude(manifest, profile) === undefined) {
127
+ issues.push(`fetch: "keys" requires an include allowlist (${label})`);
128
+ }
129
+ };
130
+ check(undefined, "root");
131
+ for (const name of Object.keys(manifest.profiles ?? {})) {
132
+ check(name, `profile "${name}"`);
133
+ }
134
+ return issues;
135
+ }
136
+ export function normalizeFolderPath(folder) {
137
+ return `/${folder.replace(/^\/+/, "")}`;
138
+ }
139
+ export function resolveSecretsOutputPath(manifestDir, outputName) {
140
+ if (outputName !== outputName.split("/").pop() ||
141
+ outputName.includes("..") ||
142
+ outputName.length === 0) {
143
+ throw new Error(`Invalid secrets output filename: ${outputName}`);
144
+ }
145
+ const resolvedDir = resolve(manifestDir);
146
+ const resolvedOut = resolve(manifestDir, outputName);
147
+ if (resolvedOut !== resolvedDir &&
148
+ !resolvedOut.startsWith(resolvedDir + sep)) {
149
+ throw new Error(`Secrets output escapes manifest directory: ${outputName}`);
150
+ }
151
+ return resolvedOut;
152
+ }
153
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { SecretsManifest } from "./manifest.js";
2
+ export declare function resolveOptionalKeys(manifest: SecretsManifest, envName: string): string[];
3
+ export declare function logMissingOptionalKeys(merged: Record<string, string>, optionalKeys: string[]): void;
4
+ //# sourceMappingURL=optional-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optional-keys.d.ts","sourceRoot":"","sources":["../src/optional-keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,GACd,MAAM,EAAE,CAEV;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,EAAE,MAAM,EAAE,GACrB,IAAI,CAQN"}
@@ -0,0 +1,11 @@
1
+ export function resolveOptionalKeys(manifest, envName) {
2
+ return manifest.environments?.[envName]?.optionalKeys ?? [];
3
+ }
4
+ export function logMissingOptionalKeys(merged, optionalKeys) {
5
+ for (const key of optionalKeys) {
6
+ if (!merged[key]?.trim()) {
7
+ console.log(`::notice::Optional secret ${key} not set (allowed for this environment)`);
8
+ }
9
+ }
10
+ }
11
+ //# sourceMappingURL=optional-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optional-keys.js","sourceRoot":"","sources":["../src/optional-keys.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,mBAAmB,CACjC,QAAyB,EACzB,OAAe;IAEf,OAAO,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,MAA8B,EAC9B,YAAsB;IAEtB,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CACT,6BAA6B,GAAG,yCAAyC,CAC1E,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type SpawnSyncReturns } from "node:child_process";
2
+ import type { SecretsProvider } from "./types.js";
3
+ export type SpawnExportFn = (command: string, args: string[], cwd: string) => SpawnSyncReturns<string>;
4
+ export type LocalProviderOptions = {
5
+ projectId: string;
6
+ cwd?: string;
7
+ maxAttempts?: number;
8
+ spawn?: SpawnExportFn;
9
+ };
10
+ /**
11
+ * Dev-time provider: shells out to the `infisical` CLI using the developer's
12
+ * `infisical login` session. No machine identity or tokens required locally.
13
+ */
14
+ export declare class LocalProvider implements SecretsProvider {
15
+ private readonly projectId;
16
+ private readonly cwd;
17
+ private readonly maxAttempts;
18
+ private readonly spawnFn;
19
+ constructor(options: LocalProviderOptions);
20
+ exportFolder(envName: string, folder: string): Promise<Record<string, string>>;
21
+ /**
22
+ * Select only the named keys from a folder.
23
+ *
24
+ * The `infisical` CLI has no true single-secret *server* fetch — `secrets get`
25
+ * pulls the whole folder from the API and filters client-side (running it per
26
+ * key would transfer the folder once per key). So we fetch the folder once via
27
+ * {@link exportFolder} and select the requested keys locally. This means the
28
+ * **wire-level** least-privilege guarantee holds only for the CI/REST lane
29
+ * ({@link RemoteProvider}); the local lane narrows what's *written*, not what
30
+ * the vault transmits. Crucially, it also inherits `exportFolder`'s retry and
31
+ * its clear `"infisical export failed…"` error, so a transient CLI failure
32
+ * throws an infrastructure error rather than silently dropping keys into the
33
+ * generic "not produced by any folder" path.
34
+ */
35
+ exportKeys(envName: string, folder: string, keys: string[]): Promise<Record<string, string>>;
36
+ }
37
+ export declare function commandExists(cmd: string): boolean;
38
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,gBAAgB,EAAa,MAAM,oBAAoB,CAAC;AAGtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,KACR,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAE9B,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC;AAUF;;;GAGG;AACH,qBAAa,aAAc,YAAW,eAAe;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,OAAO,EAAE,oBAAoB;IAOnC,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAkClC;;;;;;;;;;;;;OAaG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAQnC;AAMD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGlD"}
@@ -0,0 +1,76 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { parseDotenv } from "../dotenv.js";
3
+ import { normalizeFolderPath } from "../manifest.js";
4
+ function defaultSpawn(command, args, cwd) {
5
+ return spawnSync(command, args, { encoding: "utf8", cwd });
6
+ }
7
+ /**
8
+ * Dev-time provider: shells out to the `infisical` CLI using the developer's
9
+ * `infisical login` session. No machine identity or tokens required locally.
10
+ */
11
+ export class LocalProvider {
12
+ projectId;
13
+ cwd;
14
+ maxAttempts;
15
+ spawnFn;
16
+ constructor(options) {
17
+ this.projectId = options.projectId;
18
+ this.cwd = options.cwd ?? process.cwd();
19
+ this.maxAttempts = options.maxAttempts ?? 4;
20
+ this.spawnFn = options.spawn ?? defaultSpawn;
21
+ }
22
+ async exportFolder(envName, folder) {
23
+ const pathArg = normalizeFolderPath(folder);
24
+ let lastMsg = "";
25
+ for (let attempt = 1; attempt <= this.maxAttempts; attempt++) {
26
+ const result = this.spawnFn("infisical", [
27
+ "export",
28
+ `--env=${envName}`,
29
+ `--projectId=${this.projectId}`,
30
+ `--path=${pathArg}`,
31
+ "--format=dotenv",
32
+ "--silent",
33
+ ], this.cwd);
34
+ if (result.status === 0) {
35
+ return parseDotenv(result.stdout ?? "");
36
+ }
37
+ lastMsg = (result.stderr || result.stdout || "").trim();
38
+ if (attempt < this.maxAttempts) {
39
+ const delay = 2 * attempt;
40
+ await sleepSeconds(delay);
41
+ }
42
+ }
43
+ throw new Error(`infisical export failed for ${pathArg} after ${this.maxAttempts} attempts: ${lastMsg || "unknown error"}`);
44
+ }
45
+ /**
46
+ * Select only the named keys from a folder.
47
+ *
48
+ * The `infisical` CLI has no true single-secret *server* fetch — `secrets get`
49
+ * pulls the whole folder from the API and filters client-side (running it per
50
+ * key would transfer the folder once per key). So we fetch the folder once via
51
+ * {@link exportFolder} and select the requested keys locally. This means the
52
+ * **wire-level** least-privilege guarantee holds only for the CI/REST lane
53
+ * ({@link RemoteProvider}); the local lane narrows what's *written*, not what
54
+ * the vault transmits. Crucially, it also inherits `exportFolder`'s retry and
55
+ * its clear `"infisical export failed…"` error, so a transient CLI failure
56
+ * throws an infrastructure error rather than silently dropping keys into the
57
+ * generic "not produced by any folder" path.
58
+ */
59
+ async exportKeys(envName, folder, keys) {
60
+ const all = await this.exportFolder(envName, folder);
61
+ const out = {};
62
+ for (const key of keys) {
63
+ if (key in all)
64
+ out[key] = all[key];
65
+ }
66
+ return out;
67
+ }
68
+ }
69
+ function sleepSeconds(seconds) {
70
+ return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
71
+ }
72
+ export function commandExists(cmd) {
73
+ const result = spawnSync(cmd, ["--version"], { stdio: "ignore" });
74
+ return !result.error && result.status === 0;
75
+ }
76
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAgBrD,SAAS,YAAY,CACnB,OAAe,EACf,IAAc,EACd,GAAW;IAEX,OAAO,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,aAAa;IACP,SAAS,CAAS;IAClB,GAAG,CAAS;IACZ,WAAW,CAAS;IACpB,OAAO,CAAgB;IAExC,YAAY,OAA6B;QACvC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,OAAe,EACf,MAAc;QAEd,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;YAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CACzB,WAAW,EACX;gBACE,QAAQ;gBACR,SAAS,OAAO,EAAE;gBAClB,eAAe,IAAI,CAAC,SAAS,EAAE;gBAC/B,UAAU,OAAO,EAAE;gBACnB,iBAAiB;gBACjB,UAAU;aACX,EACD,IAAI,CAAC,GAAG,CACT,CAAC;YAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC;YAED,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACxD,IAAI,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC;gBAC1B,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,MAAM,IAAI,KAAK,CACb,+BAA+B,OAAO,UAAU,IAAI,CAAC,WAAW,cAAc,OAAO,IAAI,eAAe,EAAE,CAC3G,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,UAAU,CACd,OAAe,EACf,MAAc,EACd,IAAc;QAEd,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,GAAG,GAA2B,EAAE,CAAC;QACvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,IAAI,GAAG;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { SecretsProvider } from "./types.js";
2
+ export type RemoteProviderOptions = {
3
+ domain?: string;
4
+ projectSlug: string;
5
+ /**
6
+ * Infisical machine-identity id bound to a GitHub OIDC auth method. This is
7
+ * the only CI auth lane infisicml supports — there is no client-id/secret
8
+ * fallback.
9
+ */
10
+ identityId: string;
11
+ /**
12
+ * OIDC audience — must match one of the Infisical machine identity's bound
13
+ * audiences. There is no universal default, so it is only appended to the
14
+ * GitHub token request when set. Configure it per repo (see InfisicmlConfig.auth).
15
+ */
16
+ oidcAudience?: string;
17
+ fetchFn?: typeof fetch;
18
+ getOidcJwt?: () => Promise<string>;
19
+ };
20
+ /**
21
+ * CI-time provider: talks to the Infisical REST API directly using a machine
22
+ * identity via GitHub OIDC. No `infisical` CLI, and no long-lived client
23
+ * secret, in the runner — the runner's short-lived OIDC token is exchanged for
24
+ * an Infisical access token.
25
+ */
26
+ export declare class RemoteProvider implements SecretsProvider {
27
+ private readonly domain;
28
+ private readonly projectSlug;
29
+ private readonly identityId;
30
+ private readonly oidcAudience?;
31
+ private readonly fetchFn;
32
+ private readonly getOidcJwt?;
33
+ private token?;
34
+ constructor(options: RemoteProviderOptions);
35
+ exportFolder(envName: string, folder: string): Promise<Record<string, string>>;
36
+ /**
37
+ * Fetch only the named keys from a folder via the single-secret raw endpoint
38
+ * (`GET /api/v3/secrets/raw/{name}`), so the vault transmits nothing beyond
39
+ * the requested keys — wire-level least privilege. `include_imports=true`
40
+ * matches {@link exportFolder}, so a key surfaced into this folder via an
41
+ * Infisical import is still resolved (the single-name endpoint returns only
42
+ * that one secret, so following imports doesn't widen the read). A 404 means
43
+ * the key isn't reachable from this folder and is skipped; the caller merges
44
+ * across folders and enforces genuine absence. The access token is fetched
45
+ * once and reused across keys.
46
+ */
47
+ exportKeys(envName: string, folder: string, keys: string[]): Promise<Record<string, string>>;
48
+ private getAccessToken;
49
+ private fetchOidcJwtFromEnv;
50
+ private fetchWithRetry;
51
+ }
52
+ //# sourceMappingURL=remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/providers/remote.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACpC,CAAC;AAIF;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,eAAe;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAwB;IACpD,OAAO,CAAC,KAAK,CAAC,CAAS;gBAEX,OAAO,EAAE,qBAAqB;IASpC,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAyClC;;;;;;;;;;OAUG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAuCpB,cAAc;YA4Bd,mBAAmB;YAqBnB,cAAc;CAkC7B"}
@@ -0,0 +1,166 @@
1
+ import { normalizeEnvSlug } from "../env-slug.js";
2
+ import { normalizeFolderPath } from "../manifest.js";
3
+ /**
4
+ * CI-time provider: talks to the Infisical REST API directly using a machine
5
+ * identity via GitHub OIDC. No `infisical` CLI, and no long-lived client
6
+ * secret, in the runner — the runner's short-lived OIDC token is exchanged for
7
+ * an Infisical access token.
8
+ */
9
+ export class RemoteProvider {
10
+ domain;
11
+ projectSlug;
12
+ identityId;
13
+ oidcAudience;
14
+ fetchFn;
15
+ getOidcJwt;
16
+ token;
17
+ constructor(options) {
18
+ this.domain = options.domain ?? "https://app.infisical.com";
19
+ this.projectSlug = options.projectSlug;
20
+ this.identityId = options.identityId;
21
+ this.oidcAudience = options.oidcAudience;
22
+ this.fetchFn = options.fetchFn ?? fetch;
23
+ this.getOidcJwt = options.getOidcJwt;
24
+ }
25
+ async exportFolder(envName, folder) {
26
+ const token = await this.getAccessToken();
27
+ const envSlug = normalizeEnvSlug(envName);
28
+ const secretPath = normalizeFolderPath(folder);
29
+ const url = new URL(`${this.domain}/api/v3/secrets/raw`);
30
+ url.searchParams.set("secretPath", secretPath);
31
+ url.searchParams.set("environment", envSlug);
32
+ url.searchParams.set("workspaceSlug", this.projectSlug);
33
+ url.searchParams.set("include_imports", "true");
34
+ url.searchParams.set("recursive", "false");
35
+ url.searchParams.set("expandSecretReferences", "true");
36
+ const resp = await this.fetchWithRetry(url.toString(), {
37
+ headers: { Authorization: `Bearer ${token}` },
38
+ });
39
+ const data = (await resp.json());
40
+ if (data.message) {
41
+ throw new Error(`Infisical error for path ${secretPath}: ${data.message}`);
42
+ }
43
+ const merged = {};
44
+ for (const imp of data.imports ?? []) {
45
+ for (const s of imp.secrets ?? []) {
46
+ if (s.secretKey)
47
+ merged[s.secretKey] = s.secretValue ?? "";
48
+ }
49
+ }
50
+ for (const s of data.secrets ?? []) {
51
+ if (s.secretKey)
52
+ merged[s.secretKey] = s.secretValue ?? "";
53
+ }
54
+ return merged;
55
+ }
56
+ /**
57
+ * Fetch only the named keys from a folder via the single-secret raw endpoint
58
+ * (`GET /api/v3/secrets/raw/{name}`), so the vault transmits nothing beyond
59
+ * the requested keys — wire-level least privilege. `include_imports=true`
60
+ * matches {@link exportFolder}, so a key surfaced into this folder via an
61
+ * Infisical import is still resolved (the single-name endpoint returns only
62
+ * that one secret, so following imports doesn't widen the read). A 404 means
63
+ * the key isn't reachable from this folder and is skipped; the caller merges
64
+ * across folders and enforces genuine absence. The access token is fetched
65
+ * once and reused across keys.
66
+ */
67
+ async exportKeys(envName, folder, keys) {
68
+ const token = await this.getAccessToken();
69
+ const envSlug = normalizeEnvSlug(envName);
70
+ const secretPath = normalizeFolderPath(folder);
71
+ const out = {};
72
+ for (const key of keys) {
73
+ const url = new URL(`${this.domain}/api/v3/secrets/raw/${encodeURIComponent(key)}`);
74
+ url.searchParams.set("secretPath", secretPath);
75
+ url.searchParams.set("environment", envSlug);
76
+ url.searchParams.set("workspaceSlug", this.projectSlug);
77
+ url.searchParams.set("include_imports", "true");
78
+ url.searchParams.set("expandSecretReferences", "true");
79
+ const resp = await this.fetchWithRetry(url.toString(), { headers: { Authorization: `Bearer ${token}` } }, 5, true // allow404: a missing key is a non-fatal miss, not an error
80
+ );
81
+ if (resp.status === 404)
82
+ continue;
83
+ const data = (await resp.json());
84
+ if (data.message) {
85
+ throw new Error(`Infisical error for key ${key}: ${data.message}`);
86
+ }
87
+ if (data.secret?.secretKey) {
88
+ out[data.secret.secretKey] = data.secret.secretValue ?? "";
89
+ }
90
+ }
91
+ return out;
92
+ }
93
+ async getAccessToken() {
94
+ if (this.token)
95
+ return this.token;
96
+ if (!this.identityId) {
97
+ throw new Error("INFISICAL_IDENTITY_ID required for OIDC auth");
98
+ }
99
+ const jwt = this.getOidcJwt
100
+ ? await this.getOidcJwt()
101
+ : await this.fetchOidcJwtFromEnv();
102
+ const body = new URLSearchParams({ identityId: this.identityId, jwt });
103
+ const resp = await this.fetchWithRetry(`${this.domain}/api/v1/auth/oidc-auth/login`, {
104
+ method: "POST",
105
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
106
+ body,
107
+ });
108
+ const data = (await resp.json());
109
+ this.token = data.accessToken ?? "";
110
+ if (!this.token) {
111
+ throw new Error("Infisical OIDC auth failed: empty access token");
112
+ }
113
+ return this.token;
114
+ }
115
+ async fetchOidcJwtFromEnv() {
116
+ const requestUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
117
+ const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
118
+ if (!requestUrl || !requestToken) {
119
+ throw new Error("OIDC auth requires ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN");
120
+ }
121
+ const url = this.oidcAudience
122
+ ? `${requestUrl}&audience=${encodeURIComponent(this.oidcAudience)}`
123
+ : requestUrl;
124
+ const resp = await this.fetchWithRetry(url, {
125
+ headers: { Authorization: `bearer ${requestToken}` },
126
+ });
127
+ const data = (await resp.json());
128
+ if (!data.value) {
129
+ throw new Error("OIDC JWT request returned empty value");
130
+ }
131
+ return data.value;
132
+ }
133
+ async fetchWithRetry(url, init, maxAttempts = 5,
134
+ // When set, a 404 short-circuits: it's returned as-is (not retried, not
135
+ // thrown) so a per-key read can treat "key not in this folder" as a normal,
136
+ // non-fatal miss rather than an error.
137
+ allow404 = false) {
138
+ let lastError;
139
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
140
+ try {
141
+ const controller = new AbortController();
142
+ const timeout = setTimeout(() => controller.abort(), 120_000);
143
+ const resp = await this.fetchFn(url, {
144
+ ...init,
145
+ signal: controller.signal,
146
+ });
147
+ clearTimeout(timeout);
148
+ if (allow404 && resp.status === 404)
149
+ return resp;
150
+ if (!resp.ok) {
151
+ const text = await resp.text();
152
+ throw new Error(`HTTP ${resp.status}: ${text}`);
153
+ }
154
+ return resp;
155
+ }
156
+ catch (err) {
157
+ lastError = err;
158
+ if (attempt < maxAttempts) {
159
+ await new Promise((r) => setTimeout(r, attempt * 5000));
160
+ }
161
+ }
162
+ }
163
+ throw lastError;
164
+ }
165
+ }
166
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/providers/remote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAwBrD;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACR,MAAM,CAAS;IACf,WAAW,CAAS;IACpB,UAAU,CAAS;IACnB,YAAY,CAAU;IACtB,OAAO,CAAe;IACtB,UAAU,CAAyB;IAC5C,KAAK,CAAU;IAEvB,YAAY,OAA8B;QACxC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,2BAA2B,CAAC;QAC5D,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;QACxC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,OAAe,EACf,MAAc;QAEd,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAE/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,qBAAqB,CAAC,CAAC;QACzD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAC/C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACxD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;QAChD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC3C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YACrD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;SAC9C,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAI9B,CAAC;QAEF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,4BAA4B,UAAU,KAAK,IAAI,CAAC,OAAO,EAAE,CAC1D,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YACrC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBAClC,IAAI,CAAC,CAAC,SAAS;oBAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;YAC7D,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YACnC,IAAI,CAAC,CAAC,SAAS;gBAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;QAC7D,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,UAAU,CACd,OAAe,EACf,MAAc,EACd,IAAc;QAEd,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,GAAG,GAA2B,EAAE,CAAC;QAEvC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,IAAI,GAAG,CACjB,GAAG,IAAI,CAAC,MAAM,uBAAuB,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAC/D,CAAC;YACF,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAC/C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACxD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;YAChD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YAEvD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CACpC,GAAG,CAAC,QAAQ,EAAE,EACd,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,EAAE,EACjD,CAAC,EACD,IAAI,CAAC,4DAA4D;aAClE,CAAC;YACF,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG;gBAAE,SAAS;YAElC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAG9B,CAAC;YACF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACrE,CAAC;YACD,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;gBAC3B,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC;QAElC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU;YACzB,CAAC,CAAC,MAAM,IAAI,CAAC,UAAU,EAAE;YACzB,CAAC,CAAC,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CACpC,GAAG,IAAI,CAAC,MAAM,8BAA8B,EAC5C;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI;SACL,CACF,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA6B,CAAC;QAC7D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;QAEpC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;QAC5D,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC;QAChE,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY;YAC3B,CAAC,CAAC,GAAG,UAAU,aAAa,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE;YACnE,CAAC,CAAC,UAAU,CAAC;QACf,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE;YAC1C,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,EAAE,EAAE;SACrD,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAuB,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,cAAc,CAC1B,GAAW,EACX,IAAkB,EAClB,WAAW,GAAG,CAAC;IACf,wEAAwE;IACxE,4EAA4E;IAC5E,uCAAuC;IACvC,QAAQ,GAAG,KAAK;QAEhB,IAAI,SAAkB,CAAC;QACvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;YACxD,IAAI,CAAC;gBACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC9D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;oBACnC,GAAG,IAAI;oBACP,MAAM,EAAE,UAAU,CAAC,MAAM;iBAC1B,CAAC,CAAC;gBACH,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,IAAI,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG;oBAAE,OAAO,IAAI,CAAC;gBACjD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;oBACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;gBAClD,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,SAAS,GAAG,GAAG,CAAC;gBAChB,IAAI,OAAO,GAAG,WAAW,EAAE,CAAC;oBAC1B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;gBAC1D,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,SAAS,CAAC;IAClB,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ export interface SecretsProvider {
2
+ /**
3
+ * Read every secret in a folder (whole-folder read — `fetch: "folder"`).
4
+ */
5
+ exportFolder(envName: string, folder: string): Promise<Record<string, string>>;
6
+ /**
7
+ * Read only the named keys from a folder (`fetch: "keys"` — wire-level least
8
+ * privilege). Keys absent from this folder are omitted from the result, not
9
+ * an error: a key may live in a different folder, or not exist at all (the
10
+ * caller's `include` enforcement decides whether absence is fatal).
11
+ */
12
+ exportKeys(envName: string, folder: string, keys: string[]): Promise<Record<string, string>>;
13
+ }
14
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,YAAY,CACV,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEnC;;;;;OAKG;IACH,UAAU,CACR,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
package/dist/pull.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { SecretsProvider } from "./providers/types.js";
2
+ import type { PackageManifest } from "./registry.js";
3
+ export type PullResult = "pulled" | "skipped";
4
+ export type PullManifestOptions = {
5
+ manifest: PackageManifest;
6
+ repoRoot: string;
7
+ envName: string;
8
+ profile?: string;
9
+ force?: boolean;
10
+ turboMode?: boolean;
11
+ provider: SecretsProvider;
12
+ };
13
+ export declare function writeInjectedSecretsStub(outputPath: string, manifest: PackageManifest, keys: string[]): void;
14
+ export declare function pullManifest(options: PullManifestOptions): Promise<PullResult>;
15
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../src/pull.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE9C,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;CAC3B,CAAC;AAEF,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,MAAM,EAAE,GACb,IAAI,CAgBN;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC,CAkErB"}