mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-16 07:40:04 +02:00
Support _FILE env vars
Closes https://github.com/fosrl/docs-v2/issues/141
This commit is contained in:
@@ -1,3 +1,37 @@
|
||||
export const getEnvOrYaml = (envVar: string) => (valFromYaml: any) => {
|
||||
return process.env[envVar] ?? valFromYaml;
|
||||
import fs from "fs";
|
||||
|
||||
// Resolves an environment variable, also honoring a `<envVar>_FILE` variant
|
||||
// that points to a file whose (trimmed) contents should be used as the
|
||||
// value. This is the common convention for consuming Docker/Swarm secrets
|
||||
// (e.g. mounted at /run/secrets/...) without putting the raw value in the
|
||||
// container's environment.
|
||||
export const readEnvOrFile = (envVar: string): string | undefined => {
|
||||
const fileEnvVar = `${envVar}_FILE`;
|
||||
const filePath = process.env[fileEnvVar];
|
||||
|
||||
if (filePath) {
|
||||
if (process.env[envVar]) {
|
||||
throw new Error(
|
||||
`Both ${envVar} and ${fileEnvVar} are set. Please set only one.`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return fs.readFileSync(filePath, "utf8").trim();
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to read ${fileEnvVar} (${filePath}): ${
|
||||
error instanceof Error ? error.message : error
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return process.env[envVar];
|
||||
};
|
||||
|
||||
export const getEnvOrYaml =
|
||||
(envVar: string) =>
|
||||
(valFromYaml: string | undefined): string | undefined => {
|
||||
return readEnvOrFile(envVar) ?? valFromYaml;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as yaml from "js-yaml";
|
||||
import { configFilePath1, configFilePath2 } from "./consts";
|
||||
import { z } from "zod";
|
||||
import stoi from "./stoi";
|
||||
import { getEnvOrYaml } from "./getEnvOrYaml";
|
||||
import { getEnvOrYaml, readEnvOrFile } from "./getEnvOrYaml";
|
||||
|
||||
const portSchema = z.number().positive().gt(0).lte(65535);
|
||||
|
||||
@@ -160,14 +160,17 @@ export const configSchema = z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(false)
|
||||
.transform((val) =>
|
||||
process.env.ENABLE_AI_GATEWAY_CLIENT_IP_HEADER !==
|
||||
undefined
|
||||
? process.env.ENABLE_AI_GATEWAY_CLIENT_IP_HEADER ===
|
||||
"true"
|
||||
: val
|
||||
),
|
||||
secret: z.string().pipe(z.string().min(8)).optional(),
|
||||
.transform((val) => {
|
||||
const envVal = readEnvOrFile(
|
||||
"ENABLE_AI_GATEWAY_CLIENT_IP_HEADER"
|
||||
);
|
||||
return envVal !== undefined ? envVal === "true" : val;
|
||||
}),
|
||||
secret: z
|
||||
.string()
|
||||
.pipe(z.string().min(8))
|
||||
.optional()
|
||||
.transform(getEnvOrYaml("SERVER_SECRET")),
|
||||
maxmind_db_path: z.string().optional(),
|
||||
maxmind_asn_path: z.string().optional()
|
||||
})
|
||||
@@ -198,7 +201,8 @@ export const configSchema = z
|
||||
dashboard_session_length_hours: 720,
|
||||
resource_session_length_hours: 720,
|
||||
trust_proxy: 1,
|
||||
enable_ai_gateway_client_ip_header: false
|
||||
enable_ai_gateway_client_ip_header: false,
|
||||
secret: undefined
|
||||
}),
|
||||
postgres: z
|
||||
.object({
|
||||
@@ -499,10 +503,7 @@ export const configSchema = z
|
||||
)
|
||||
.refine(
|
||||
(data) => {
|
||||
// If hybrid is not defined, server secret must be defined. If its not defined already then pull it from env
|
||||
if (data.server?.secret === undefined) {
|
||||
data.server.secret = process.env.SERVER_SECRET;
|
||||
}
|
||||
// If hybrid is not defined, server secret must be defined
|
||||
return (
|
||||
data.server?.secret !== undefined &&
|
||||
data.server.secret.length > 0
|
||||
|
||||
Reference in New Issue
Block a user