Repository navigation
fix(app-crm): hide the Pipeline nav entry from a member who cannot read opportunities - #27805
Merged
Merged
Conversation
Claude-Session: https://claude.ai/code/session_01Utp6CY2n1JmZZKrHgtp9jC Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CY2n1JmZZKrHgtp9jC Co-authored-by: Claude <noreply@anthropic.com>
…ad opportunities Per ruling 6512784198 (letter G): a visible predicate on the nav entry instead of a declared capability; the capability, its grant and the dashboard's requiredPermissions are reverted. Claude-Session: https://claude.ai/code/session_01Utp6CXo8iLQ8vn2fXj6wxp Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXo8iLQ8vn2fXj6wxp Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC 席位核对ACCEPT · head
Generated by Claude Code |
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.
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Requested by Bill · project thread
Fixes #27735
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6512784198
维护者速读
current_user.can('crm_opportunity', 'read'),读不到商机的成员看不到它;仪表盘本身、权限集和能力都不动。examples/app-crm/src/apps/crm.app.ts(一行)、examples/app-crm/test/pipeline-audience.test.ts。pnpm --filter @objectstack/example-crm exec vitest run test/pipeline-audience.test.ts,预期 2 个用例全绿。What changes
Per ruling 6512784198 (letter G, which amends the mechanism of #27491 ruling 6508997538 item 5):
examples/app-crm/src/apps/crm.app.ts:nav_pipeline_dashboardgainsvisible: "current_user.can('crm_opportunity', 'read')". Nothing else on the entry changes.opportunity_metrics, the dataset every Pipeline widget reads, is bound tocrm_opportunity.crm.view_pipelinedeclaration, no stackcapabilities, nosystemPermissionsoncrm_sales_user, and norequiredPermissionsonpipeline_dashboardor its nav entry. The branch diff againstmainis the two files listed here.visiblehides and refuses nothing (ADR-0066 D4). The refusal stays the dataset query's 403 for a caller who cannot readcrm_opportunity, unchanged. The server's meta read gate does not judgevisible, so the seeded administrator's reads of the dashboard (the dogfood's managed-install lock control) are untouched, and the package stays installable unmanaged.Acceptance (as amended by the ruling): a member who cannot read
crm_opportunitysees no Pipeline entry in the CRM sidebar; a sales user and the seeded administrator see it as today; a direct link for the refused member shows the #27491 no-access panel (PR #27777), not a blank.Tests
examples/app-crm/test/pipeline-audience.test.ts(new, 2 cases), read off the parsed stack:visibleof the formcurrent_user.can(OBJECT, 'read')(the stack parse normalises the authored string to{ dialect: 'cel', source });objectof the dataset that everypipeline_dashboardwidget reads, derived from the definitions, not hard-coded.Ablation:
scripts/ablation-replace.mjsreplacingcrm_opportunitywithcrm_accountin the predicate (anchor hit 1) turns the second case red (expected [ 'crm_opportunity' ] to deeply equal [ 'crm_account' ]), restored to the HEAD blob withgit diff HEADempty.Acceptance notes
current_user.can(ui/packages/app-shell, objectui#4421). The example has no renderer harness; the pins cover the predicate's shape and its object.@objectstack/example-crmisprivate: true; labelledskip-changeset.87e10674) measured why a declared capability does not fit here:install-local-unmanaged-mode.dogfood.test.tswent 11 failed / 9 passed (422UNMANAGED_INSTALL_UNCOPYABLEon the stack'scapabilities, and 403audience-permissionfor the seeded administrator), against 20/20 at the merge-base. Recorded in the ruling.Verification
Local, at
a1cd6d8d(after mergingorigin/mainonce more):pnpm --filter @objectstack/example-crm test: exit 0, Test Files 7 passed (7), Tests 48 passed (48);typecheckexit 0 (lock VERDICT command-exit 0).pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/install-local-unmanaged-mode.dogfood.test.ts(closure built first): exit 0, Test Files 1 passed (1), Tests 20 passed (20). At the first revision87e10674the same file was 11 failed / 9 passed.node scripts/pm/dispatch-gates.mjs --ran: 39 derived, 38 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, exit 3 PREREQUISITE NOT MET: needs every package's dist; CI's). Three families first answered from a mid-build tree and were re-run after the build settled:check:dts-closure(exit 1 naming@objectstack/runtime/service-automationwhile the dogfood closure was rebuilding, thendriver-odata, new onmain, unlinked untilpnpm install) exit 0;check:i18n-coverageexit 0 ("OK (14 config(s), 527 baselined untranslated string(s), none new)");check:type-check-debtexit 0 ("0 raw tsc error(s) total, none above its recorded number"). The diff touches no package, so none of these read it beyond the example.node scripts/check-sdui-manifest.mjs: exit 0.Derived gate families, exit codes (final readings)
Generated by Claude Code