Repository navigation
fix(app-shell,auth,i18n): the organization form says requiring MFA needs two-factor on, and the enrollment screen names a two-factor-off deployment in the user's language (#30295) - #30369
Merged
Conversation
…he user's language Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
…n accepted save says who must enroll Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
…usal Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG Known red, not this PR's · Lint UI (job 127131167427). Same signature as main-red anchor #30367: |
…zation MFA notice console.organizationMfa.needsTwoFactor quotes the Setup switch it names („Mehrstufige Authentifizierung verlangen“), one more correctly paired span: 103 -> 104 in both pinned counts. Claude-Session: https://claude.ai/code/session_01Utp6CYeUM6wKr7VK5xLHXn Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG 维护者速读
席位核对 — ACCEPT · head 8031747
|
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Bill · project thread
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG
维护者速读
Two-factor enable failed (404)。status、code,原 message 不变),新增 3 个翻译键、十个语言包齐全。没有服务端、元数据或权限改动。回滚即撤本 PR。ui/packages/app-shell/src/console/organizationMfaNotices.ts(何时提示、何时不提示);ui/packages/app-shell/src/console/AppContent.tsx的组织表单挂接与保存成功 toast;RemediationOverlay.tsx的enrollRefusalMessage。pnpm --dir ui exec vitest run packages/app-shell/src/console/__tests__/organizationMfaNotices-30295.test.tsx packages/app-shell/src/console/__tests__/RemediationOverlay.enrollUnavailable-30295.test.tsx,预期 11/11 通过。Fixes #30295
Clause-②: yes (widening)
Metadata-protocol: none
What changes
The three Wanted items of the card, on a zh-CN console against a local
app-showcasebackend carrying #30293:GET /api/v1/auth/configanswersfeatures.twoFactor: false, thesys_organizationedit form (the Console's global record-form modal inAppContent.tsx; the object declares noeditMode: 'page') shows a notice as the dialog's description: Require Multi-Factor Auth needs two-factor, a save with it ticked is refused, and how to turn two-factor on (Require multi-factor authentication in Setup → Authentication, which applies to every organization, orOS_AUTH_TWO_FACTOR=true). The notice is judged byorganizationMfaFormNoticein the neworganizationMfaNotices.ts: only that object, only a form that offersrequire_mfa, and only when the flag readsfalse(an unread config says nothing).400 VALIDATION_FAILEDtext on therequire_mfafield, not a generic failure (thefields[]entry fix(plugin-auth)!: an organization cannot require MFA while two-factor enrollment is off (#30201) #30293 sends). See Acceptance notes for its language.require_mfaon for a row that stored it off adds a line to the saved toast (the existingnoticeslot oftoastRecordSave): every member without an authenticator app must set one up, and is blocked from data once the MFA grace period ends (7 days unless changed in Setup → Authentication), counted from their first use after the change; members already enrolled are not affected. The stored value comes from onefindOnewhen the organization form opens (useStoredRequireMfa, keyed on the object, the record id and the open flag); a create counts as off, an unread value as off, a row already on says nothing.enrollTotp/verifyTotpin@object-ui/authnow reject with the HTTPstatusand the server'scodebeside the unchanged message (twoFactorEnrollError). The authenticator step ofRemediationOverlayreads404(the/two-factor/*endpoints are mounted only while two-factor is on) asauth.remediation.mfa.unavailable, saying enrollment is off and that an administrator turns it on in Setup → Authentication, andINVALID_PASSWORDas the password screen's existing sentence. Any other refusal keeps the server's message.auth.remediation.mfa.unavailable,console.organizationMfa.needsTwoFactor,console.organizationMfa.nowRequired..changeset/30295-org-mfa-notice-and-enroll-refusal.md(patchfor@object-ui/app-shell,@object-ui/auth,@object-ui/i18n).Why
#30293 made the server refuse
require_mfa = truewhile two-factor is off and stopped the gate from holding anyone it cannot enroll. Nothing in the console said so: the form offered the checkbox with the object's help ("When true, every member … must enroll"), the administrator learned the dependency only from the refusal, a successful save said nothing about who is now held or when, and a member sent to enroll on a deployment without two-factor readTwo-factor enable failed (404).Tests
ui/packages/app-shell/src/console/__tests__/organizationMfaNotices-30295.test.tsx(new, 7): the notice's three conditions (two-factor off; on or unread; another object or no field), the saved line's (turned on; already on, left off, another object; unread counts as off), and the stored-value hook (one read per open edit, create is off, closed form or another object reads nothing, a failed read stays unread).ui/packages/app-shell/src/console/__tests__/RemediationOverlay.enrollUnavailable-30295.test.tsx(new, 4): zh and en 404 sentences (and the Englishfailed (404)gone), zhINVALID_PASSWORD, and a control where a 429 keeps the server's message. The other RemediationOverlay files each carry their ownuseAuthmock and no shared harness exists, so this is its own file.ui/packages/auth/src/__tests__/createAuthClient.test.ts: a new top-level describe in the existing harness, three pins through the real better-auth client and a mocked fetch (404 on enable and on verify carriesstatus, a wrong password carriescodeandstatus, messages unchanged).scripts/ablation-replace.mjs, each restore proven blob == HEAD (these suites import source, so no build sits between mutation and run). A, C and D ran onc4ec9241; B ran onc4ec9241and again on9fb2f487, after its pins moved into the harness file (3 red of 37):statusno longer copied onto the error: 3 red (expected undefined to be 404).expected 'console.organizationMfa.needsTwoFactor' to be undefined).expected 'console.organizationMfa.nowRequired' to be undefined).Acceptance notes
OS_AUTH_TWO_FACTORandauth.mfa_required). It is server-authored text; this PR adds the localized notice above it rather than replacing it. Localizing that refusal belongs to the server's message.auth.mfa_grace_period_days(/api/v1/auth/configdoes not publish it,@objectstack/clienthas no settings read, and the settings page is admin-only), so the saved line says "7 days unless changed in Setup → Authentication". The server knows the configured value; a write notice from the server would carry it.RecordFormPagewould show neither line for an organization;sys_organizationdeclares noeditMode: 'page', so the modal is the only host a user reaches today.packages/platform-objects, server metadata) still says only "When true, every member … must enroll"; this PR leaves it alone (out of this card's file surface).sys_organization.require_mfa, every member of one organization) and the setting is 要求多因素认证 (auth.mfa_required, every organization, and it turns two-factor on). The notice names both in each pack's own spelling.Verification
Suites, type-check and gates ran on
30cfab99(main9afcd6a6, which carries #30293, plus this branch); the final headfc268ce2mergesmainagain (noui/file moved) and re-ran the scoped suites.Browser check (zh-CN, local app-showcase backend, Playwright)
The screenshots are in the project files (
ui-seat3/30295/); no image host is reachable from this session. What each shows:before-enroll.png/after-enroll.png: the MFA overlay raised by answering one data read with the server's403 MFA_REQUIRED(two-factor is off, so the real gate no longer holds anyone), then the password step against the real backend, whosePOST /two-factor/enableanswered 404. Before:Two-factor enable failed (404). After: 此部署未开启双重验证,暂时无法绑定身份验证器。请联系管理员在“设置 → 认证”中开启后再试。before-form.png/after-form.png: the 编辑组织 dialog with two-factor off. Before: no notice. After: the notice under the title.before-saved.png/after-saved.png: the box ticked and 更新 pressed with two-factor off. Both show the server's refusal on the field; the row staysrequire_mfa: false(read back over REST).after-2fa-saved.png: backend restarted withOS_AUTH_TWO_FACTOR=true, the box ticked and saved: the toast reads 组织“Default Organization”已更新 plus 本组织所有尚未绑定身份验证器的成员现在都必须绑定。每位成员从此次变更后第一次使用起开始计算 MFA 宽限期(默认 7 天,可在“设置 → 认证”中修改)… The row readsrequire_mfa: true.Suites and type-check (under scripts/pm/os-verify-lock.sh)
pnpm --dir ui exec vitest runover the three changed test files plus the files importing the changed modules' behaviour (the five otherRemediationOverlay.*files,changePassword-code-27869, and the i18n parity filesall-locales-key-parity,authRemediation-locale-parity,en-zh-key-parity,console-namespace-3546): 14 files, 158 tests passed (the auth pins then moved intocreateAuthClient.test.ts: 37/37).pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/auth --filter=@object-ui/i18n --concurrency=2: Tasks 70 successful, 70 total. VERDICT command-exit 0.Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon30cfab99: 35 derived, each run with its exit code captured before any pipe: 35 exit 0 (check:type-check-debtunder the lock).node scripts/check-sdui-manifest.mjsexit 0.--ranover the record (COMMAND :: exit N): 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN, exit 0 ("a DERIVED zero — all 35 recorded an exit code and none of them is 3"). The merge ofmain(fc268ce2) brought no file underui/or.changeset/; the derivation on the merged head is byte-identical, and the scoped suites re-ran green there (13 files, 158 tests).pnpm lintis CI's run.Human Minimum
packages/specholds no runtime logic (packages/specnot touched).pnpm lintis CI's run.main, one pull request.packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
Generated by Claude Code