feat: manage frontend auth from YAML source
Pipelines as Code CI / hwlab-web-probe-sentinel-nc01- Success

This commit is contained in:
Codex
2026-07-09 15:20:54 +02:00
parent 61d05dccf9
commit 44b716538e
5 changed files with 591 additions and 4 deletions
@@ -13,6 +13,11 @@ function record(value, path) {
return value;
}
function positiveInteger(value, path) {
if (!Number.isInteger(value) || value < 1) throw new Error(`${path} must be a positive integer`);
return value;
}
function readEnvFile(path) {
const values = {};
const text = readFileSync(path, "utf8");
@@ -26,6 +31,15 @@ function readEnvFile(path) {
return values;
}
function readLinePairCredential(path, usernameLine, passwordLine) {
const lines = readFileSync(path, "utf8").split(/\r?\n/u);
const username = (lines[usernameLine - 1] || "").trim();
const password = (lines[passwordLine - 1] || "").trim();
if (!username) throw new Error(`missing username line ${usernameLine} in ${path}`);
if (!password) throw new Error(`missing password line ${passwordLine} in ${path}`);
return { username, password };
}
function sha(value) {
return createHash("sha256").update(value).digest("hex").slice(0, 16);
}
@@ -92,13 +106,23 @@ const services = record(config.services, "services");
const backend = record(services.backendCore, "services.backendCore");
const frontend = record(services.frontend, "services.frontend");
const runtimeConfig = record(config.runtimeConfig, "runtimeConfig");
const runtimeAuth = record(config.runtimeAuth, "runtimeAuth");
const runtimeAuthSourceRef = record(runtimeAuth.sourceRef, "runtimeAuth.sourceRef");
const runtimeSecrets = record(config.runtimeSecrets, "runtimeSecrets");
const secretTarget = record(runtimeSecrets.target, "runtimeSecrets.target");
const secretKeys = record(secretTarget.keys, "runtimeSecrets.target.keys");
const namespace = required(target.namespace, "target.namespace");
const secretName = required(secretTarget.name, "runtimeSecrets.target.name");
const authSourcePath = resolve(required(runtimeAuthSourceRef.path, "runtimeAuth.sourceRef.path"));
if (required(runtimeAuthSourceRef.format, "runtimeAuth.sourceRef.format") !== "linePair") throw new Error("runtimeAuth.sourceRef.format must be linePair");
const authCredential = readLinePairCredential(
authSourcePath,
positiveInteger(runtimeAuthSourceRef.usernameLine, "runtimeAuth.sourceRef.usernameLine"),
positiveInteger(runtimeAuthSourceRef.passwordLine, "runtimeAuth.sourceRef.passwordLine"),
);
const sourcePath = resolve(required(record(runtimeSecrets.sourceRef, "runtimeSecrets.sourceRef").path, "runtimeSecrets.sourceRef.path"));
const secrets = readEnvFile(sourcePath);
secrets[secretKeys.authPassword] = authCredential.password;
const requiredSecretKeys = Object.values(secretKeys);
for (const key of requiredSecretKeys) {
if (typeof secrets[key] !== "string" || secrets[key].length === 0) throw new Error(`missing ${key} in ${sourcePath}`);
@@ -160,7 +184,7 @@ data:
TASK_PENDING_TIMEOUT_MS: ${yamlScalar(required(runtimeConfig.taskPendingTimeoutMs, "runtimeConfig.taskPendingTimeoutMs"))}
DATABASE_POOL_MAX: ${yamlScalar(required(runtimeConfig.databasePoolMax, "runtimeConfig.databasePoolMax"))}
SESSION_TTL_SECONDS: ${yamlScalar(required(runtimeConfig.sessionTtlSeconds, "runtimeConfig.sessionTtlSeconds"))}
AUTH_USERNAME: ${yamlScalar(required(runtimeConfig.authUsername, "runtimeConfig.authUsername"))}
AUTH_USERNAME: ${yamlScalar(authCredential.username)}
UNIDESK_SSH_CLIENT_ROUTE_ALLOWLIST: ${yamlScalar(required(runtimeConfig.sshClientRouteAllowlist, "runtimeConfig.sshClientRouteAllowlist"))}
MICROSERVICES_JSON: ${yamlScalar(required(runtimeConfig.microservicesJson, "runtimeConfig.microservicesJson"))}
NO_PROXY: ${yamlScalar(required(runtime.noProxy, "runtime.noProxy"))}