fix: reject ambiguous database env values
This commit is contained in:
@@ -43,7 +43,7 @@ fi
|
||||
|
||||
definition_count() {
|
||||
local key="$1"
|
||||
grep -Ec "^[[:space:]]*(export[[:space:]]+)?${key}[[:space:]]*=" "$ENV_FILE" || true
|
||||
grep -Ec "^[[:space:]]*(export[[:space:]]+)?${key}([[:space:]]*=|[[:space:]]*$)" "$ENV_FILE" || true
|
||||
}
|
||||
|
||||
environment_value() {
|
||||
@@ -51,13 +51,20 @@ environment_value() {
|
||||
sed -n -E "s/^[[:space:]]*(export[[:space:]]+)?${key}[[:space:]]*=[[:space:]]*(.*)$/\\2/p" "$ENV_FILE"
|
||||
}
|
||||
|
||||
is_safe_literal() {
|
||||
local value="$1"
|
||||
# Required values are generated as single-line hex-safe literals. This also
|
||||
# permits percent-encoded schema URLs without evaluating dotenv syntax.
|
||||
[[ "$value" =~ ^[A-Za-z0-9._~%:@/+,-]+$ ]]
|
||||
}
|
||||
|
||||
require_once_non_empty() {
|
||||
local key="$1"
|
||||
local count
|
||||
local value
|
||||
count="$(definition_count "$key")"
|
||||
value="$(environment_value "$key")"
|
||||
if [ "$count" -ne 1 ] || [ -z "$value" ]; then
|
||||
if [ "$count" -ne 1 ] || ! is_safe_literal "$value"; then
|
||||
echo "required staging database environment variable is missing or duplicated: $key" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -25,7 +25,7 @@ const validEnvironment = [
|
||||
"MIGRATION_RUNNER_PASSWORD=migration-runner-test-password",
|
||||
"BACKUP_READER_PASSWORD=backup-reader-test-password",
|
||||
"STAGING_BACKUP_ENCRYPTION_KEY=staging-backup-test-password",
|
||||
"SCHEMA_DATABASE_URL=postgresql://schema_owner:schema-owner-test-password@postgres:5432/jyotisha",
|
||||
"SCHEMA_DATABASE_URL=postgresql://schema_owner:schema-owner%2Dtest-password@postgres:5432/jyotisha",
|
||||
];
|
||||
|
||||
test("database env validator rejects Compose-compatible duplicate selectors without printing values", () => {
|
||||
@@ -83,6 +83,60 @@ test("database env validator rejects Compose-compatible duplicate selectors with
|
||||
}
|
||||
});
|
||||
|
||||
test("database env validator rejects bare Compose-compatible duplicate definitions", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "jyotisha-database-env-"));
|
||||
const envFile = join(root, ".env.staging.database");
|
||||
|
||||
try {
|
||||
writeFileSync(
|
||||
envFile,
|
||||
`${[...validEnvironment, " POSTGRES_DB"].join("\n")}\n`,
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
chmodSync(envFile, 0o600);
|
||||
|
||||
const result = spawnSync("bash", [validator, envFile], { encoding: "utf8" });
|
||||
assert.notEqual(result.status, 0);
|
||||
assert.doesNotMatch(
|
||||
`${result.stdout}${result.stderr}`,
|
||||
/postgres-test-password|schema-owner-test-password|staging-backup-test-password/,
|
||||
);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("database env validator rejects quoted and interpolated required secrets", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "jyotisha-database-env-"));
|
||||
const envFile = join(root, ".env.staging.database");
|
||||
|
||||
try {
|
||||
for (const password of ['""', "''", "${UNSET}"]) {
|
||||
writeFileSync(
|
||||
envFile,
|
||||
`${validEnvironment
|
||||
.map((line) =>
|
||||
line.startsWith("POSTGRES_PASSWORD=")
|
||||
? `POSTGRES_PASSWORD=${password}`
|
||||
: line,
|
||||
)
|
||||
.join("\n")}\n`,
|
||||
{ mode: 0o600 },
|
||||
);
|
||||
chmodSync(envFile, 0o600);
|
||||
|
||||
const result = spawnSync("bash", [validator, envFile], { encoding: "utf8" });
|
||||
assert.notEqual(result.status, 0, password);
|
||||
assert.doesNotMatch(
|
||||
`${result.stdout}${result.stderr}`,
|
||||
/postgres-test-password|schema-owner-test-password|staging-backup-test-password/,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("database env validator rejects symlinks and unsafe modes", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "jyotisha-database-env-"));
|
||||
const envFile = join(root, ".env.staging.database");
|
||||
|
||||
Reference in New Issue
Block a user