diff --git a/.github/workflows/tag-ci.yml b/.github/workflows/tag-ci.yml index 8834101..47b5e7b 100644 --- a/.github/workflows/tag-ci.yml +++ b/.github/workflows/tag-ci.yml @@ -53,7 +53,7 @@ jobs: deploy: needs: validate - if: startsWith(github.ref, 'refs/tags/v') + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') uses: FastR-D/FastDeploy/.github/workflows/deploy.yml@9a2c51dcd63f47a0e6c8f6bb07bd22ea589abbd2 with: app: fastcas diff --git a/internal/httpapi/auth_ui.go b/internal/httpapi/auth_ui.go index 89d45dc..aa30dd3 100644 --- a/internal/httpapi/auth_ui.go +++ b/internal/httpapi/auth_ui.go @@ -10,8 +10,9 @@ import ( ) type authAssets struct { - Script string - Styles []string + Bootstrap string + Script string + Styles []string } // Read the Vite manifest at startup. Authentication pages consume the same @@ -76,6 +77,9 @@ func readAuthAssets(dir string) (authAssets, error) { return result, err } result.Script, err = asset(manifest["src/auth.ts"].File, ".js") + if err == nil { + result.Bootstrap, err = asset("assets/theme-init.js", ".js") + } if err == nil && len(result.Styles) == 0 { return result, fmt.Errorf("console auth styles missing") } @@ -85,7 +89,7 @@ func readAuthAssets(dir string) (authAssets, error) { func authTemplate(name, body string) *template.Template { return template.Must(template.New(name).Parse(` {{define "auth-head"}}{{.Title}} · FastCAS -{{range .Assets.Styles}}{{end}}{{if .Assets.Script}}{{end}}{{end}} +{{if .Assets.Bootstrap}}{{end}}{{range .Assets.Styles}}{{end}}{{if .Assets.Script}}{{end}}{{end}} {{define "auth-toolbar"}}
FASTR-D / IDENTITY{{if .Assets.Script}}{{end}}
{{end}} {{define "auth-footer"}}

FastCAS · 可选认证,独立账号
各项目的账号、内容和权限由项目独立管理。

