diff --git a/backend/internal/httpapi/dns_api_test.go b/backend/internal/httpapi/dns_api_test.go index 9f0b93f..548158b 100644 --- a/backend/internal/httpapi/dns_api_test.go +++ b/backend/internal/httpapi/dns_api_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "net/http" "net/http/httptest" + "path/filepath" "strings" "testing" @@ -78,6 +79,37 @@ func TestDNSCredentialUseRejectsUnauthorizedProject(t *testing.T) { } } +func TestSettingsDNSProjectAssignmentRequiresDNSManagePermission(t *testing.T) { + dir := t.TempDir() + cfg := config.Default(dir) + cfg.SetupReady = true + cfg.DNS.VerificationState = "verified" + cfg.Web.Hostname = "scert.example.test" + cfg.Admin.Username = "admin" + cfg.Admin.Email = "admin@example.test" + cfg.Admin.PasswordHash = mustTestPasswordHash(t, "Password123") + configPath := filepath.Join(dir, "config", "scert.json") + if err := cfg.Save(configPath); err != nil { + t.Fatalf("保存测试配置失败:%v", err) + } + server := New(Dependencies{ + Config: cfg, ConfigPath: configPath, + ProjectDomains: projectDomainRepositoryStub{authorizeErr: repository.ErrProjectAccessDenied}, + }) + cookie := loginForSettingsTest(t, server) + request := httptest.NewRequest(http.MethodPut, "/api/v1/settings", strings.NewReader(`{"dns":{"project_id":"project-a"}}`)) + request.Header.Set("Content-Type", "application/json") + request.AddCookie(cookie) + response := httptest.NewRecorder() + server.Handler().ServeHTTP(response, request) + if response.Code != http.StatusForbidden { + t.Fatalf("无 DNS 管理权限修改项目归属应返回 403,实际为 %d:%s", response.Code, response.Body.String()) + } + if server.config.DNS.ProjectID != "default" { + t.Fatalf("拒绝修改后 DNS 项目归属不应变化:%q", server.config.DNS.ProjectID) + } +} + func TestAdminDNSTestReturnsVerificationResult(t *testing.T) { cfg := config.Default(t.TempDir()) cfg.SetupReady = true diff --git a/doc/Scert开发任务清单.md b/doc/Scert开发任务清单.md index b85ba3b..cb3fd8c 100644 --- a/doc/Scert开发任务清单.md +++ b/doc/Scert开发任务清单.md @@ -3415,4 +3415,18 @@ Linux Ubuntu 22.04 上的 `Scert-admin` 手动启停、无开机自启动、无 - `[~]` DNS 账户项目归属与使用权限、续期任务及其他任务/资源写入权限仍在开发。 - `[!]` PostgreSQL/MySQL 矩阵、浏览器验收、Linux/Windows 生产部署、远端 SSH、HTTPS/DNS/ACME 和 `odacm.cn` 实机验收尚未执行。 -下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 \ No newline at end of file +下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 + +## 本轮开发进度(2026-09-29 19:30) + +总体验收位置继续保持 **P0-03 完成待复审**,当前仍处于先开发、后统一测试阶段。 + +- `[x]` DNS 配置和账户响应补充项目归属,历史缺失归属自动兼容到默认项目。 +- `[x]` DNS 凭据使用入口接入实时项目成员权限,跨项目、撤权和停用账户不能继续使用凭据。 +- `[x]` DNS 项目归属修改要求 `dns.manage`,无权限时拒绝保存且不改变原配置。 +- `[x]` DNS 账户管理页面显示项目归属,保留归属用户和脱敏账号标识。 +- `[x]` 本批专项后端测试、`go vet ./...`、前端 230 项测试和前端生产构建通过。 +- `[~]` P0-07 仍需继续补齐续期、证书导入/部署、任务执行/重试和其他资源写入的完整权限链。 +- `[!]` PostgreSQL/MySQL 矩阵、浏览器验收、远端 SSH、HTTPS/DNS/ACME 和生产部署验收尚未执行。 + +下一步继续开发剩余任务与证书/部署权限链,开发阶段结束后再统一执行三库、浏览器和远端生产流程测试。 diff --git a/doc/Scert整改任务执行清单.md b/doc/Scert整改任务执行清单.md index 27a03ed..a121079 100644 --- a/doc/Scert整改任务执行清单.md +++ b/doc/Scert整改任务执行清单.md @@ -716,4 +716,12 @@ P0-05 从 `[!]` 调整为 `[~]`,并未标记完成;P0-04 剩余门禁和全 - `[~]` DNS 账户项目归属与使用权限、续期任务及其他任务/资源写入权限仍在开发。 - `[!]` PostgreSQL/MySQL 矩阵、浏览器验收、Linux/Windows 生产部署、远端 SSH、HTTPS/DNS/ACME 和 `odacm.cn` 实机验收尚未执行。 -下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 \ No newline at end of file +下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 + +## 本轮执行状态(2026-09-29 19:30) + +- **总体验收位置:P0-03 完成待复审。** +- **P0-07 DNS 项目权限批次:** DNS 账户项目归属、凭据使用权限、项目归属修改授权和前端项目归属展示已完成,等待复审。 +- **自动化验证:** 后端 HTTP API/配置专项通过,前端 230 项测试通过,前端生产构建通过;这些结果不等同于生产部署验收。 +- **仍在开发:** 续期任务、证书导入/部署、任务执行/重试及其他资源写入的完整实时授权和拒绝副作用验证。 +- **尚未执行:** PostgreSQL/MySQL 矩阵、浏览器清缓存验收、远端密码 SSH、HTTPS/DNS/ACME 和生产部署流程。 diff --git a/doc/Scert整改合并优化清单.md b/doc/Scert整改合并优化清单.md index fb0621f..1d00e43 100644 --- a/doc/Scert整改合并优化清单.md +++ b/doc/Scert整改合并优化清单.md @@ -1352,4 +1352,15 @@ P0-11 生产验收门禁 - `[~]` DNS 账户项目归属与使用权限、续期任务及其他任务/资源写入权限仍在开发。 - `[!]` PostgreSQL/MySQL 矩阵、浏览器验收、Linux/Windows 生产部署、远端 SSH、HTTPS/DNS/ACME 和 `odacm.cn` 实机验收尚未执行。 -下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 \ No newline at end of file +下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 + +## 本轮进度(2026-09-29 19:30) + +按总体验收口径仍为 **P0-03 完成待复审**。 + +- `[x]` DNS 账户项目归属已加入配置、接口和管理页面。 +- `[x]` DNS 凭据使用和项目归属修改已加入实时项目权限校验。 +- `[x]` 无权限修改配置的拒绝回归测试已补齐,确认原配置不被改变。 +- `[x]` 后端专项测试、静态检查、前端测试和生产构建通过。 +- `[~]` P0-07 其他任务/证书/部署权限链继续开发。 +- `[!]` 三数据库、浏览器、远端服务器和生产部署验收仍未开始。 diff --git a/doc/基础整改任务规格.md b/doc/基础整改任务规格.md index c412f51..9967600 100644 --- a/doc/基础整改任务规格.md +++ b/doc/基础整改任务规格.md @@ -275,6 +275,17 @@ P0-06 与 P0-07 均维持 `[~]`,六阶段中的隔离、生产和最终验收 下一步:继续补齐任务与证书/部署权限链,完成开发阶段后再统一运行三库、浏览器和远端生产流程测试。 +## 本轮规格落地状态(2026-09-29 19:30) + +总体验收仍保持 **P0-03 完成待复审**。 + +- `[x]` DNS 配置资源具有明确项目归属,旧配置无归属时归入默认项目。 +- `[x]` DNS 凭据读取和使用前按实时账户状态、项目成员关系及 `dns.credential.use` 判权。 +- `[x]` DNS 项目归属变更按 `dns.manage` 判权,拒绝路径不读取凭据、不执行外部 DNS 操作、不保存新配置。 +- `[x]` DNS 管理页面展示项目归属,账号标识继续脱敏。 +- `[~]` 续期、证书导入/部署、任务执行/重试和其他资源写入权限规格仍在开发落地。 +- `[!]` PostgreSQL/MySQL、浏览器、远端 SSH、HTTPS/DNS/ACME 和生产验收证据尚未形成。 + > ???????2026-09-29 18:38???????? **P0-03 ?????**?P0-07 ?????????????????????????????????????? HTTP ?????????????SSH?DNS?????????????????????????????????? @@ -303,4 +314,4 @@ P0-06 与 P0-07 均维持 `[~]`,六阶段中的隔离、生产和最终验收 - `[~]` DNS 账户项目归属与使用权限、续期任务及其他任务/资源写入权限仍在开发。 - `[!]` PostgreSQL/MySQL 矩阵、浏览器验收、Linux/Windows 生产部署、远端 SSH、HTTPS/DNS/ACME 和 `odacm.cn` 实机验收尚未执行。 -下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 \ No newline at end of file +下一步继续开发 DNS 账户及任务相关权限链,开发阶段结束后统一执行生产构建、部署和验收流程。 diff --git a/frontend/src/views/DNSAccounts/DNSAccounts.css b/frontend/src/views/DNSAccounts/DNSAccounts.css index 55fb662..ccc3fa5 100644 --- a/frontend/src/views/DNSAccounts/DNSAccounts.css +++ b/frontend/src/views/DNSAccounts/DNSAccounts.css @@ -132,6 +132,6 @@ select:focus-visible, } .dns-accounts-table { - min-width: 640px; + min-width: 760px; } } diff --git a/frontend/src/views/DNSAccounts/DNSAccounts.js b/frontend/src/views/DNSAccounts/DNSAccounts.js index 7186ca8..6cee439 100644 --- a/frontend/src/views/DNSAccounts/DNSAccounts.js +++ b/frontend/src/views/DNSAccounts/DNSAccounts.js @@ -6,6 +6,11 @@ export function dnsVerificationLabel(item) { return item.verification_state === "verified" ? "已验证" : "待验证"; } +export function dnsProjectLabel(item) { + const projectID = typeof item?.project_id === "string" ? item.project_id.trim() : ""; + return projectID === "" || projectID === "default" ? "默认项目" : projectID; +} + export function useDNSAccounts() { const accounts = ref([]); const loading = ref(false); diff --git a/frontend/src/views/DNSAccounts/DNSAccounts.vue b/frontend/src/views/DNSAccounts/DNSAccounts.vue index ad3c718..82004f6 100644 --- a/frontend/src/views/DNSAccounts/DNSAccounts.vue +++ b/frontend/src/views/DNSAccounts/DNSAccounts.vue @@ -1,6 +1,6 @@