fix: 用专用权限收窄经理 AP 访问(09-07-manager-ap-access-scope)
这个提交包含在:
@@ -18,6 +18,56 @@
|
||||
redacted form.
|
||||
- `scripts/qa/check-trellis-governance.mjs` must pass before commit.
|
||||
|
||||
## Scenario: AP Full-Ledger Reading Is Not Payment Review
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
AP financial summary and reimbursement ledger reads, not general entity visibility.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- Permission: `finance.ledger.view` in both server and client role maps.
|
||||
- Reads: `GET /api/ap-operations` and `GET /api/ap-operations/reimbursement-ledger`.
|
||||
- Separate export: `POST /api/exports/ap-operations`.
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
Grant ledger reading to `ceo`, `finance`, `finance_mgr`, not `manager` or
|
||||
`system_admin`. Preserve emergency `admin` wildcard semantics. Both reads require
|
||||
the dedicated permission before data queries; query filters cannot confer access.
|
||||
Frontend route and navigation projections use the same permission. Keep manager
|
||||
payment review and multi-role permission unions intact; never grant CEO payment
|
||||
management to preserve read access. Export keeps its existing independent
|
||||
`payment.batch.manage` / `risk.review.manage` rule.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
Feature enabled: missing ledger permission returns 403 / `PERM_001`, with no
|
||||
financial query. Feature disabled: the existing 409 refusal may occur first.
|
||||
CEO/finance/finance manager and manager+finance retain reading. Old payment or
|
||||
risk permissions alone no longer imply ledger reading.
|
||||
|
||||
### 5. Good / Base / Bad Cases
|
||||
|
||||
- Base: manager keeps payment review but cannot enter AP.
|
||||
- Good: CEO reads AP without acquiring export or payment-write rights.
|
||||
- Bad: hiding a menu while leaving either backend read unrestricted.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
Route injection checks both reads, filters and zero queries on refusal; role and
|
||||
navigation tests cover CEO and mixed roles. Browser checks cover manager direct
|
||||
refusal and preserved payment entry, plus allowed AP readers. Export and payment
|
||||
review regressions remain separate from ledger authorization.
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
Wrong: `payment.batch.review` implies all-company financial visibility, or a CEO
|
||||
role exception is added to AP handlers. Correct: use `finance.ledger.view` in role
|
||||
maps and read guards. This AP-only change does not alter the manager's six
|
||||
`*.view_all` permissions: reimbursement-list all-record visibility remains an
|
||||
explicit deferred decision, not a completed scope restriction.
|
||||
|
||||
## Scenario: Bank Account Snapshots And Payment-Order Export
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# AP 全量读取最小收窄方案(专用权限修订已批准)
|
||||
|
||||
## 1. 读取授权
|
||||
|
||||
获批修订:新增专用权限 `finance.ledger.view`,仅授予 ceo、finance、finance_mgr;两个 AP GET 及前端入口统一只检查此权限。manager 不授予;不存在 CEO 角色特判,旧付款管理、复核、风险和支付权限均不再独立授予 AP 读取。既有应急 admin 通配符语义不变。
|
||||
|
||||
前后端各有静态 ROLE_PERMISSIONS,需要同步三类角色和相关测试,不是只改服务端三行。无数据库权限迁移,不授予 CEO 写权限,不按人员账号特判,不采用 manager deny-list。AP 导出仍使用原有独立权限。
|
||||
|
||||
## 2. 接入范围
|
||||
|
||||
- `server/src/routes/apOperations.js`:两个 GET 共用收紧后的守卫,数据查询之前拒绝。功能门禁先后顺序保持现状。
|
||||
- `client/src/auth/permissions.ts`:集中表达 AP 全量读取判据;不修改通用付款复核判据或其他角色权限集合。
|
||||
- `client/src/router/index.tsx`、AP 页面入口及服务端 `workspaceSettings`:只同步 AP 投影,核对移动和桌面入口,不能全局替换相同的旧 permission 数组而误伤付款路由。
|
||||
- `server/src/routes/exports.js`:现有导出不含复核授权,本轮不更改;验证拒绝和已有正例。
|
||||
- 不在 AP 中另造“经理相关单据子集”;经理继续通过既有审批/付款复核路径处理职责内工作。若核实必须借 AP 才能完成复核,报告导航依赖并交审,不默认扩充数据范围。
|
||||
|
||||
## 3. 验证矩阵
|
||||
|
||||
| 身份 | AP 汇总/台账 | 付款复核 | AP 导出 |
|
||||
| --- | --- | --- | --- |
|
||||
| employee | 拒绝 | 按现有权限拒绝 | 拒绝 |
|
||||
| manager,仅复核职责 | 拒绝 | 保留原业务条件 | 拒绝 |
|
||||
| ceo | 保留全量读取 | 保留原业务条件 | 不新增 |
|
||||
| finance / finance_mgr | 专用权限允许 | 不改变角色和独立复核条件 | 按既有两项权限 |
|
||||
| manager+已授权财务角色 | 允许 | 原条件不变 | 按财务授权 |
|
||||
| 仅系统管理员 | 不新增 | 不新增 | 不新增 |
|
||||
| 仅持旧付款管理/复核/风险/支付权限 | 拒绝 | 按原权限 | 按既有两项权限 |
|
||||
|
||||
API 验证包括数据查询未发生、筛选不绕过;前端验证包括直连、菜单和复核入口。现有经理 AP 拒绝断言保留,必要时拆分用例使后续角色断言真正执行,不以局部通过冒充整个权限审计通过。
|
||||
|
||||
## 4. 安全与交付边界
|
||||
|
||||
不查询生产日志,不回填历史访问结论。不触碰既有门禁交审文件;若实施必须修改已交审测试,先保存对应增量基线,单独交本 task diff,不混报旧包。实现后独立只读复核,提交、推送和部署继续另行授权。
|
||||
@@ -0,0 +1,57 @@
|
||||
# 执行计划
|
||||
|
||||
## 2026-09-08 独立复核与提交授权
|
||||
|
||||
- 用户已独立复核通过本 task 的 18 文件包,包括单权限守卫、原有获准角色无误伤、经理复核保留、前后端正反测试与 AP-only 边界;不是主会话自检替代独立复核。
|
||||
- 用户本轮授权独立提交 AP 修复,并与门禁包及已有两个 Trellis 提交一起推送;不包含部署或归档。本节之后的“待复核/未提交”表述保留为上轮交审时的历史状态。
|
||||
- 推送不是发布;尚未授权生产部署,不能宣称生产 AP 权限已经收窄。经理其他 view_all 仍保留,不能宣称全域只看相关单据。
|
||||
- 后续若准备未通过完整候选验收的发布方案,必须另行明确批准合同、验证缺口、候选、回滚及验收条件;本次提交推送授权不是整道候选门禁的豁免。
|
||||
|
||||
## 当前状态
|
||||
|
||||
- 2026-09-07:方案获批并修订为专用 finance.ledger.view,已 start;inline 实施。已保存全仓起始快照于本 task 的 artifacts,旧门禁包不得改写。
|
||||
- 已读取 AP 两个 GET、导出守卫、角色权限和前端路由/页面判据,形成 PRD 与设计。
|
||||
- 门禁任务不关闭、不归档、不自动提交;本轮实现及验证已完成,等待用户独立只读权限复核。
|
||||
|
||||
## 执行结果
|
||||
|
||||
- 已同步前后端静态角色表:仅 ceo、finance、finance_mgr 新增 finance.ledger.view;manager/ceo 的复核权限和六个 view_all 不变。应急 admin 通配符不变。
|
||||
- AP 两个 GET、前端路由、本地 fallback 导航、服务端导航注册表只使用专用读取权限;没有 CEO 角色分支。导出与付款复核实现未修改。
|
||||
- 新增 AP 路由矩阵;角色/导航/导出单测补反例;既有浏览器经理 AP 可访问测试按获批口径改为直连拒绝,新增 CEO、finance、finance_mgr、manager+finance 读取正例,实际切换财务台账;合同用例正文未修改、未运行。
|
||||
- 后端五文件 123/123 PASS(含 76 条付款批次报销回归);前端六条定向浏览器 6/6 PASS、零重试、trace。不是 full-local,不抵扣旧 58 条清单。
|
||||
- typecheck、独立 artifacts 目录 build、Node 语法、diff 检查和 Trellis governance PASS;未覆盖 client/dist。build 保留既有 Browserslist 数据陈旧提示,没有更新依赖。
|
||||
- 首轮扩展付款回归有 BIFF8 导出失败,默认 Python 缺 xlrd;使用已存在的隔离 Python(固定 BIFF8 依赖)后 123/123 通过。原始失败日志保留,不宣称任意环境都具备该依赖。
|
||||
- 浏览器前置原生 online=true、无 cookie、登录表单可见、refresh=0;本次是本地 Vite + 合成 API 浏览器测试,不冒充真实后端浏览器闭环或部署验证。
|
||||
- 旧门禁 33 文件逐一摘要核对全部不变。未提交、push、部署或操作生产;独占 Vite 服务已停止。独立只读复核待用户,不派 implement/check 代理,不以主会话自检冒充独立复核。
|
||||
|
||||
## 验证命令与证据
|
||||
|
||||
证据目录:`artifacts/qa-flow/manager-ap-access-scope/implementation-01/`。
|
||||
|
||||
```bash
|
||||
cd server
|
||||
PAYMENT_ORDER_PYTHON_BIN=<已存在的隔离BIFF8解释器> npm test -- tests/unit/routes/apOperations.permissions.test.js tests/unit/constants/permissions.test.js tests/unit/workspaceSettings.navigation.test.js tests/unit/routes/exports.apOperations.test.js tests/unit/routes/paymentBatches.reimbursement.test.js
|
||||
cd ../client
|
||||
npm run typecheck
|
||||
E2E_MODE=local E2E_BASE_URL=http://127.0.0.1:23117 ./node_modules/.bin/playwright test tests/e2e/payment-reviewer-permissions.spec.ts --grep '只有付款复核职责|AP 专用读取权限' --retries=0 --trace=on --reporter=list --output=../artifacts/qa-flow/manager-ap-access-scope/implementation-01/browser-final-results
|
||||
./node_modules/.bin/vite build --outDir ../artifacts/qa-flow/manager-ap-access-scope/implementation-01/build
|
||||
cd ..
|
||||
node scripts/qa/check-trellis-governance.mjs
|
||||
git diff --check
|
||||
```
|
||||
|
||||
日志:`server-tests-final.log`、`browser-tests-final.log`、`browser-preflight.json`、`typecheck-final.log`、`build.log`、`governance-final.log`。局部 6 条来源 spec 与 grep 如实记录,不能称整个 payment-reviewer-permissions spec 通过。
|
||||
|
||||
## 原批准步骤(保留顺序记录)
|
||||
|
||||
1. 加载权限、后端、前端相关稳定规约,冻结既有工作树和本 task 写入面。
|
||||
2. 先补 AP 权限矩阵测试及 CEO/多角色/经理复核保留反例。
|
||||
3. 最小收紧 AP 后端读取与前端入口投影,不改其他 view_all 或付款复核授权。
|
||||
4. 执行针对性后端测试、前端类型检查及获批的本地合成浏览器验证;不默认重跑 full-local 或生产操作。
|
||||
5. 对照 AC 审核并交独立只读权限复核;发现新的数据范围或正常复核依赖问题先报告,不扩修。
|
||||
6. 获批后更新现有权限规约,交付明确保留的 view_all 开口。提交、推送、部署均不随实施授权自动进行。
|
||||
|
||||
## 待独立复核
|
||||
|
||||
- 复核代码、正反权限结果和范围;本轮不请求或执行生产变更。task 保持 in_progress。
|
||||
- 明确保留:经理仍可从报销列表查看全部单据,本轮只收窄 AP 入口,未实现所有业务域“只看相关单据”。
|
||||
@@ -0,0 +1,59 @@
|
||||
# 经理 AP 财务台账与付款汇总访问收紧
|
||||
|
||||
## Goal
|
||||
|
||||
仅收窄 AP 财务台账与付款汇总的全量读取入口:只有经理/付款复核职责的账号不得借付款复核权限访问全公司 AP 数据;保留 CEO 全量读取、既有财务读取及经理正常审批和付款复核能力。
|
||||
|
||||
2026-09-07 用户已批准 AP-only 方案实施,附修订:使用 finance.ledger.view 专用权限,不使用 CEO 角色分支。仅授予 ceo、finance、finance_mgr;前后端同步。当前 in_progress;不查询生产、不部署。
|
||||
|
||||
## 已确认事实与边界
|
||||
|
||||
- 用户确认系统管理员、经理、财务、员工是不同业务角色;授权按角色和权限表达,不硬编码个人账号。
|
||||
- `server/src/constants/permissions.js` 中 manager 和 ceo 均有 `payment.batch.review`;manager 另有六个 `*.view_all`。本轮不调整这些全量查看权限。
|
||||
- `server/src/routes/apOperations.js` 的两个 GET 路由共用四选一读取守卫,其中包含 `payment.batch.review`;台账调用 `listFinanceLedger` 时只传 Prisma 与查询条件,没有传当前员工范围。
|
||||
- `client/tests/e2e/permission-direct-access.spec.ts` 留有经理 AP 读取预期拒绝、实际返回 200 的本地合成测试证据。业务现已明确拒绝经理仅凭复核职责获取 AP 全量数据;不将此失败改成接受 200。
|
||||
- 当前 AP 导出使用独立的 `payment.batch.manage` / `risk.review.manage` 守卫,不包含 `payment.batch.review`。本轮保留既有导出边界,不为 CEO 或经理新增导出权限。
|
||||
- 未证明实际生产部署与当前源码一致,未证明经理访问过无关数据,不宣称发生过泄露。
|
||||
|
||||
## Scope
|
||||
|
||||
- 范围:AP 汇总、报销财务台账两个后端读取入口;对应前端直连保护、导航与入口投影;相关正反权限测试和既有权限规约。
|
||||
- AP 导出仅作旁路负例和既有授权不变验证,不重构导出流程。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 不修改报销、请假、考勤、采购、资产、项目的 `view_all`,不设计本人/部门/审批链可见范围,不重构付款批次自身的数据范围。
|
||||
- 明确保留的开口:本轮完成后,经理仍可从报销列表查看全部报销。这是待业务另行决定的权限范围,不得在交付中宣称“经理只能看相关单据”已经全局实现。
|
||||
- 门禁 33 文件包不变,58 条不逐条修,合同阶段 B、R1、场景 8 继续暂停。业务包接收确认独立待办,不属于本任务交付。
|
||||
|
||||
## Requirements
|
||||
|
||||
- R1:仅持经理/付款复核职责、没有其他 AP 全量授权的账号访问两个 AP GET 接口必须被后端拒绝,不返回汇总、台账或计数;不得仅靠隐藏前端菜单。
|
||||
- R2:CEO、finance、finance_mgr 通过专用权限保留两个接口的全量读取;旧付款/风险权限码本身不再隐含读取。不得通过授予 CEO 付款管理等写权限实现读取,也不得删除经理的 `payment.batch.review`。
|
||||
- R3:经理原有正常审批、付款复核及独立复核约束不变。前端提供既有付款复核入口,不以恢复 AP 全量访问解决导航问题。
|
||||
- R4:多角色按显式授权并集合成;manager 与已授权财务角色组合不得因包含 manager 被一票否决。系统管理员身份不自动等同财务权限。
|
||||
- R5:查询参数、日期、关键词、分页不能绕过 AP 读取守卫。导出保持原权限,不将 CEO 全量读取等同导出或写入授权。
|
||||
- R6:实施与部署分别批准;实现后须只读独立权限复核,主会话验证不能冒充独立复核。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] 普通员工和仅经理角色对两个 GET 均被拒绝;功能开启时为 403,关闭时可保留既有无数据 409。拒绝路径不调用财务数据查询。
|
||||
- [ ] CEO、finance、finance_mgr 正例通过;manager+财务组合保留其财务授权;仅系统管理员不新增授权。
|
||||
- [ ] 日期、状态、关键词等查询组合不能改变拒绝结果;经理 AP 导出仍拒绝,既有导出角色不退化。
|
||||
- [ ] 经理付款复核正例及原有独立复核负例通过;不扩大其付款执行、组批或其他写权限。
|
||||
- [ ] 前端 AP 直连被阻止、导航不暴露不可用入口,经理付款复核入口仍可达;CEO 和财务 AP 入口保留。
|
||||
- [ ] 六个 view_all 未修改,交付明确“仅 AP 收窄”,不冒充所有业务单据范围收窄。
|
||||
- [ ] 针对性验证与只读独立复核有记录;无部署、生产查询或写入,除非另获明确授权。
|
||||
|
||||
## Test Plan
|
||||
|
||||
- Fastify inject:两个 AP GET、筛选组合、旧权限码反例、专用权限正例、feature-off、无权时零财务查询。
|
||||
- 角色与导航单测:经理、CEO、财务、财务经理、系统管理员、多角色;保持经理付款入口。
|
||||
- 既有 AP 导出及付款复核回归:保留独立授权、制单/复核分离及 CEO 无新增导出权。
|
||||
- 本地合成浏览器:经理直连 403 和零 AP 请求、CEO/财务/财务经理/混合角色进入 AP 和台账、经理付款页保留;零重试、trace,排除合同用例及其他红项。
|
||||
- 前端 typecheck、隔离目录 build、语法、diff、治理检查。扩大付款回归需既有固定 BIFF8 Python 依赖,不改产品逻辑绕过环境缺项。
|
||||
- 独立只读权限复核待用户;inline 主会话自检不冒充独立复核。
|
||||
|
||||
## Notes
|
||||
|
||||
- 本文及 design.md 的专用权限修订已获实施批准;验证结果见 implement.md,不是生产状态证明。
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"id": "manager-ap-access-scope",
|
||||
"name": "manager-ap-access-scope",
|
||||
"title": "经理 AP 财务台账与付款汇总访问收紧",
|
||||
"description": "使用 finance.ledger.view 收紧 AP 全量读取,保留 CEO 财务读取与经理复核;其他 view_all 和导出授权不变,不部署",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": "AP-only 专用读取权限、对应前后端投影和权限验证",
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "shunli",
|
||||
"assignee": "shunli",
|
||||
"createdAt": "2026-09-07",
|
||||
"completedAt": null,
|
||||
"branch": "main",
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
"server/src/constants/permissions.js",
|
||||
"server/src/routes/apOperations.js",
|
||||
"server/src/services/workspaceSettings.js",
|
||||
"client/src/auth/permissions.ts",
|
||||
"client/src/router/index.tsx",
|
||||
"client/src/components/navigation/NavLinks.tsx",
|
||||
"client/tests/e2e/payment-reviewer-permissions.spec.ts",
|
||||
"server/tests/unit/routes/apOperations.permissions.test.js",
|
||||
"server/tests/unit/constants/permissions.test.js",
|
||||
"server/tests/unit/workspaceSettings.navigation.test.js",
|
||||
"server/tests/unit/routes/exports.apOperations.test.js",
|
||||
".trellis/spec/hyb-oa/security-privacy.md"
|
||||
],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户