cloak-api / copilot /impact.py
n1th1sh's picture
Upload 35 files
375880c verified
Raw History Blame Contribute Delete
5.81 kB
"""What the new policy will actually change, given how CLOAK combines policies.
Endpoint (modules/pii/resolvePolicy.ts, modules/agent/routes.ts):
- AI prompt part (action, detection rules, AI sites, upload/paste, test mode): a group with its own
active policies uses only those; the org-wide prompt rules stop applying to it
- device and browser controls (agentControl, the agent's extensionControl): folded across org-wide AND
group policies, any "on" wins, so org-wide controls keep applying to every group
- within the prompt set in force, ONE action applies to every rule: the strictest one wins
Channels (pickChannelPolicy): one active policy per channel applies, the newest; it does not merge.
Email: one active email policy per provider (Gmail, Outlook / Microsoft 365).
"""
from __future__ import annotations
from .model import Draft
from .platform import catalog
from .platform.context import PlatformContext
PROVIDER_LABEL = {'google': 'Gmail', 'm365': 'Outlook / Microsoft 365'}
def assess(d: Draft, ctx: PlatformContext) -> None:
body = d.policyBody
if body is None:
return
d.issue('CREATED_INACTIVE', 'info', 'The policy is proposed switched off. Review it, then turn it on.')
if not ctx.policiesKnown:
return
if d.policyType == 'endpoint':
_endpoint(d, body, ctx)
elif d.policyType == 'email':
provider = body['channels']['email'].get('provider') or 'google'
active = [p for p in ctx.policies if p.type == 'email' and (p.provider or 'google') == provider]
if active:
label = PROVIDER_LABEL.get(provider, provider)
d.issue('ONE_ACTIVE_EMAIL_POLICY', 'warning',
f'"{active[0].name}" is the active {label} email policy, and only one per provider can be active. '
f'To use this one, turn that one off first.', policy=active[0].name, provider=provider)
else:
_channel(d, body, ctx)
def _endpoint(d: Draft, body: dict, ctx: PlatformContext) -> None:
rank = catalog.action_rank()
gid = body['groupId']
endpoint = [p for p in ctx.policies if p.type == 'endpoint']
org = [p for p in endpoint if p.groupId == 'default']
own = [p for p in endpoint if p.groupId == gid and gid != 'default']
if gid != 'default':
name = ctx.group(gid).name if ctx.group(gid) else gid
if not own and org:
pl = 'y' if len(org) == 1 else 'ies'
msg = (f'Once this policy is on, AI prompts from {name} are checked only by policies for {name}, so the '
f'AI prompt rules of the org-wide polic{pl} ({", ".join(p.name for p in org[:3])}) stop applying '
f'to {name}.')
if not _has_prompt_part(body):
msg += f' This policy checks no prompts itself, so AI prompts from {name} would only be logged.'
msg += (f' Device and browser controls from the org-wide polic{pl} (USB, printing, block lists and '
f'the rest) still apply to {name}.')
d.issue('GROUP_REPLACES_ORG_WIDE', 'warning', msg, group=name, orgWide=[p.name for p in org])
else:
groups = sorted({p.groupId for p in endpoint if p.groupId != 'default'})
if groups and _has_prompt_part(body):
names = [ctx.group(g).name if ctx.group(g) else g for g in groups]
d.issue('ORG_WIDE_SKIPS_GROUPS', 'warning',
f'Groups with their own policies ({", ".join(names)}) keep their own AI prompt rules, so this '
f'policy\'s prompt checks do not reach them. Its device and browser controls apply to them too.',
groups=names)
uses_action = bool(body['extensionControl']['detectionRuleIds'])
if not uses_action:
return
if gid != 'default' and not own:
return # the group's first policy: once on, it is the only one in force for the group
scope = own if gid != 'default' else org
if not scope:
return
new = rank.get(body['action'], 0)
strictest = max(scope, key=lambda p: rank.get(p.action, 0))
if rank.get(strictest.action, 0) > new:
d.issue('STRICTER_ACTION_ACTIVE', 'warning',
f'"{strictest.name}" is already active with "{strictest.action}". One action applies to all rules '
f'and the strictest wins, so this policy will also "{strictest.action}", not "{body["action"]}".',
policy=strictest.name, action=strictest.action)
elif rank.get(strictest.action, 0) < new:
d.issue('ACTION_RAISES_OTHERS', 'warning',
f'One action applies to every rule in force and the strictest wins: once this is on, matches of the '
f'other active policies ({", ".join(p.name for p in scope[:3])}) will also "{body["action"]}".',
action=body['action'])
def _has_prompt_part(body: dict) -> bool:
"""Whether the policy sets anything the group-replaces-org-wide rule applies to."""
return bool(body['extensionControl']['detectionRuleIds']) or body['allowFileUpload'] is False \
or body['allowCodePaste'] is False or body['action'] != 'log'
def _channel(d: Draft, body: dict, ctx: PlatformContext) -> None:
cfg = body['channels'][d.policyType]
mine = set(cfg.get('connectorIds') or [])
for p in ctx.policies:
if p.type != d.policyType:
continue
theirs = set(p.connectorIds)
if not mine or not theirs or mine & theirs:
d.issue('CHANNEL_POLICY_REPLACED', 'warning',
f'"{p.name}" is the active {catalog.TYPE_LABEL[d.policyType]} policy. Only one applies at a time '
f'(the newest), so turning this on replaces it rather than adding to it.', policy=p.name)
return