test: 扩展租户 RBAC 冒烟并同步前端版本 #7
@@ -483,6 +483,7 @@ class RuleConfigServiceImpl(IRuleConfigService):
|
||||
SELECT id, oss_url
|
||||
FROM leaudit_rule_versions
|
||||
WHERE id = ANY(:version_ids)
|
||||
AND deleted_at IS NULL
|
||||
"""
|
||||
),
|
||||
{"version_ids": version_ids},
|
||||
@@ -501,6 +502,7 @@ class RuleConfigServiceImpl(IRuleConfigService):
|
||||
SELECT DISTINCT ON (rule_set_id) rule_set_id, id
|
||||
FROM leaudit_rule_versions
|
||||
WHERE rule_set_id = ANY(:rule_set_ids)
|
||||
AND deleted_at IS NULL
|
||||
ORDER BY rule_set_id, version_seq DESC, id DESC
|
||||
"""
|
||||
),
|
||||
@@ -518,6 +520,7 @@ class RuleConfigServiceImpl(IRuleConfigService):
|
||||
SELECT oss_url
|
||||
FROM leaudit_rule_versions
|
||||
WHERE id = :version_id
|
||||
AND deleted_at IS NULL
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
@@ -676,6 +679,7 @@ class RuleConfigServiceImpl(IRuleConfigService):
|
||||
SELECT id
|
||||
FROM leaudit_rule_versions
|
||||
WHERE rule_set_id = :rule_set_id
|
||||
AND deleted_at IS NULL
|
||||
ORDER BY version_seq DESC, id DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
@@ -696,6 +700,7 @@ class RuleConfigServiceImpl(IRuleConfigService):
|
||||
SELECT version_seq
|
||||
FROM leaudit_rule_versions
|
||||
WHERE id = :version_id
|
||||
AND deleted_at IS NULL
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
|
||||
@@ -237,6 +237,7 @@ class RuleServiceImpl(IRuleService):
|
||||
rv.published_at
|
||||
FROM leaudit_rule_versions rv
|
||||
WHERE rv.rule_set_id = :rule_set_id
|
||||
AND rv.deleted_at IS NULL
|
||||
ORDER BY rv.version_seq DESC, rv.id DESC
|
||||
"""
|
||||
),
|
||||
@@ -258,6 +259,7 @@ class RuleServiceImpl(IRuleService):
|
||||
JOIN leaudit_rule_sets rs ON rs.id = rv.rule_set_id
|
||||
WHERE rs.rule_type = :rule_type
|
||||
AND rs.deleted_at IS NULL
|
||||
AND rv.deleted_at IS NULL
|
||||
ORDER BY rv.version_seq DESC, rv.id DESC
|
||||
"""
|
||||
),
|
||||
@@ -281,6 +283,7 @@ class RuleServiceImpl(IRuleService):
|
||||
FROM leaudit_rule_versions rv
|
||||
JOIN leaudit_rule_sets rs ON rs.id = rv.rule_set_id
|
||||
WHERE rv.id = :version_id
|
||||
AND rv.deleted_at IS NULL
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
@@ -1087,6 +1090,7 @@ class RuleServiceImpl(IRuleService):
|
||||
published_at
|
||||
FROM leaudit_rule_versions
|
||||
WHERE id = :version_id
|
||||
AND deleted_at IS NULL
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
@@ -1102,6 +1106,7 @@ class RuleServiceImpl(IRuleService):
|
||||
SELECT id
|
||||
FROM leaudit_rule_versions
|
||||
WHERE rule_set_id = :rule_set_id
|
||||
AND deleted_at IS NULL
|
||||
ORDER BY version_seq DESC, id DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
|
||||
+1
-1
Submodule legal-platform-frontend updated: fb2fb0b76a...f219811a6e
@@ -482,7 +482,66 @@ async def _backup_rule_domain(session) -> Path:
|
||||
return backup_path
|
||||
|
||||
|
||||
async def reset_and_import_rules(root: Path, *, dry_run: bool, prune_oss: bool) -> None:
|
||||
async def _purge_rule_history() -> int:
|
||||
async with GetAsyncSession() as session:
|
||||
await session.execute(
|
||||
text(
|
||||
"""
|
||||
UPDATE leaudit_audit_runs ar
|
||||
SET rule_version_id = rs.current_version_id,
|
||||
rule_source_oss_url = COALESCE(current_rv.oss_url, ar.rule_source_oss_url),
|
||||
rule_source_sha256 = COALESCE(current_rv.file_sha256, ar.rule_source_sha256),
|
||||
rule_type_id = COALESCE(current_rv.metadata_type_id, ar.rule_type_id)
|
||||
FROM leaudit_rule_sets rs
|
||||
LEFT JOIN leaudit_rule_versions current_rv ON current_rv.id = rs.current_version_id
|
||||
CROSS JOIN leaudit_rule_versions old_rv
|
||||
WHERE old_rv.id = ar.rule_version_id
|
||||
AND ar.rule_set_id = rs.id
|
||||
AND old_rv.id <> rs.current_version_id
|
||||
AND rs.current_version_id IS NOT NULL
|
||||
"""
|
||||
)
|
||||
)
|
||||
await session.execute(
|
||||
text(
|
||||
"""
|
||||
UPDATE leaudit_rule_results rr
|
||||
SET rule_version_id = ar.rule_version_id
|
||||
FROM leaudit_audit_runs ar
|
||||
CROSS JOIN leaudit_rule_versions old_rv
|
||||
WHERE old_rv.id = rr.rule_version_id
|
||||
AND rr.run_id = ar.id
|
||||
AND old_rv.id <> ar.rule_version_id
|
||||
"""
|
||||
)
|
||||
)
|
||||
result = await session.execute(
|
||||
text(
|
||||
"""
|
||||
DELETE FROM leaudit_rule_versions rv
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_rule_sets rs
|
||||
WHERE rs.current_version_id = rv.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_audit_runs ar
|
||||
WHERE ar.rule_version_id = rv.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM leaudit_rule_results rr
|
||||
WHERE rr.rule_version_id = rv.id
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
return int(result.rowcount or 0)
|
||||
|
||||
|
||||
async def reset_and_import_rules(root: Path, *, dry_run: bool, prune_oss: bool, purge_rule_history: bool) -> None:
|
||||
local_rules = load_local_rules(root)
|
||||
canonical_keys = {
|
||||
OssPathUtils.BuildRuleYamlKey(local.rule_type, local.version_no)
|
||||
@@ -572,6 +631,9 @@ async def reset_and_import_rules(root: Path, *, dry_run: bool, prune_oss: bool)
|
||||
print("oss_deleted=0")
|
||||
|
||||
await import_rules(root, dry_run=False)
|
||||
if purge_rule_history:
|
||||
deleted = await _purge_rule_history()
|
||||
print(f"purged_rule_versions={deleted}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -580,9 +642,17 @@ def main() -> None:
|
||||
parser.add_argument("--execute", action="store_true")
|
||||
parser.add_argument("--reset-rule-domain", action="store_true")
|
||||
parser.add_argument("--prune-oss", action="store_true")
|
||||
parser.add_argument("--purge-rule-history", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if args.reset_rule_domain:
|
||||
asyncio.run(reset_and_import_rules(Path(args.root), dry_run=not args.execute, prune_oss=args.prune_oss))
|
||||
asyncio.run(
|
||||
reset_and_import_rules(
|
||||
Path(args.root),
|
||||
dry_run=not args.execute,
|
||||
prune_oss=args.prune_oss,
|
||||
purge_rule_history=args.purge_rule_history,
|
||||
)
|
||||
)
|
||||
else:
|
||||
asyncio.run(import_rules(Path(args.root), dry_run=not args.execute))
|
||||
|
||||
|
||||
@@ -25,6 +25,18 @@ def test_g1_admin_auth_and_rbac_context(admin_client: ReleaseApiClient) -> None:
|
||||
assert users_data["total"] >= 1
|
||||
assert isinstance(users_data["items"], list)
|
||||
|
||||
roles_response = admin_client.get("/api/v3/rbac/roles?page=1&page_size=20")
|
||||
roles_data = ReleaseApiClient.json_data(roles_response)
|
||||
assert roles_data["items"]
|
||||
role_id = int(roles_data["items"][0]["id"])
|
||||
role_users_response = admin_client.get(f"/api/v3/rbac/roles/{role_id}/users?page=1&page_size=1")
|
||||
role_users_data = ReleaseApiClient.json_data(role_users_response)
|
||||
assert role_users_data["page"] == 1
|
||||
assert role_users_data["page_size"] == 1
|
||||
assert "total" in role_users_data
|
||||
assert isinstance(role_users_data["items"], list)
|
||||
assert len(role_users_data["items"]) <= 1
|
||||
|
||||
org_response = admin_client.get("/api/admin/users/organizations/tree?include_users=false")
|
||||
org_data = ReleaseApiClient.json_data(org_response)
|
||||
assert "organizations" in org_data
|
||||
|
||||
@@ -105,6 +105,12 @@ def test_assert_rollback_target_allows_previous_version():
|
||||
service._assert_rollback_target(version_row, rule_set)
|
||||
|
||||
|
||||
def test_rule_version_queries_exclude_soft_deleted_versions():
|
||||
sql_text = str(RuleServiceImpl.GetVersions.__code__.co_consts)
|
||||
|
||||
assert "rv.deleted_at IS NULL" in sql_text
|
||||
|
||||
|
||||
def test_tenant_user_requires_rule_tenant_schema_before_write():
|
||||
service = RuleServiceImpl()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user