fix: accept literal database secret punctuation

This commit is contained in:
Jesse_Chen
2026-07-20 21:52:48 +08:00
parent ac9277a7a8
commit 1afbc23e19
2 changed files with 57 additions and 4 deletions
+28 -4
View File
@@ -53,9 +53,33 @@ environment_value() {
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._~%:@/+,-]+$ ]]
local inner
# Required values are literal single-line values: use an unquoted token or
# matching non-empty quotes. Dotenv interpolation, comments, and malformed
# quoting are rejected rather than evaluated, so generate secrets without $.
if [ -z "$value" ] || [[ "$value" == *'$'* ]]; then
return 1
fi
case "$value" in
\"*\")
inner="${value:1}"
inner="${inner%?}"
[ -n "$inner" ] && [[ "$inner" != *'"'* ]]
;;
\'*\')
inner="${value:1}"
inner="${inner%?}"
[ -n "$inner" ] && [[ "$inner" != *"'"* ]]
;;
*\"*|*\'*)
return 1
;;
*[[:space:]]*|*\#*)
return 1
;;
esac
}
require_once_non_empty() {
@@ -65,7 +89,7 @@ require_once_non_empty() {
count="$(definition_count "$key")"
value="$(environment_value "$key")"
if [ "$count" -ne 1 ] || ! is_safe_literal "$value"; then
echo "required staging database environment variable is missing or duplicated: $key" >&2
echo "required staging database literal is missing, duplicated, or ambiguous: $key" >&2
exit 1
fi
}
@@ -137,6 +137,35 @@ test("database env validator rejects quoted and interpolated required secrets",
}
});
test("database env validator accepts punctuated literal required secrets", () => {
const root = mkdtempSync(join(tmpdir(), "jyotisha-database-env-"));
const envFile = join(root, ".env.staging.database");
try {
for (const password of ["c2VjcmV0IT0=", '"secret!=value"']) {
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.equal(result.status, 0, result.stderr);
assert.equal(result.stdout, "staging database environment validated\n");
assert.doesNotMatch(`${result.stdout}${result.stderr}`, /secret!=value|c2VjcmV0IT0=/);
}
} 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");