Skip to content

fix: align dashboard policy scopes - #6092

Open
vishalg0wda wants to merge 5 commits into
mainfrom
vishal/ais-678-policy-scope-dashboard
Open

fix: align dashboard policy scopes#6092
vishalg0wda wants to merge 5 commits into
mainfrom
vishal/ais-678-policy-scope-dashboard

Conversation

@vishalg0wda

@vishalg0wda vishalg0wda commented Sep 4, 2026

Copy link
Copy Markdown
Member

https://linear.app/speakeasy/issue/AIS-678

Summary

Align policy scope persistence and display so the dashboard matches effective scanner behavior.

  • Save onboarding message type choices as per-category detection scopes.
  • Resolve Applies To from category overrides or recommendations, then intersect with legacy narrowing.
  • Show Nothing in scope when a policy has an empty effective scope.

Motivation

The wizard wrote a legacy hard prefilter while the editor used per-category scopes, permanently narrowing new policies and making the list contradictory.

  • Keep the backfill for policies with legacy scope on AIS-678.

Summary by cubic

Fixes AIS-678 by making the Policy Center’s “Applies To” value match the scanner’s effective scope instead of reading only legacy messageTypes. With the risk-recommended-scopes flag enabled, onboarding saves selections as per-category detectionScopes; legacy mode remains unchanged and prevents empty scopes.

  • Applies To unions category scopes, intersects legacy messageTypes and CEL narrowing, and shows “Nothing in scope” or “Custom scope” when needed.
  • Onboarding preserves existing category scopes and keeps at least one message type selected when legacy mode is active.
  • No migration is included; existing legacy policies, including Platform MCP policies, continue to work through the narrowing intersection.

Written for commit c5068b8. Summary will update on new commits.

Review in cubic

@vishalg0wda vishalg0wda added the bug Something isn't working label Sep 4, 2026
@vishalg0wda
vishalg0wda requested review from a team as code owners September 4, 2026 16:43
@vishalg0wda vishalg0wda added the bug Something isn't working label Sep 4, 2026
@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

AIS-678

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c5068b8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
dashboard Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Running ultrareview automatically — This PR changes how policy scopes are computed and saved, introducing new CEL encoding/decoding logic and shifting the API payload from messageTypes to detectionScopes. A subtle bug here could cause policies to be misconfigured, leading to undetected security issues or over-blocking, and the.... I'll post findings when complete.

@vishalg0wda

Copy link
Copy Markdown
Member Author

Demo

Policy Center effective scopes

What it shows:

  1. Applies To resolves category scopes into message types.
  2. An empty effective scope renders as Nothing in scope.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ultrareview completed in 13m 39s

All reported issues were addressed across 5 files

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread client/dashboard/src/pages/security/policy-scope.ts
Comment thread client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx Outdated
Comment thread client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx Outdated
Comment thread client/dashboard/src/pages/security/policy-scope.ts
Comment thread client/dashboard/src/pages/security/policy-scope.ts
Comment thread client/dashboard/src/pages/security/policy-scope.ts Outdated
Comment thread client/dashboard/src/pages/security/PolicyCenter.tsx
Comment thread client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx Outdated
Comment thread client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread client/dashboard/src/pages/security/policy-scope.ts
Comment thread client/dashboard/src/pages/security/PolicyCenter.tsx
Comment thread client/dashboard/src/pages/security/PolicyCenter.tsx
Comment thread client/dashboard/src/pages/security/policy-scope.test.ts Outdated
@vishalg0wda

Copy link
Copy Markdown
Member Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@vishalg0wda I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx Outdated
Comment thread client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="client/dashboard/src/pages/security/PolicyCenter.tsx">

<violation number="1" location="client/dashboard/src/pages/security/PolicyCenter.tsx:964">
P2: When a scope contains non-decodable CEL and also has decodable message kinds, the Applies To column shows the kinds plus `+ custom CEL` instead of `Custom scope`. Use the required `Custom scope` summary whenever `scope.custom` is true.</violation>
</file>

<file name="client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx">

