Uh oh!
There was an error while loading. Please reload this page.
fix(example-crm): grant crm_opportunity_line_item in crm_sales_user, matching its master crm_opportunity (#8164) - #8228
Merged
Conversation
…matching its master crm_opportunity (#8164) crm_opportunity_line_item is a master-detail CHILD of crm_opportunity (sharingModel: 'controlled_by_parent', inlineEdit: 'grid' on the Opportunity form), but crm_sales_user granted object-level CRUD on 5 CRM objects and never the line item. Record-level access always follows the master (ADR-0055), but object-level CRUD is a SEPARATE gate the platform never derives -- every role-bound (non-admin) user got a silent 403 the moment they tried to add/edit a product line on an Opportunity they otherwise fully own. The platform's own build-time lint (security-master-detail-ungranted) already flagged this independently. Grant shape matches the master exactly: { allowRead: true, allowCreate: true, allowEdit: true, allowDelete: false }. Adds one purely-additive test asserting the grant exists and equals the master's -- there was zero prior coverage of crm_sales_user's grant contents. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PEVB6w7D7uCszR9Mw1BL73
…ant (ADR-0090 D6) Companion to the sales-positions.ts fix (#8164): the ADR-0090 D6 access-matrix snapshot gate fails the build on any undocumented capability drift, and granting crm_opportunity_line_item is exactly such a drift. Regenerated with `objectstack build --update-access-matrix` per the gate's own instructions -- the diff is the review artifact: crm_sales_user gains create/read/edit on crm_opportunity_line_item, recorded with the object's OWN sharingModel (controlled_by_parent), not the master's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PEVB6w7D7uCszR9Mw1BL73
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-zhuang
marked this pull request as ready for review
August 12, 2026 21:39
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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.
Fixes#8164
What
crm_opportunity_line_itemis a master-detail child ofcrm_opportunity(
sharingModel: 'controlled_by_parent',inlineEdit: 'grid'on theOpportunity form) but was not granted object-level CRUD in any app-crm
permission set. Record-level access always follows the master (ADR-0055),
but object-level CRUD is a separate gate the platform never derives —
so every role-bound (non-admin) user, including the three positions this
app ships to demonstrate selling, got a silent 403 the moment they tried
to add/edit a product line on an Opportunity they otherwise fully own. The
platform's own build-time lint (
security-master-detail-ungranted)already flagged this independently.
Added
crm_opportunity_line_itemtocrm_sales_user'sobjectsmap inexamples/app-crm/src/security/sales-positions.ts, with the same grantshape as its master
crm_opportunity:{ allowRead: true, allowCreate: true, allowEdit: true, allowDelete: false }.Why this shape
The lint rule's own name (
security-master-detail-ungranted) and theruntime's ADR-0055 derivation both say the line item's access is meant to
follow its master. Matching the parent's grant exactly (not inventing an
independent CRUD policy) keeps that relationship visible in the metadata:
the same users who can already create/read/edit an Opportunity can now
also create/read/edit its line items, with delete withheld on both (line
items are removed by editing the Opportunity's grid, not by a standalone
delete permission — consistent with the master).
Also regenerated
examples/app-crm/access-matrix.json(the ADR-0090 D6capability snapshot
objectstack buildchecks on every compile) viaobjectstack build --update-access-matrix— never hand-edited. The buildfails on undocumented capability drift, and granting the line item is
exactly such a drift; the new entry records the object's own
sharingModel(controlled_by_parent), not the master'spublic_read_write.Tests
examples/app-crm/test/smoke.test.tsgained one new,purely-additive test —
grants crm_opportunity_line_item in crm_sales_user, matching its master crm_opportunity (#8164)— asserting the child's grant exists and equalsthe master's. No existing test was touched or re-spelled; there was zero
prior coverage of
crm_sales_user's grant contents before this PR.Confirmed the test discriminates: red on the ablated (pre-fix) code
(
expected undefined to be defined), green on the fix.objectstack verify --app examples/app-crm/objectstack.config.ts --rls:every position persona's
probeBlockedcount dropped from 1 (the lineitem — the sole gap [finding] The CRM example binds none of its 3 declared positions to
crm_sales_user, so a user holding one is 403 on every CRM object #8060 deliberately left open) to 0(
memberVisible: 6, notproven— expected, since the object iseffectively
controlled_by_parenton apublic_read_writemaster, sothe object gate opening makes it visible by design), with zero RLS
holes. Aggregate across the 3 position personas:
probeBlocked3 → 0,memberVisible15 → 18,holes0 → 0. Full before/after readout in thedev report.
security-master-detail-ungrantedno longer fires forcrm_opportunity_line_item(confirmed present on the ablated build,absent on the fix).
sales-positions.tsandaccess-matrix.jsontogether (reverting onlythe grant would itself trigger an access-matrix drift failure),
re-ran
verify --rlsand the build lint, confirmed both returnedexactly to the pre-fix baseline, then restored from the committed
branch (no
git stash).Not in scope
packages/plugins/plugin-security/**— this PR stays entirely insideexamples/app-crm/**, per the card's scope.Generated by Claude Code