{{end}} ` + body)) diff --git a/internal/httpapi/console_test.go b/internal/httpapi/console_test.go index 8b88132..f5c6bc9 100644 --- a/internal/httpapi/console_test.go +++ b/internal/httpapi/console_test.go @@ -59,7 +59,7 @@ func TestConsoleAuthManifestValidation(t *testing.T) { t.Fatal(err) } } - for _, path := range []string{"index.html", "assets/auth.js", "assets/foundation.js", "assets/auth.css", "assets/foundation.css"} { + for _, path := range []string{"index.html", "assets/theme-init.js", "assets/auth.js", "assets/foundation.js", "assets/auth.css", "assets/foundation.css"} { if err := os.WriteFile(filepath.Join(dir, path), []byte("fixture"), 0600); err != nil { t.Fatal(err) } diff --git a/web/FASTUI.md b/web/FASTUI.md new file mode 100644 index 0000000..0e58ea2 --- /dev/null +++ b/web/FASTUI.md @@ -0,0 +1,9 @@ +# FastUI console + +`@fastrd/ui-react` 与直接使用的 `@fastrd/ui-foundation` 精确固定消费官方 npm `0.1.2`,锁文件保留制品完整性。安装后 `pnpm run build` 将 CSS/JS 打入本地控制台输出,运行时不访问包下载站点。 + +保留 main 的桌面 Shell、Security、Admin、Audit、应用配置与安全确认对话框。基础表单实际使用 npm `TextField` / `TextArea` / `Select` / `Button`,加载和成功/错误反馈使用 `Loading` / `Alert`;宿主 CSS 只维护布局、密度及语义 token,没有复制浅深色板。 + +`src/theme-init.ts` 通过 Vite 编译为同源、parser-blocking 的 `assets/theme-init.js`,在页面内容前创建唯一 foundation controller。Shell 与原生 Auth/Device 的主题选择器复用 `window.fastCASColorMode`;保留 main 的 `fastcas.color-mode` key,默认为 system。切换主题不重挂载 React 树,不清除表单草稿/焦点。没有再次运行包的自动初始化脚本。 + +Auth/Device 页面继续使用 main 的 Vite manifest CSS 与原生 Go 表单校验,包括禁用 JavaScript 的登录;业务请求、一次性凭证、CSRF、近期 MFA、角色权限及确认取消行为由原有业务组件和服务端管理。 diff --git a/web/README.md b/web/README.md index f3ab252..24c1816 100644 --- a/web/README.md +++ b/web/README.md @@ -15,7 +15,7 @@ pnpm run build 审计支持操作名称、执行者 ID、目标 ID 的精确匹配和开始/结束时间组合筛选;分页保留已应用条件,重置与刷新从首屏重新查询。输入时间使用浏览器时区,发送时转为 UTC;开始时间包含、结束时间排除。后台迁移 `015_audit_filters.sql` 为检索与分页增加索引。 -主题支持浅色、深色和跟随系统,使用 foundation 的颜色模式控制器;仅 `fastcas.color-mode` 偏好写入 localStorage。一次性凭证、客户端密钥、恢复码和认证器密钥只保存在当前页面内存中;离开对应页面会卸载组件并清空显示,管理页之间不会复用密钥。查询参数中的邀请/恢复凭证在 React 发出请求前从地址栏清除。凭证须通过可信渠道私密交付。 +主题支持浅色、深色和跟随系统,使用 foundation 的颜色模式控制器;仅 `fastcas.color-mode` 偏好写入 localStorage。同源经典脚本 `assets/theme-init.js` 在 head 阻塞初始化首屏主题,Shell 和原生认证页复用同一 controller,系统或跨标签主题变化保持表单 DOM、草稿和焦点。一次性凭证、客户端密钥、恢复码和认证器密钥只保存在当前页面内存中;离开对应页面会卸载组件并清空显示,管理页之间不会复用密钥。查询参数中的邀请/恢复凭证在 React 发出请求前从地址栏清除。凭证须通过可信渠道私密交付。 公开表单入口为 `/console/?flow=invite`、`?flow=recovery`、`?flow=mfa_reset`,支持手动凭证或 `token` 查询参数。切换流程清空原凭证与密码。成功后提示独立登录,各项目账号不会自动创建或合并。 @@ -29,7 +29,7 @@ FASTCAS_BROWSER_CONTRACT=1 \ go test ./internal/httpapi -run '^TestConsoleAgainstRealBrowser$' -count=1 -v ``` -该契约使用隔离 schema、真实 HTTP 和构建产物,覆盖注册、登录、改密、恢复、MFA、分页、审计筛选、应用配置保存/失败重试/取消、焦点恢复、密钥轮换与清除、服务生命周期和设备确认。也验证禁用 JavaScript 时的原生登录、桌面深浅主题和主题持久化;截图保存在 `.local/ui-verification/`,只含隔离测试数据。`TestAuditFiltersAndPagination` 验证服务端时间边界、组合筛选、分页、非法条件与权限;`TestConsoleAuthManifestValidation` 验证产物完整性与路径约束。 +该契约使用隔离 schema、真实 HTTP 和构建产物,覆盖注册、登录、改密、恢复、MFA、分页、审计筛选、应用配置保存/失败重试/取消、焦点恢复、密钥轮换与清除、服务生命周期和设备确认。也验证禁用 JavaScript 时的原生登录、桌面深浅主题和主题持久化;延迟应用模块检查 console/login 的保存偏好、系统默认、无效值和存储拒绝首屏,以及首屏 controller 同一性和安全表单跨主题保持。截图和 `integration-results.json` 保存在 `.local/ui-verification/`,只含隔离测试数据。`TestAuditFiltersAndPagination` 验证服务端时间边界、组合筛选、分页、非法条件与权限;`TestConsoleAuthManifestValidation` 验证产物完整性与路径约束。 这轮完成控制台基础重构与审计检索,不代表全部商业化规划完成。真实域名部署、监控告警、备份恢复和跨项目容量/SLO 验收仍需按项目交付清单推进。 diff --git a/web/src/Guest.tsx b/web/src/Guest.tsx index 81e9fa2..9e895d9 100644 --- a/web/src/Guest.tsx +++ b/web/src/Guest.tsx @@ -199,7 +199,7 @@ export function Guest({ initial }: { initial: InitialCredential }) { )} {error && {error}} -