<violation number="1" location="client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx:359">
P1: When the flag is enabled, the wizard hides the legacy narrowing that the scanner still enforces. According to linked Linear issue AIS-678, legacy `messageTypes` remains a hard prefilter until migration; intersect it with the category scope, including when no category override exists, before populating these controls.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

if (recommendedScopesEnabled) {
serverMessageTypes =
effectiveScope === null || effectiveScope.custom
? new Set(next[cat].messageTypes)

@cubic-dev-ai cubic-dev-ai Bot Sep 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When the flag is enabled, the wizard hides the legacy narrowing that the scanner still enforces. According to linked Linear issue AIS-678, legacy messageTypes remains a hard prefilter until migration; intersect it with the category scope, including when no category override exists, before populating these controls.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx, line 356:

<comment>When the flag is enabled, the wizard hides the legacy narrowing that the scanner still enforces. According to linked Linear issue AIS-678, legacy `messageTypes` remains a hard prefilter until migration; intersect it with the category scope, including when no category override exists, before populating these controls.</comment>

<file context>
@@ -327,13 +343,26 @@ export function ConfigurePoliciesStep({
+        if (recommendedScopesEnabled) {
+          serverMessageTypes =
+            effectiveScope === null || effectiveScope.custom
+              ? new Set(next[cat].messageTypes)
+              : new Set(effectiveScope.kinds);
+        } else if (existing.messageTypes?.length) {
</file context>
Fix with cubic

} else {
summary = labels.join(", ");
}
if (scope.custom && labels.length > 0) summary += " + custom CEL";

@cubic-dev-ai cubic-dev-ai Bot Sep 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a scope contains non-decodable CEL and also has decodable message kinds, the Applies To column shows the kinds plus + custom CEL instead of Custom scope. Use the required Custom scope summary whenever scope.custom is true.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At client/dashboard/src/pages/security/PolicyCenter.tsx, line 964:

<comment>When a scope contains non-decodable CEL and also has decodable message kinds, the Applies To column shows the kinds plus `+ custom CEL` instead of `Custom scope`. Use the required `Custom scope` summary whenever `scope.custom` is true.</comment>

<file context>
@@ -895,31 +919,67 @@ function PolicyCenterContent() {
+        } else {
+          summary = labels.join(", ");
+        }
+        if (scope.custom && labels.length > 0) summary += " + custom CEL";
+
+        let tooltipSummary = labels.join(", ");
</file context>
Suggested change
if (scope.custom && labels.length > 0) summary += " + custom CEL";
if (scope.custom) summary = "Custom scope";
Fix with cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="client/dashboard/src/pages/security/PolicyCenter.tsx">

<violation number="1" location="client/dashboard/src/pages/security/PolicyCenter.tsx:922">
P2: When the category query fails after a prior successful fetch, `useQuery` keeps cached `categoriesData` while setting `categoriesError`, so this guard is bypassed and Applies To renders a scope from failed/stale definitions. Include `categoriesError` in the guard so the display shows `Scope unavailable` on every category-query error.

(Based on your team's feedback about holding Applies To when category definitions are loading or erroring.)</violation>
</file>

<file name="client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx">

<violation number="1" location="client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx:306">
P1: When the rollout flag is loading or unavailable, editing an existing scoped policy clears its `detectionScopes` because every non-enabled status selects the legacy persistence path. Hold persistence until the flag resolves, or distinguish resolved disabled from unavailable states instead of treating all non-enabled statuses as legacy mode.</violation>
</file>

<file name="client/dashboard/src/pages/security/policy-scope.ts">

<violation number="1" location="client/dashboard/src/pages/security/policy-scope.ts:136">
P2: When `scopeInclude` is a valid noncanonical `kind in` list, this fallback treats it as allowing prompt attachments. Preserve the legacy list parser so `Applies To` excludes `prompt_attachment` whenever the list does not contain it.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

disabledRules: existing.disabledRules,
customRuleIds: existing.customRuleIds ?? [],
messageTypes: [...nextCfg.messageTypes],
...(recommendedScopesEnabled

@cubic-dev-ai cubic-dev-ai Bot Sep 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When the rollout flag is loading or unavailable, editing an existing scoped policy clears its detectionScopes because every non-enabled status selects the legacy persistence path. Hold persistence until the flag resolves, or distinguish resolved disabled from unavailable states instead of treating all non-enabled statuses as legacy mode.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At client/dashboard/src/pages/setup/components/steps/configure-policies-step.tsx, line 306:

<comment>When the rollout flag is loading or unavailable, editing an existing scoped policy clears its `detectionScopes` because every non-enabled status selects the legacy persistence path. Hold persistence until the flag resolves, or distinguish resolved disabled from unavailable states instead of treating all non-enabled statuses as legacy mode.</comment>

<file context>
@@ -297,14 +303,21 @@ export function ConfigurePoliciesStep({
-              ...kindScopeForMessageTypes([...nextCfg.messageTypes]),
-            },
-          ),
+          ...(recommendedScopesEnabled
+            ? {
+                messageTypes: [],
</file context>
Fix with cubic

typeSet.size === ALL_POLICY_MESSAGE_TYPES.length ||
hasOnlyToolCallMessageTypes(typeSet)
) {
if (recommendedScopesEnabled && !categoriesData) {

@cubic-dev-ai cubic-dev-ai Bot Sep 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When the category query fails after a prior successful fetch, useQuery keeps cached categoriesData while setting categoriesError, so this guard is bypassed and Applies To renders a scope from failed/stale definitions. Include categoriesError in the guard so the display shows Scope unavailable on every category-query error.

(Based on your team's feedback about holding Applies To when category definitions are loading or erroring.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At client/dashboard/src/pages/security/PolicyCenter.tsx, line 922:

<comment>When the category query fails after a prior successful fetch, `useQuery` keeps cached `categoriesData` while setting `categoriesError`, so this guard is bypassed and Applies To renders a scope from failed/stale definitions. Include `categoriesError` in the guard so the display shows `Scope unavailable` on every category-query error.

(Based on your team's feedback about holding Applies To when category definitions are loading or erroring.) </comment>

<file context>
@@ -915,6 +919,16 @@ function PolicyCenterContent() {
       header: "Applies To",
       width: "2.1fr",
       render: (row) => {
+        if (recommendedScopesEnabled && !categoriesData) {
+          return (
+            <span className="text-muted-foreground text-sm">
</file context>
Suggested change
if (recommendedScopesEnabled && !categoriesData) {
if (recommendedScopesEnabled && (categoriesError || !categoriesData)) {
Fix with cubic


function promptAttachmentScopeMatch(cel: string): boolean | null {
const decoded = decodeEffectiveKindScope(cel);
return decoded ? decoded.includes("prompt_attachment") : null;

@cubic-dev-ai cubic-dev-ai Bot Sep 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When scopeInclude is a valid noncanonical kind in list, this fallback treats it as allowing prompt attachments. Preserve the legacy list parser so Applies To excludes prompt_attachment whenever the list does not contain it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At client/dashboard/src/pages/security/policy-scope.ts, line 136:

<comment>When `scopeInclude` is a valid noncanonical `kind in` list, this fallback treats it as allowing prompt attachments. Preserve the legacy list parser so `Applies To` excludes `prompt_attachment` whenever the list does not contain it.</comment>

<file context>
@@ -112,34 +126,14 @@ export function decodeKindScope(cel: string): PolicyMessageType[] | null {
-  return null;
+function promptAttachmentScopeMatch(cel: string): boolean | null {
+  const decoded = decodeEffectiveKindScope(cel);
+  return decoded ? decoded.includes("prompt_attachment") : null;
 }
 
</file context>
Suggested change
return decoded ? decoded.includes("prompt_attachment") : null;
if (decoded) return decoded.includes("prompt_attachment");
if (cel.startsWith("kind in ")) {
try {
const parsed: unknown = JSON.parse(cel.slice("kind in ".length));
if (
!Array.isArray(parsed) ||
!parsed.every((value) => typeof value === "string")
) {
return null;
}
return parsed.includes("prompt_attachment");
} catch {
return null;
}
}
return null;
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant