1"use strict";(globalThis.webpackChunkcontrolzero_docs||=[]).push([[2108],{2888(e,r,o){o.r(r),o.d(r,{assets:()=>l,contentTitle:()=>d,default:()=>h,frontMatter:()=>i,metadata:()=>n,toc:()=>c});const n=JSON.parse('{"id":"changelog/2026-05-11-policy-fixes","title":"Policy enforcement fixes (May 2026)","description":"Two customer-reported issues where a published policy did not take effect have been fixed and shipped to all SDKs and the dashboard.","source":"@site/docs/changelog/2026-05-11-policy-fixes.md","sourceDirName":"changelog","slug":"/changelog/2026-05-11-policy-fixes","permalink":"/docs/changelog/2026-05-11-policy-fixes","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"title":"Policy enforcement fixes (May 2026)"},"sidebar":"docsSidebar","previous":{"title":"Changelog","permalink":"/docs/changelog"},"next":{"title":"Product Consolidation","permalink":"/docs/changelog/product-consolidation"}}');var s=o(74848),t=o(28453);const i={sidebar_position:2,title:"Policy enforcement fixes (May 2026)"},d="Policy enforcement fixes, 2026-05-11",l={},c=[{value:"What was wrong",id:"what-was-wrong",level:2},{value:"Republished policies did not refresh attached projects",id:"republished-policies-did-not-refresh-attached-projects",level:3},{value:"Hosted-mode SDKs returned deny on every call when a rule used resources:["*"]",id:"hosted-mode-sdks-returned-deny-on-every-call-when-a-rule-used-resources",level:3},{value:"What you need to do",id:"what-you-need-to-do",level:2},{value:"Related",id:"related",level:2}];function a(e){const r={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(r.header,{children:(0,s.jsx)(r.h1,{id:"policy-enforcement-fixes-2026-05-11",children:"Policy enforcement fixes, 2026-05-11"})}),"\n",(0,s.jsx)(r.p,{children:"Two customer-reported issues where a published policy did not take effect have been fixed and shipped to all SDKs and the dashboard."}),"\n",(0,s.jsx)(r.h2,{id:"what-was-wrong",children:"What was wrong"}),"\n",(0,s.jsx)(r.h3,{id:"republished-policies-did-not-refresh-attached-projects",children:"Republished policies did not refresh attached projects"}),"\n",(0,s.jsx)(r.p,{children:"When a policy in the Policy Library was edited and a new version was published, projects that already had the previous version attached did not always pick up the new version. The dashboard showed the new version as published, but the SDK kept enforcing the prior version."}),"\n",(0,s.jsx)(r.p,{children:"This is now fixed: republishing a policy rolls forward every project that already had it attached. Projects without the policy attached are unaffected."}),"\n",(0,s.jsx)(r.h3,{id:"hosted-mode-sdks-returned-deny-on-every-call-when-a-rule-used-resources",children:'Hosted-mode SDKs returned deny on every call when a rule used resources:["*"]'}),"\n",(0,s.jsxs)(r.p,{children:["Rules in the published bundle that listed ",(0,s.jsx)(r.code,{children:'resources: ["*"]'})," (the universal wildcard) were silently skipped on calls that did not pass ",(0,s.jsx)(r.code,{children:"context.resource"}),". Result: every ",(0,s.jsx)(r.code,{children:"guard()"})," call returned ",(0,s.jsx)(r.code,{children:"deny"})," with ",(0,s.jsx)(r.code,{children:"reason_code=NO_RULE_MATCH"}),", regardless of what the policy said."]}),"\n",(0,s.jsxs)(r.p,{children:["This is now fixed: ",(0,s.jsx)(r.code,{children:'resources: ["*"]'})," matches every call, with or without a caller-supplied resource. Non-wildcard resource patterns (for example, ",(0,s.jsx)(r.code,{children:'["table/orders"]'}),") still require the caller to set a matching ",(0,s.jsx)(r.code,{children:"context.resource"}),", so narrow rules stay narrow."]}),"\n",(0,s.jsx)(r.h2,{id:"what-you-need-to-do",children:"What you need to do"}),"\n",(0,s.jsxs)(r.ul,{children:["\n",(0,s.jsxs)(r.li,{children:[(0,s.jsx)(r.strong,{children:"Python SDK users"}),": upgrade to ",(0,s.jsx)(r.code,{children:"controlzero"})," 1.4.6 or later via ",(0,s.jsx)(r.code,{children:"pip install -U controlzero"}),"."]}),"\n",(0,s.jsxs)(r.li,{children:[(0,s.jsx)(r.strong,{children:"Node SDK users"}),": configure the Control Zero registry once by adding ",(0,s.jsx)(r.code,{children:"@controlzero:registry=https://npm.controlzero.ai"})," to your ",(0,s.jsx)(r.code,{children:".npmrc"})," (or running ",(0,s.jsx)(r.code,{children:"npm config set @controlzero:registry https://npm.controlzero.ai"}),"); it applies to npm install and npx for the whole @controlzero scope. Then upgrade to ",(0,s.jsx)(r.code,{children:"@controlzero/sdk"})," 1.8.2 or later via ",(0,s.jsx)(r.code,{children:"npm install @controlzero/sdk@latest"}),"."]}),"\n",(0,s.jsxs)(r.li,{children:[(0,s.jsx)(r.strong,{children:"Dashboard republish flow"}),": no action needed; the fix is live on the SaaS platform."]}),"\n"]}),"\n",(0,s.jsx)(r.p,{children:"If you were affected and policies still appear stuck after upgrading the SDK, force a refresh:"}),"\n",(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{className:"language-python",children:"cz.refresh() # Python\n"})}),"\n",(0,s.jsx)(r.pre,{children:(0,s.jsx)(r.code,{className:"language-typescript",children:"await cz.refreshPolicies(); // Node\n"})}),"\n",(0,s.jsxs)(r.p,{children:["If a fresh refresh still shows the wrong behavior, see ",(0,s.jsx)(r.a,{href:"/docs/guides/troubleshooting-deny-deny",children:"Troubleshooting deny-on-every-call"}),"."]}),"\n",(0,s.jsx)(r.h2,{id:"related",children:"Related"}),"\n",(0,s.jsxs)(r.ul,{children:["\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"/docs/guides/troubleshooting-deny-deny",children:"Troubleshooting deny-on-every-call"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"/docs/guides/debugging-integration",children:"Debugging your integration"})}),"\n",(0,s.jsx)(r.li,{children:(0,s.jsx)(r.a,{href:"/docs/concepts/enforcement-behavior",children:"Enforcement Behavior"})}),"\n"]})]})}function h(e={}){const{wrapper:r}={...(0,t.R)(),...e.components};return r?(0,s.jsx)(r,{...e,children:(0,s.jsx)(a,{...e})}):a(e)}},28453(e,r,o){o.d(r,{R:()=>i,x:()=>d});var n=o(96540);const s={},t=n.createContext(s);function i(e){const r=n.useContext(t);return n.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function d(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:i(e.components),n.createElement(t.Provider,{value:r},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.