@purpleschool/infisical-env 0.1.0 → 0.1.2
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/package.json +5 -2
- package/src/cli.js +267 -267
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purpleschool/infisical-env",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
|
-
"
|
|
6
|
+
"infisical-env": "src/cli.js"
|
|
7
7
|
},
|
|
8
|
+
"files": [
|
|
9
|
+
"src/cli.js"
|
|
10
|
+
],
|
|
8
11
|
"scripts": {
|
|
9
12
|
"start": "node ./src/cli.js"
|
|
10
13
|
},
|
package/src/cli.js
CHANGED
|
@@ -16,348 +16,348 @@ const DEFAULT_INFISICAL_BASE_URL = "https://secret.purplecode.ru";
|
|
|
16
16
|
const DEFAULT_INFISICAL_CLIENT_ID = "f3e0d60c-a602-4296-bd03-3be228e89165";
|
|
17
17
|
|
|
18
18
|
async function main() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const repoRoot = findRepoRoot(process.cwd());
|
|
27
|
-
const packageJson = readJson(path.join(repoRoot, "package.json"));
|
|
28
|
-
|
|
29
|
-
const projectId = resolveInfisicalProject(packageJson);
|
|
30
|
-
const envName = await resolveEnvName(args);
|
|
19
|
+
try {
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
22
|
+
printHelp();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
const repoRoot = findRepoRoot(process.cwd());
|
|
27
|
+
const packageJson = readJson(path.join(repoRoot, "package.json"));
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
29
|
+
const projectId = resolveInfisicalProject(packageJson);
|
|
30
|
+
const envName = await resolveEnvName(args);
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
envName,
|
|
42
|
-
envRefs,
|
|
43
|
-
repoRoot,
|
|
44
|
-
});
|
|
32
|
+
const deploymentPath = resolveDeploymentPath(repoRoot);
|
|
33
|
+
const envRefs = collectEnvRefs(deploymentPath);
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
if (envRefs.length === 0) {
|
|
36
|
+
throw new Error(`No env refs found in ${deploymentPath}`);
|
|
37
|
+
}
|
|
49
38
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
39
|
+
const values = await resolveEnvValues({
|
|
40
|
+
projectId,
|
|
41
|
+
envName,
|
|
42
|
+
envRefs,
|
|
43
|
+
repoRoot,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const envFilePath = path.join(repoRoot, ".env");
|
|
47
|
+
const lines = values.map((item) => `${item.name}=${item.value}`);
|
|
48
|
+
fs.writeFileSync(envFilePath, lines.join(os.EOL), "utf8");
|
|
49
|
+
|
|
50
|
+
console.log(pc.green(`.env written to ${envFilePath}`));
|
|
51
|
+
} catch (err) {
|
|
52
|
+
console.error(pc.red(formatError(err)));
|
|
53
|
+
console.error(pc.yellow("Run with --help for usage."));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function printHelp() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
59
|
+
console.log(
|
|
60
|
+
[
|
|
61
|
+
pc.bold("Usage:"),
|
|
62
|
+
" infisical-env [--env stage|stage-2]",
|
|
63
|
+
"",
|
|
64
|
+
pc.bold("Options:"),
|
|
65
|
+
" --env <name> Environment name (stage or stage-2)",
|
|
66
|
+
" -h, --help Show this help",
|
|
67
|
+
"",
|
|
68
|
+
pc.bold("Environment variables:"),
|
|
69
|
+
" INFISICAL_CLIENT_SECRET Required (machine identity secret)",
|
|
70
|
+
" INFISICAL_CLIENT_ID Optional override",
|
|
71
|
+
" INFISICAL_BASE_URL Optional override (default https://secret.purplecode.ru)",
|
|
72
|
+
" INFISICAL_MOCK_PATH Optional mock json path for offline testing",
|
|
73
|
+
].join(os.EOL)
|
|
74
|
+
);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function findRepoRoot(startDir) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
let current = startDir;
|
|
79
|
+
while (true) {
|
|
80
|
+
const candidate = path.join(current, "package.json");
|
|
81
|
+
if (fs.existsSync(candidate)) {
|
|
82
|
+
return current;
|
|
83
|
+
}
|
|
84
|
+
const parent = path.dirname(current);
|
|
85
|
+
if (parent === current) {
|
|
86
|
+
throw new Error("package.json not found in any parent directory");
|
|
87
|
+
}
|
|
88
|
+
current = parent;
|
|
87
89
|
}
|
|
88
|
-
current = parent;
|
|
89
|
-
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
function readJson(filePath) {
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
94
|
+
return JSON.parse(raw);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
function resolveInfisicalProject(packageJson) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
const name = typeof packageJson.name === "string" ? packageJson.name.toLowerCase() : "";
|
|
99
|
+
if (name.includes("rugpt")) {
|
|
100
|
+
return "48854e39-7129-4786-87ac-cfcce296991c";
|
|
101
|
+
}
|
|
102
|
+
if (name.includes("studdy") || name.includes('student-works')) {
|
|
103
|
+
return "b4b0abbd-f8e6-428a-a296-6289369ca8dd";
|
|
104
|
+
}
|
|
105
|
+
if (name.includes("multisite")) {
|
|
106
|
+
return "6531c08b-45e0-4d75-a8ab-08d14d0387bf";
|
|
107
|
+
}
|
|
108
|
+
throw new Error(
|
|
109
|
+
"Unable to resolve Infisical project from package.json name. Expected name to include rugpt, studdy, or multisite."
|
|
110
|
+
);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
async function resolveEnvName(args) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
const flagValue = parseEnvFlag(args);
|
|
115
|
+
if (flagValue) {
|
|
116
|
+
return validateEnv(flagValue);
|
|
117
|
+
}
|
|
118
|
+
return promptEnv();
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
function parseEnvFlag(args) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
123
|
+
const arg = args[i];
|
|
124
|
+
if (arg === "--env") {
|
|
125
|
+
return args[i + 1] || "";
|
|
126
|
+
}
|
|
127
|
+
if (arg.startsWith("--env=")) {
|
|
128
|
+
return arg.slice("--env=".length);
|
|
129
|
+
}
|
|
129
130
|
}
|
|
130
|
-
|
|
131
|
-
return "";
|
|
131
|
+
return "";
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
function validateEnv(value) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
if (!ALLOWED_ENVS.includes(value)) {
|
|
136
|
+
throw new Error(`Invalid environment \"${value}\". Allowed: ${ALLOWED_ENVS.join(", ")}`);
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
async function promptEnv() {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
console.log(pc.bold("Select environment:"));
|
|
149
|
-
ALLOWED_ENVS.forEach((name, idx) => {
|
|
150
|
-
console.log(`${idx + 1}. ${name}`);
|
|
142
|
+
const rl = readline.createInterface({
|
|
143
|
+
input: process.stdin,
|
|
144
|
+
output: process.stdout,
|
|
151
145
|
});
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
console.log(pc.bold("Select environment:"));
|
|
149
|
+
ALLOWED_ENVS.forEach((name, idx) => {
|
|
150
|
+
console.log(`${idx + 1}. ${name}`);
|
|
151
|
+
});
|
|
152
|
+
const answer = await rl.question("Enter number: ");
|
|
153
|
+
const index = Number(answer.trim()) - 1;
|
|
154
|
+
if (!Number.isInteger(index) || index < 0 || index >= ALLOWED_ENVS.length) {
|
|
155
|
+
throw new Error("Invalid environment selection");
|
|
156
|
+
}
|
|
157
|
+
return ALLOWED_ENVS[index];
|
|
158
|
+
} finally {
|
|
159
|
+
rl.close();
|
|
156
160
|
}
|
|
157
|
-
return ALLOWED_ENVS[index];
|
|
158
|
-
} finally {
|
|
159
|
-
rl.close();
|
|
160
|
-
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function resolveDeploymentPath(repoRoot) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
164
|
+
const candidates = [
|
|
165
|
+
path.join(repoRoot, ".kube", "deployment.yml"),
|
|
166
|
+
path.join(repoRoot, ".kube", "deployment.yaml"),
|
|
167
|
+
path.join(repoRoot, "deployment.yml"),
|
|
168
|
+
path.join(repoRoot, "deployment.yaml"),
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
for (const candidate of candidates) {
|
|
172
|
+
if (fs.existsSync(candidate)) {
|
|
173
|
+
return candidate;
|
|
174
|
+
}
|
|
174
175
|
}
|
|
175
|
-
}
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
throw new Error("Deployment file not found. Expected .kube/deployment.yml or .kube/deployment.yaml");
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
function collectEnvRefs(deploymentPath) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
181
|
+
const raw = fs.readFileSync(deploymentPath, "utf8");
|
|
182
|
+
const docs = YAML.parseAllDocuments(raw);
|
|
183
|
+
const refs = [];
|
|
184
|
+
|
|
185
|
+
for (const doc of docs) {
|
|
186
|
+
const data = doc.toJSON();
|
|
187
|
+
const containers = data?.spec?.template?.spec?.containers || [];
|
|
188
|
+
for (const container of containers) {
|
|
189
|
+
const envList = container?.env || [];
|
|
190
|
+
for (const envItem of envList) {
|
|
191
|
+
const name = envItem?.name;
|
|
192
|
+
const secretKeyRef = envItem?.valueFrom?.secretKeyRef;
|
|
193
|
+
const folder = secretKeyRef?.name;
|
|
194
|
+
const key = secretKeyRef?.key;
|
|
195
|
+
if (name && folder && key) {
|
|
196
|
+
refs.push({ name, folder, key });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
197
199
|
}
|
|
198
|
-
}
|
|
199
200
|
}
|
|
200
|
-
}
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
return refs;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
async function resolveEnvValues({ projectId, envName, envRefs, repoRoot }) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
const clientId = process.env.INFISICAL_CLIENT_ID || DEFAULT_INFISICAL_CLIENT_ID;
|
|
212
|
-
const clientSecret = process.env.INFISICAL_CLIENT_SECRET;
|
|
213
|
-
if (!clientId || !clientSecret) {
|
|
214
|
-
throw new Error(
|
|
215
|
-
"Missing Infisical credentials. Set INFISICAL_CLIENT_SECRET or use INFISICAL_MOCK_PATH."
|
|
216
|
-
);
|
|
217
|
-
}
|
|
206
|
+
const mockPath = process.env.INFISICAL_MOCK_PATH;
|
|
207
|
+
if (mockPath) {
|
|
208
|
+
return resolveFromMock({ projectId, envName, envRefs, mockPath, repoRoot });
|
|
209
|
+
}
|
|
218
210
|
|
|
219
|
-
|
|
220
|
-
|
|
211
|
+
const clientId = process.env.INFISICAL_CLIENT_ID || DEFAULT_INFISICAL_CLIENT_ID;
|
|
212
|
+
const clientSecret = process.env.INFISICAL_CLIENT_SECRET;
|
|
213
|
+
if (!clientId || !clientSecret) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
"Missing Infisical credentials. Set INFISICAL_CLIENT_SECRET or use INFISICAL_MOCK_PATH."
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const baseUrl = normalizeBaseUrl(process.env.INFISICAL_BASE_URL || DEFAULT_INFISICAL_BASE_URL);
|
|
220
|
+
const accessToken = await loginUniversalAuth({ baseUrl, clientId, clientSecret });
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
return fetchSecretsFromInfisical({ baseUrl, accessToken, projectId, envName, envRefs });
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
function resolveFromMock({ projectId, envName, envRefs, mockPath, repoRoot }) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return envRefs.map((ref) => {
|
|
241
|
-
const folderData = envData?.[ref.folder];
|
|
242
|
-
const value = folderData?.[ref.key];
|
|
243
|
-
if (value === undefined || value === null) {
|
|
244
|
-
throw new Error(`Missing value for ${ref.folder}.${ref.key}`);
|
|
226
|
+
const absPath = path.isAbsolute(mockPath) ? mockPath : path.join(repoRoot, mockPath);
|
|
227
|
+
if (!fs.existsSync(absPath)) {
|
|
228
|
+
throw new Error(`Mock file not found: ${absPath}`);
|
|
229
|
+
}
|
|
230
|
+
const data = readJson(absPath);
|
|
231
|
+
const projectData = data?.projects?.[projectId];
|
|
232
|
+
if (!projectData) {
|
|
233
|
+
throw new Error(`Project not found in mock: ${projectId}`);
|
|
234
|
+
}
|
|
235
|
+
const envData = projectData?.[envName];
|
|
236
|
+
if (!envData) {
|
|
237
|
+
throw new Error(`Environment not found in mock: ${envName}`);
|
|
245
238
|
}
|
|
246
|
-
|
|
247
|
-
|
|
239
|
+
|
|
240
|
+
return envRefs.map((ref) => {
|
|
241
|
+
const folderData = envData?.[ref.folder];
|
|
242
|
+
const value = folderData?.[ref.key];
|
|
243
|
+
if (value === undefined || value === null) {
|
|
244
|
+
throw new Error(`Missing value for ${ref.folder}.${ref.key}`);
|
|
245
|
+
}
|
|
246
|
+
return { name: ref.name, value: String(value) };
|
|
247
|
+
});
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
function formatError(err) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
251
|
+
if (err instanceof Error) {
|
|
252
|
+
return err.message;
|
|
253
|
+
}
|
|
254
|
+
return String(err);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
function normalizeBaseUrl(value) {
|
|
258
|
-
|
|
258
|
+
return value.replace(/\/+$/, "");
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
async function loginUniversalAuth({ baseUrl, clientId, clientSecret }) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
262
|
+
const url = `${baseUrl}/api/v1/auth/universal-auth/login`;
|
|
263
|
+
const body = new URLSearchParams();
|
|
264
|
+
body.set("clientId", clientId);
|
|
265
|
+
body.set("clientSecret", clientSecret);
|
|
266
|
+
|
|
267
|
+
const res = await fetch(url, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: {
|
|
270
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
271
|
+
},
|
|
272
|
+
body,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
if (!res.ok) {
|
|
276
|
+
const text = await safeReadText(res);
|
|
277
|
+
throw new Error(`Infisical login failed (${res.status}). ${text}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const data = await res.json();
|
|
281
|
+
if (!data?.accessToken) {
|
|
282
|
+
throw new Error("Infisical login response missing accessToken.");
|
|
283
|
+
}
|
|
284
|
+
return data.accessToken;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
async function fetchSecretsFromInfisical({ baseUrl, accessToken, projectId, envName, envRefs }) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const secretCache = new Map();
|
|
297
|
-
for (const [folder, refs] of refsByFolder.entries()) {
|
|
298
|
-
const secretPath = folder.startsWith("/") ? folder : `/${folder}`;
|
|
299
|
-
const secrets = await listSecrets({
|
|
300
|
-
baseUrl,
|
|
301
|
-
accessToken,
|
|
302
|
-
projectId,
|
|
303
|
-
envName,
|
|
304
|
-
secretPath,
|
|
305
|
-
});
|
|
306
|
-
const map = new Map();
|
|
307
|
-
for (const item of secrets) {
|
|
308
|
-
if (item?.secretKey != null) {
|
|
309
|
-
map.set(item.secretKey, item.secretValue);
|
|
310
|
-
}
|
|
288
|
+
const refsByFolder = new Map();
|
|
289
|
+
for (const ref of envRefs) {
|
|
290
|
+
if (!refsByFolder.has(ref.folder)) {
|
|
291
|
+
refsByFolder.set(ref.folder, []);
|
|
292
|
+
}
|
|
293
|
+
refsByFolder.get(ref.folder).push(ref);
|
|
311
294
|
}
|
|
312
|
-
secretCache.set(folder, map);
|
|
313
295
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
296
|
+
const secretCache = new Map();
|
|
297
|
+
for (const [folder, refs] of refsByFolder.entries()) {
|
|
298
|
+
const secretPath = folder.startsWith("/") ? folder : `/${folder}`;
|
|
299
|
+
const secrets = await listSecrets({
|
|
300
|
+
baseUrl,
|
|
301
|
+
accessToken,
|
|
302
|
+
projectId,
|
|
303
|
+
envName,
|
|
304
|
+
secretPath,
|
|
305
|
+
});
|
|
306
|
+
const map = new Map();
|
|
307
|
+
for (const item of secrets) {
|
|
308
|
+
if (item?.secretKey != null) {
|
|
309
|
+
map.set(item.secretKey, item.secretValue);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
secretCache.set(folder, map);
|
|
313
|
+
|
|
314
|
+
for (const ref of refs) {
|
|
315
|
+
if (!map.has(ref.key)) {
|
|
316
|
+
throw new Error(`Missing value for ${folder}.${ref.key} in environment ${envName}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
318
319
|
}
|
|
319
|
-
}
|
|
320
320
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
321
|
+
return envRefs.map((ref) => {
|
|
322
|
+
const folderMap = secretCache.get(ref.folder);
|
|
323
|
+
const value = folderMap?.get(ref.key);
|
|
324
|
+
return { name: ref.name, value: String(value) };
|
|
325
|
+
});
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
async function listSecrets({ baseUrl, accessToken, projectId, envName, secretPath }) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
329
|
+
const params = new URLSearchParams({
|
|
330
|
+
projectId,
|
|
331
|
+
environment: envName,
|
|
332
|
+
secretPath,
|
|
333
|
+
viewSecretValue: "true",
|
|
334
|
+
expandSecretReferences: "true",
|
|
335
|
+
recursive: "false",
|
|
336
|
+
includeImports: "true",
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const url = `${baseUrl}/api/v4/secrets?${params.toString()}`;
|
|
340
|
+
const res = await fetch(url, {
|
|
341
|
+
headers: {
|
|
342
|
+
Authorization: `Bearer ${accessToken}`,
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
if (!res.ok) {
|
|
347
|
+
const text = await safeReadText(res);
|
|
348
|
+
throw new Error(`Infisical secrets list failed (${res.status}) for ${secretPath}. ${text}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const data = await res.json();
|
|
352
|
+
return Array.isArray(data?.secrets) ? data.secrets : [];
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
async function safeReadText(res) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
356
|
+
try {
|
|
357
|
+
return await res.text();
|
|
358
|
+
} catch {
|
|
359
|
+
return "";
|
|
360
|
+
}
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
await main();
|