ORG8 固化组织账号只读审计口径
这个提交包含在:
+103
@@ -60,6 +60,109 @@ OA 员工账号是权限、审批、业务数据和审计的主事实源;企
|
||||
- 新员工账号创建必须同时确认直属主管、初始角色、账号状态和企业微信绑定路径。
|
||||
- 离职或停用账号必须阻断登录、企业微信入口和新业务处理,但不得删除历史单据和审批记录。
|
||||
|
||||
只读审计口径:
|
||||
|
||||
所有 ORG8 主数据审计只允许使用只读账号执行 `SELECT`,输出仅保留工号、姓名、状态、角色摘要、业务类型和数量;不得导出手机号、邮箱、银行卡、身份证号、密码哈希、token 或企业微信真实标识。发现问题后只记录摘要和责任归属,不在审计 SQL 中修数据。
|
||||
|
||||
直属主管缺失:
|
||||
|
||||
```sql
|
||||
WITH role_summary AS (
|
||||
SELECT employee_id, string_agg(role_code::text, ',' ORDER BY role_code::text) AS roles
|
||||
FROM employee_roles
|
||||
GROUP BY employee_id
|
||||
)
|
||||
SELECT e.employee_no, e.name, e.status, COALESCE(r.roles, '') AS roles
|
||||
FROM employees e
|
||||
LEFT JOIN role_summary r ON r.employee_id = e.id
|
||||
WHERE e.status = 'active'
|
||||
AND e.direct_manager_id IS NULL
|
||||
AND COALESCE(r.roles, '') !~ '(^|,)(ceo|admin)(,|$)'
|
||||
ORDER BY e.employee_no;
|
||||
```
|
||||
|
||||
主管停用或主管链断裂:
|
||||
|
||||
```sql
|
||||
SELECT e.employee_no, e.name, m.employee_no AS manager_no, m.name AS manager_name, m.status AS manager_status
|
||||
FROM employees e
|
||||
LEFT JOIN employees m ON m.id = e.direct_manager_id
|
||||
WHERE e.status = 'active'
|
||||
AND e.direct_manager_id IS NOT NULL
|
||||
AND (m.id IS NULL OR m.status <> 'active' OR m.archived_at IS NOT NULL)
|
||||
ORDER BY e.employee_no;
|
||||
```
|
||||
|
||||
待办分配给停用审批人或无有效角色持有人:
|
||||
|
||||
```sql
|
||||
SELECT t.id AS task_id, wi.entity_type, a.employee_no AS assignee_no, a.name AS assignee_name, a.status AS assignee_status
|
||||
FROM workflow_tasks t
|
||||
JOIN workflow_instances wi ON wi.id = t.instance_id
|
||||
LEFT JOIN employees a ON a.id = t.assignee_id
|
||||
WHERE t.status = 'pending'
|
||||
AND t.assignee_id IS NOT NULL
|
||||
AND (a.id IS NULL OR a.status <> 'active' OR a.archived_at IS NOT NULL)
|
||||
ORDER BY t.created_at;
|
||||
|
||||
SELECT t.assignee_role, count(*) AS pending_count
|
||||
FROM workflow_tasks t
|
||||
WHERE t.status = 'pending'
|
||||
AND t.assignee_role IS NOT NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM employee_roles er
|
||||
JOIN employees e ON e.id = er.employee_id
|
||||
WHERE er.role_code = t.assignee_role
|
||||
AND e.status = 'active'
|
||||
AND e.archived_at IS NULL
|
||||
)
|
||||
GROUP BY t.assignee_role
|
||||
ORDER BY t.assignee_role;
|
||||
```
|
||||
|
||||
`admin-only` 误用为业务审批:
|
||||
|
||||
```sql
|
||||
WITH role_summary AS (
|
||||
SELECT employee_id, string_agg(role_code::text, ',' ORDER BY role_code::text) AS roles
|
||||
FROM employee_roles
|
||||
GROUP BY employee_id
|
||||
)
|
||||
SELECT t.id AS task_id, wi.entity_type, e.employee_no, e.name, r.roles
|
||||
FROM workflow_tasks t
|
||||
JOIN workflow_instances wi ON wi.id = t.instance_id
|
||||
JOIN employees e ON e.id = t.assignee_id
|
||||
JOIN role_summary r ON r.employee_id = e.id
|
||||
WHERE t.status = 'pending'
|
||||
AND r.roles ~ '(^|,)admin(,|$)'
|
||||
AND r.roles !~ '(^|,)(manager|ceo|finance|finance_mgr|hr)(,|$)'
|
||||
ORDER BY t.created_at;
|
||||
|
||||
SELECT id, name, level1_role, level2_role, level3_role
|
||||
FROM approval_rules
|
||||
WHERE enabled = true
|
||||
AND 'admin' IN (level1_role::text, COALESCE(level2_role::text, ''), COALESCE(level3_role::text, ''))
|
||||
ORDER BY priority;
|
||||
```
|
||||
|
||||
财务和系统管理员混授:
|
||||
|
||||
```sql
|
||||
WITH role_summary AS (
|
||||
SELECT employee_id, string_agg(role_code::text, ',' ORDER BY role_code::text) AS roles
|
||||
FROM employee_roles
|
||||
GROUP BY employee_id
|
||||
)
|
||||
SELECT e.employee_no, e.name, e.status, r.roles
|
||||
FROM employees e
|
||||
JOIN role_summary r ON r.employee_id = e.id
|
||||
WHERE e.status = 'active'
|
||||
AND r.roles ~ '(^|,)admin(,|$)'
|
||||
AND r.roles ~ '(^|,)(finance|finance_mgr)(,|$)'
|
||||
ORDER BY e.employee_no;
|
||||
```
|
||||
|
||||
## 4. 人员生命周期管理
|
||||
### 4.1 入职
|
||||
1. 在 `人员管理` 创建员工账号。
|
||||
|
||||
在新工单中引用
屏蔽一个用户