diff --git a/.claude/commands b/.claude/commands index 95b417d3..315ad0e7 160000 --- a/.claude/commands +++ b/.claude/commands @@ -1 +1 @@ -Subproject commit 95b417d3c70f7ec4cdf372e9432382f428ff71f7 +Subproject commit 315ad0e73645e212ec0b38a61a15bf4c73a707f6 diff --git a/internal b/internal index 148e99f2..7cb78f47 160000 --- a/internal +++ b/internal @@ -1 +1 @@ -Subproject commit 148e99f2e69bab60f39213a280f10b0f355ed4d9 +Subproject commit 7cb78f47ead7a9f36a61c5d43acb2d0fdbc9d1e6 diff --git a/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx b/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx index 764b94bf..327fd6d6 100644 --- a/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx +++ b/src/Web/autopilot-monitor-web/app/analyze-rules/page.tsx @@ -112,6 +112,9 @@ export default function AnalyzeRulesPage() { // A read-only Global Reader — and an own-tenant admin viewing a FOREIGN tenant (cross-tenant override) — // is read-only. Backend also enforces (rules write is TenantAdminOrGA, cross-tenant blocked for non-GA). const isReadOnly = !(user?.isGlobalAdmin || (user?.isTenantAdmin && !isGlobalOverride)); + // Community submissions are TenantAdminOrGA on the own tenant; only a global-scope override reads them through + // the operator list. Everyone else (Operator, Viewer) gets a hint instead of a 403 on the list call. + const submissionsAdminOnly = isReadOnly && !isGlobalOverride; // Cross-tenant write routing: in a Global Admin override the JWT-scoped rules/analyze/{id} route // resolves the tenant from the caller's token and would silently upsert into the GA's OWN tenant @@ -610,15 +613,17 @@ export default function AnalyzeRulesPage() { ) : (
{/* Community contribution: submit own custom rules for the shared pool; the list shows their status. */} - setShowSubmitModal(true)} /> - + setShowSubmitModal(true)} adminOnly={submissionsAdminOnly} /> + {!submissionsAdminOnly && ( + + )} {/* Summary Stats */}
diff --git a/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx b/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx index b8f7d2f6..179f0d32 100644 --- a/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx +++ b/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx @@ -83,6 +83,9 @@ export default function GatherRulesPage() { // A read-only Global Reader — and an own-tenant admin viewing a FOREIGN tenant (cross-tenant override) — // is read-only. Backend also enforces (rules write is TenantAdminOrGA, cross-tenant blocked for non-GA). const isReadOnly = !(user?.isGlobalAdmin || (user?.isTenantAdmin && !isGlobalOverride)); + // Community submissions are TenantAdminOrGA on the own tenant; only a global-scope override reads them through + // the operator list. Everyone else (Operator, Viewer) gets a hint instead of a 403 on the list call. + const submissionsAdminOnly = isReadOnly && !isGlobalOverride; // Cross-tenant write routing: in a Global Admin override the JWT-scoped rules/gather/{id} route // resolves the tenant from the caller's token and would silently upsert into the GA's OWN tenant @@ -444,15 +447,17 @@ export default function GatherRulesPage() { )} {/* Community contribution: submit own custom rules for the shared pool; the list shows their status. */} - setShowSubmitModal(true)} /> - + setShowSubmitModal(true)} adminOnly={submissionsAdminOnly} /> + {!submissionsAdminOnly && ( + + )} {/* Summary Stats */}
diff --git a/src/Web/autopilot-monitor-web/components/rules/CommunityContributionBox.tsx b/src/Web/autopilot-monitor-web/components/rules/CommunityContributionBox.tsx index 9d8b19d7..5f67944c 100644 --- a/src/Web/autopilot-monitor-web/components/rules/CommunityContributionBox.tsx +++ b/src/Web/autopilot-monitor-web/components/rules/CommunityContributionBox.tsx @@ -6,10 +6,12 @@ import { DOCS_PATHS } from "@/lib/docsPaths"; interface CommunityContributionBoxProps { /** Undefined hides the button (read-only roles, no custom rules yet). */ onContribute?: () => void; + /** The caller's role cannot contribute at all (contributing is tenant-admin only): say so instead of just hiding the button. */ + adminOnly?: boolean; } /** The community call-to-action on the rule pages: contribute a rule here, report bugs on GitHub. */ -export function CommunityContributionBox({ onContribute }: CommunityContributionBoxProps) { +export function CommunityContributionBox({ onContribute, adminOnly }: CommunityContributionBoxProps) { return (
@@ -22,6 +24,9 @@ export function CommunityContributionBox({ onContribute }: CommunityContribution open a GitHub issue . + {adminOnly && ( + Only tenant admins can contribute rules and follow the tenant's submissions — ask an admin of your tenant to submit it. + )}

{onContribute && (