feat: let the retention script be told which table it may delete from
Until now the target came from whatever search_path resolved to. The script printed what it found, but that print and the DELETE happen in the same run with nobody in between, so it only ever helped the person who ran a dry-run first. Swap the role that runs it and "$user" can resolve somewhere else entirely. --table takes the whole qualified name and resolves it directly. The table half has to be llm_calls: a version that accepts any name turns one typo into a general purpose row deleter, and any table with a created_at and a tenant_id would go through the same batched DELETE without complaint. The tests that run it now run as a role that owns its own scratch table and holds nothing on the shared one, so the row-count snapshot could go. What replaced it is a case that lets the script fall through to the shared table on purpose and asserts it exits 2 having deleted nothing. That one has no red-first path, since making it red means running it as the superuser, which is the thing being prevented; the finding's probe covers it instead. Five of the new usage tests passed before the flag existed, because argparse rejects an unknown --table with exit 1 and the word --table in stderr, which is exactly what they asserted. They now also assert the error is not "unrecognized", which is the difference between testing the validation and testing argparse.
This commit is contained in:
@@ -261,6 +261,104 @@ class TestUsageErrors:
|
||||
|
||||
assert result.returncode == 1
|
||||
|
||||
# --- --table 的参数分类(issue #18 设计 §4.2);真实解析行为在集成层验 ---
|
||||
|
||||
def test_sqlite_with_table_exits_one(self, tmp_path):
|
||||
"""SQLite 库文件即目标,无 schema 概念,故 `--table` 在该分支无歧义可消。"""
|
||||
result = _run(
|
||||
"--backend",
|
||||
"sqlite",
|
||||
"--path",
|
||||
str(tmp_path / "x.db"),
|
||||
"--older-than-days",
|
||||
"7",
|
||||
"--table",
|
||||
"some_schema.llm_calls",
|
||||
)
|
||||
|
||||
assert result.returncode == 1
|
||||
assert "--table" in result.stderr
|
||||
# 单看退出码与 "--table" 字样会被 argparse 的 "unrecognized arguments" 蒙混
|
||||
# 过去(它也是退出 1、也回显参数名)。必须钉住"参数已被识别、因规则被拒"。
|
||||
assert "unrecognized" not in result.stderr
|
||||
|
||||
def test_table_without_schema_qualifier_exits_one(self):
|
||||
"""单段等于没声明: 目标仍由 `search_path` 决定,隐式性原样保留,故拒绝。"""
|
||||
result = _run(
|
||||
"--backend",
|
||||
"postgres",
|
||||
"--dsn",
|
||||
"postgresql://x/y",
|
||||
"--older-than-days",
|
||||
"7",
|
||||
"--table",
|
||||
"llm_calls",
|
||||
)
|
||||
|
||||
assert result.returncode == 1
|
||||
assert "--table" in result.stderr
|
||||
# 单看退出码与 "--table" 字样会被 argparse 的 "unrecognized arguments" 蒙混
|
||||
# 过去(它也是退出 1、也回显参数名)。必须钉住"参数已被识别、因规则被拒"。
|
||||
assert "unrecognized" not in result.stderr
|
||||
|
||||
def test_table_with_empty_segment_exits_one(self):
|
||||
result = _run(
|
||||
"--backend",
|
||||
"postgres",
|
||||
"--dsn",
|
||||
"postgresql://x/y",
|
||||
"--older-than-days",
|
||||
"7",
|
||||
"--table",
|
||||
".llm_calls",
|
||||
)
|
||||
|
||||
assert result.returncode == 1
|
||||
assert "--table" in result.stderr
|
||||
# 单看退出码与 "--table" 字样会被 argparse 的 "unrecognized arguments" 蒙混
|
||||
# 过去(它也是退出 1、也回显参数名)。必须钉住"参数已被识别、因规则被拒"。
|
||||
assert "unrecognized" not in result.stderr
|
||||
|
||||
def test_table_with_quote_in_a_segment_exits_one(self):
|
||||
"""含引号的复杂标识符不支持: 此时退回不给 `--table` 的路径(见 epilog)。"""
|
||||
result = _run(
|
||||
"--backend",
|
||||
"postgres",
|
||||
"--dsn",
|
||||
"postgresql://x/y",
|
||||
"--older-than-days",
|
||||
"7",
|
||||
"--table",
|
||||
'sch"ema.llm_calls',
|
||||
)
|
||||
|
||||
assert result.returncode == 1
|
||||
assert "--table" in result.stderr
|
||||
# 单看退出码与 "--table" 字样会被 argparse 的 "unrecognized arguments" 蒙混
|
||||
# 过去(它也是退出 1、也回显参数名)。必须钉住"参数已被识别、因规则被拒"。
|
||||
assert "unrecognized" not in result.stderr
|
||||
|
||||
def test_table_naming_another_table_exits_one(self):
|
||||
"""表名段锁死: 不加这条,`--table` 会把本脚本扩成"任意同形表删除工具"。"""
|
||||
result = _run(
|
||||
"--backend",
|
||||
"postgres",
|
||||
"--dsn",
|
||||
"postgresql://x/y",
|
||||
"--older-than-days",
|
||||
"7",
|
||||
"--table",
|
||||
"audit.events",
|
||||
)
|
||||
|
||||
assert result.returncode == 1
|
||||
assert "--table" in result.stderr
|
||||
# 单看退出码与 "--table" 字样会被 argparse 的 "unrecognized arguments" 蒙混
|
||||
# 过去(它也是退出 1、也回显参数名)。必须钉住"参数已被识别、因规则被拒"。
|
||||
assert "unrecognized" not in result.stderr
|
||||
# 错误消息要当场把边界说清: 本脚本的作用域到 llm_calls 为止
|
||||
assert "llm_calls" in result.stderr
|
||||
|
||||
|
||||
class TestHelp:
|
||||
def test_help_names_the_maintenance_role_and_the_recommended_path(self):
|
||||
@@ -271,3 +369,12 @@ class TestHelp:
|
||||
assert "维护角色" in result.stdout
|
||||
assert "REVOKE" in result.stdout
|
||||
assert "PARTITION" in result.stdout
|
||||
|
||||
def test_help_states_the_table_name_is_fixed(self):
|
||||
"""`--table` 只有 schema 一段可变,这条边界必须写在运维会读到的地方。"""
|
||||
result = _run("--help")
|
||||
|
||||
assert result.returncode == 0
|
||||
assert "--table" in result.stdout
|
||||
assert "只清理" in result.stdout
|
||||
assert "llm_calls" in result.stdout
|
||||
|
||||
Reference in New Issue
Block a user