fix: reject compose env selector aliases

This commit is contained in:
Jesse_Chen
2026-07-20 16:37:42 +08:00
parent 965b0d5888
commit 26373d257b
3 changed files with 44 additions and 2 deletions
+3 -1
View File
@@ -23,8 +23,10 @@ require_selector() {
local key="$1"
local expected="$2"
local count
local definition_pattern
count="$(grep -c "^${key}=" "$ENV_FILE" || true)"
definition_pattern="^[[:space:]]*(export[[:space:]]+)?${key}([[:space:]]*=|[[:space:]]*$)"
count="$(grep -Ec "$definition_pattern" "$ENV_FILE" || true)"
if [ "$count" -ne 1 ] || ! grep -Fqx "${key}=${expected}" "$ENV_FILE"; then
echo "invalid staging selector: $key" >&2
exit 1
@@ -18,7 +18,7 @@
| 部署密钥 | production 专用 | staging 专用 |
| 应用配置 | `.env.production` | `.env.staging` |
| Supabase | 生产项目 | 独立 staging 项目 |
| 部署触发 | `main` CI 成功 | `staging` CI 成功或手动触发 |
| 部署触发 | 手动 production workflow | `staging` CI 成功或手动触发 |
staging 不得写入生产数据库,不得复用 service-role key、数据库密码、SSH 私钥或模型计费密钥。模型接口优先使用独立测试 key、低额度或 provider sandbox。
+40
View File
@@ -182,6 +182,7 @@ test("staging env validator rejects selector drift, duplicates, and unsafe permi
);
const root = mkdtempSync(join(tmpdir(), "jyotisha-staging-env-"));
const envFile = join(root, ".env.staging");
const composeFile = join(root, "compose.yml");
const validSelectors = [
"APP_ENV_FILE=../.env.staging",
"CADDYFILE_PATH=./Caddyfile.staging",
@@ -195,6 +196,17 @@ test("staging env validator rejects selector drift, duplicates, and unsafe permi
};
try {
writeFileSync(
composeFile,
[
"services:",
" probe:",
" image: alpine",
" environment:",
" SELECTED: ${APP_ENV_FILE}",
"",
].join("\n"),
);
writeEnv(validSelectors);
assert.equal(run().status, 0);
@@ -204,6 +216,34 @@ test("staging env validator rejects selector drift, duplicates, and unsafe permi
writeEnv([...validSelectors, "SITE_ADDRESS=https://example.invalid"]);
assert.notEqual(run().status, 0);
writeEnv([...validSelectors, "APP_ENV_FILE = ../.env.production"]);
assert.notEqual(run().status, 0);
const rendered = spawnSync(
"docker",
[
"compose",
"--env-file",
envFile,
"-f",
composeFile,
"config",
"--format",
"json",
],
{ encoding: "utf8" },
);
assert.equal(rendered.status, 0, rendered.stderr);
assert.equal(
JSON.parse(rendered.stdout).services.probe.environment.SELECTED,
"../.env.production",
);
writeEnv([...validSelectors, "export CADDYFILE_PATH=./Caddyfile"]);
assert.notEqual(run().status, 0);
writeEnv([...validSelectors, "SITE_ADDRESS"]);
assert.notEqual(run().status, 0);
writeEnv(validSelectors, 0o644);
assert.notEqual(run().status, 0);
} finally {