Skip to content

fix(config): reconcile config-policy ownership with the Assignments tab - #2107

Merged
ToddHebebrand merged 1 commit into
mainfrom
ToddHebebrand/config-policy-partner-assignment
Jul 1, 2026
Merged

fix(config): reconcile config-policy ownership with the Assignments tab#2107
ToddHebebrand merged 1 commit into
mainfrom
ToddHebebrand/config-policy-partner-assignment

Conversation

@ToddHebebrand

Copy link
Copy Markdown
Collaborator

Problem

The create-page "Apply to" owner picker (#2064) collided with the Assignments tab. Both surfaced a "partner-wide / all orgs" choice, but they control two independent axes:

  • Ownershipconfiguration_policies.org_id XOR partner_id (DB CHECK), set once at create. The eligibility universe.
  • Assignmentconfig_policy_assignments rows, what resolveEffectiveConfig actually reads.

Three concrete breakages:

  1. The create picker applied nothing — a partner-owned policy was created with zero assignments, so it resolved to no devices until the user separately found the Assignments tab.
  2. The Assignments tab was blind to ownership — got orgId=null for partner-owned policies (breaking target lookups) and offered all 5 levels regardless.
  3. Org-owned + partner-level validated and saved but silently applied only to the one owning org (footgun).

Fix — ownership is the single source of truth; the tab is ownership-aware

  • crud.ts — creating a partner-owned policy auto-seeds the matching partner-level assignment, so "All organizations" applies immediately. The two inserts aren't transactional, so a non-unique seed failure rolls back the orphan and surfaces the error (logged with the policy id) rather than leaving a committed-but-unassigned policy; unique violations are tolerated.
  • configurationPolicy.tsvalidateAssignmentTarget now rejects org-owned policies at the Partner level with an actionable message.
  • AssignmentsTab.tsx — partner-owned shows a banner + a re-assign card only when unassigned; org-owned drops the Partner-Wide level option. Guards against a null orgId in the site/group target fetch.
  • ConfigPolicyDetailPage.tsxPolicyDetail carries partnerId (orgId now nullable), passed to the tab.
  • ConfigPolicyCreatePage.tsx — relabeled "Apply to" → "Scope"; clarified helper text.
  • aiToolsConfigPolicy.ts — documented the partner-level constraint in the tool description.

Tests

  • New configurationPolicy.validateAssignment.test.ts — ownership gating (all four combinations), asserting the illegal combos short-circuit before any DB query.
  • crud.test.ts — partner auto-assign, org-owned does-not-auto-assign, unique-swallow (still 201), non-unique-rollback (500 + deleteConfigPolicy called).
  • AssignmentsTab.test.tsx — partner banner/no-picker, re-assign POST body (level + priority + role/OS filters, no targetId), card hiding, org-owned level list excludes partner, org-owned assign POST includes targetId.

Verification

astro check 0 errors · API tsc clean · eslint clean (both apps) · API 94 config-policy tests + web 14 component tests green.

This is a follow-up to #2064. Reviewed via the pr-review-toolkit (code / tests / silent-failure / comments / types); all surfaced findings were addressed in this branch.

🤖 Generated with Claude Code

The create-page "Apply to" owner picker (#2064) collided with the
Assignments tab: both surfaced a "partner-wide / all orgs" choice for two
different axes — ownership (org_id XOR partner_id, set at create) and
assignment (what resolveEffectiveConfig actually reads). The picker applied
nothing (zero assignments seeded), the tab was blind to ownership, and the
org-owned + partner-level combo was a silent no-op.

Make ownership the single source of truth and the tab ownership-aware:

- crud.ts: creating a partner-owned policy auto-seeds the matching
  partner-level assignment so "All organizations" applies immediately.
  Non-unique seed failure rolls back the orphan and surfaces the error
  (logged with the policy id); unique violations are tolerated.
- configurationPolicy.ts: validateAssignmentTarget now rejects org-owned
  policies at the partner level (was a silent no-op footgun).
- AssignmentsTab.tsx: partner-owned shows a banner + re-assign card only
  when unassigned; org-owned drops the Partner-Wide level option. Guards
  against a null orgId in the site/group target fetch.
- ConfigPolicyDetailPage.tsx: PolicyDetail carries partnerId (orgId now
  nullable); passed to the tab.
- ConfigPolicyCreatePage.tsx: "Apply to" -> "Scope"; clarified helper text.
- aiToolsConfigPolicy.ts: documented the partner-level constraint.

Tests: validateAssignmentTarget ownership gating, auto-assign
swallow/rollback paths, org-owned + partner re-assign POST bodies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying breeze with  Cloudflare Pages  Cloudflare Pages

Latest commit: 49284b0
Status: ✅  Deploy successful!
Preview URL: https://23fdf8fd.breeze-9te.pages.dev
Branch Preview URL: https://toddhebebrand-config-policy.breeze-9te.pages.dev

View logs

@ToddHebebrand
ToddHebebrand merged commit 7b2cbb1 into main Jul 1, 2026
40 checks passed
@ToddHebebrand
ToddHebebrand deleted the ToddHebebrand/config-policy-partner-assignment branch July 1, 2026 04:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant