Download copilot/platform/context.py from Wardline/cloak-api: direct link, hf CLI and curl.
- Browser
- Download file 12.5 kB
-
https://huggingface.co/spaces/Wardline/cloak-api/resolve/main/copilot/platform/context.py
- Command line
-
hf download hf://spaces/Wardline/cloak-api/copilot/platform/context.py
-
curl -L -o context.py https://huggingface.co/spaces/Wardline/cloak-api/resolve/main/copilot/platform/context.py
12.5 kB
| """PlatformContext: what the tenant looks like right now. | |
| The Node proxy builds this from the database on every request (groups, rules, block lists, | |
| connectors, active policies) and the copilot never reads the database itself. Loading is | |
| deliberately forgiving: a malformed entry is dropped, never raised, because a bad context | |
| must degrade answers, not crash the service. | |
| """ | |
| from __future__ import annotations | |
| import re | |
| from dataclasses import dataclass, field | |
| from typing import Any | |
| from . import catalog | |
| CONNECTOR_CHANNELS = ('email', 'slack', 'teams', 'drive', 'chat', 'm365files', 's3', 'gcs', 'azure', 'github') | |
| class Group: | |
| id: str | |
| name: str | |
| class Rule: | |
| id: str | |
| name: str | |
| entities: list[str] | |
| keywords: list[str] | |
| fileTypes: list[str] | |
| severity: str | |
| builtin: bool | |
| class BlockList: | |
| id: str | |
| name: str | |
| kind: str # 'web' | 'app' | |
| entries: list[str] | |
| builtin: bool | |
| class WebCategory: | |
| name: str # as the admin named it in Web Filtering; policies store this name | |
| domains: int # how many sites it holds (0 until it has been filled) | |
| class Connector: | |
| id: str | |
| name: str | |
| hasAdminToken: bool = False # slack: needed for the delete action | |
| remediationEnabled: bool = False # email: needed for the remediate action | |
| provider: str = '' # email: 'google' | 'm365' | |
| class Detector: | |
| """An admin-made regex detector (Policies -> Detectors). Rules reference it by label.""" | |
| label: str # CUSTOMER_ID: what a detection rule stores in `entities` | |
| name: str # "Customer ID": what the admin calls it | |
| enabled: bool | |
| class PolicySummary: | |
| id: str | |
| name: str | |
| type: str | |
| groupId: str | |
| action: str | |
| connectorIds: list[str] | |
| provider: str = '' # email policies: 'google' | 'm365' (one saved before the split is Gmail) | |
| active: bool = True | |
| # Device and browser switches that are on ("agentControl.blockPrint"), for unblock requests. | |
| controls: set[str] = field(default_factory=set) | |
| # Sites and apps it blocks by name, and the block lists it uses: for "unblock chatgpt". | |
| blockedDomains: set[str] = field(default_factory=set) | |
| blockedApps: set[str] = field(default_factory=set) | |
| webLists: list[str] = field(default_factory=list) | |
| appLists: list[str] = field(default_factory=list) | |
| class PlatformContext: | |
| groups: list[Group] = field(default_factory=list) | |
| rules: list[Rule] = field(default_factory=list) | |
| blockLists: list[BlockList] = field(default_factory=list) | |
| connectors: dict[str, list[Connector]] = field(default_factory=dict) | |
| # Active policies only. The copilot uses them to explain how a new one will combine. | |
| policies: list[PolicySummary] = field(default_factory=list) | |
| # Every policy, on or off: what a request may add to instead of creating another one. | |
| allPolicies: list[PolicySummary] = field(default_factory=list) | |
| # Names of every policy, active or not, so a new one never repeats a name. | |
| policyNames: set[str] = field(default_factory=set) | |
| # True when the caller told us which connectors exist. When it did not, we cannot | |
| # say "no connector", so connector checks are skipped rather than guessed. | |
| connectorsKnown: bool = False | |
| policiesKnown: bool = False | |
| # Web Filtering categories (tenant-defined). Unknown when the caller sent none. | |
| webCategories: list[WebCategory] = field(default_factory=list) | |
| webCategoriesKnown: bool = False | |
| # True when the caller sent each policy's switches (PolicySummary.controls). | |
| controlsKnown: bool = False | |
| # True when the caller sent what each policy blocks (sites, apps, lists). | |
| blocksKnown: bool = False | |
| # The tenant's own regex detectors, and the built-in ones an admin switched off. | |
| detectors: list[Detector] = field(default_factory=list) | |
| disabledDetectors: set[str] = field(default_factory=set) | |
| def entity_keys(self) -> frozenset[str]: | |
| """Every key a rule may hold for this tenant: the platform's plus its custom detectors.""" | |
| if not self.detectors: | |
| return catalog.entity_keys() | |
| return catalog.entity_keys() | {x.label for x in self.detectors} | |
| def entity_label(self, key: str) -> str: | |
| own = next((x for x in self.detectors if x.label == key), None) | |
| return own.name if own else catalog.entity_label(key) | |
| def detector_off(self, key: str) -> bool: | |
| """Switched off on the Detectors page: a rule may list it, but it finds nothing.""" | |
| own = next((x for x in self.detectors if x.label == key), None) | |
| return (not own.enabled) if own else key in self.disabledDetectors | |
| def policy(self, pid: str) -> PolicySummary | None: | |
| return next((p for p in self.allPolicies if p.id == pid), None) | |
| def group(self, gid: str) -> Group | None: | |
| return next((g for g in self.groups if g.id == gid), None) | |
| def rule(self, rid: str) -> Rule | None: | |
| return next((r for r in self.rules if r.id == rid), None) | |
| def block_list(self, lid: str) -> BlockList | None: | |
| return next((b for b in self.blockLists if b.id == lid), None) | |
| def connectors_for(self, channel: str) -> list[Connector]: | |
| return self.connectors.get(channel, []) | |
| def web_category(self, name: str) -> WebCategory | None: | |
| return next((w for w in self.webCategories if w.name.lower() == name.lower()), None) | |
| _LABEL = re.compile(r'^[A-Z][A-Z0-9_]{1,63}$') | |
| _CONTROL = re.compile(r'^(agentControl|extensionControl)\.[A-Za-z][A-Za-z0-9]{1,63}$') | |
| def _s(v: Any, limit: int = 300) -> str: | |
| return v.strip()[:limit] if isinstance(v, str) else '' | |
| def _strs(v: Any, limit: int = 500) -> list[str]: | |
| if not isinstance(v, list): | |
| return [] | |
| out: list[str] = [] | |
| for x in v[:limit]: | |
| s = _s(x) | |
| if s and s not in out: | |
| out.append(s) | |
| return out | |
| def _b(v: Any) -> bool: | |
| return v is True | |
| def _dicts(v: Any, limit: int = 2000) -> list[dict]: | |
| return [x for x in v[:limit] if isinstance(x, dict)] if isinstance(v, list) else [] | |
| def load_context(raw: Any) -> PlatformContext: | |
| """Build a context from untrusted JSON. Never raises.""" | |
| raw = raw if isinstance(raw, dict) else {} | |
| ctx = PlatformContext() | |
| for g in _dicts(raw.get('groups')): | |
| gid, name = _s(g.get('id'), 64), _s(g.get('name'), 120) | |
| if gid and name and gid != 'default' and not ctx.group(gid): | |
| ctx.groups.append(Group(gid, name)) | |
| seen: set[str] = set() | |
| for r in _dicts(raw.get('detectionRules')): | |
| rid, name = _s(r.get('id'), 64), _s(r.get('name'), 200) | |
| if not rid or not name or rid in seen: | |
| continue | |
| sev = _s(r.get('severity')).upper() | |
| ctx.rules.append(Rule( | |
| id=rid, name=name, | |
| entities=[e.upper() for e in _strs(r.get('entities'))], | |
| keywords=[k.lower() for k in _strs(r.get('keywords'))], | |
| fileTypes=[f.lower() for f in _strs(r.get('fileTypes'))], | |
| severity=sev if sev in ('LOW', 'MEDIUM', 'HIGH') else 'HIGH', | |
| builtin=_b(r.get('builtin')) or rid.startswith('builtin_'), | |
| )) | |
| seen.add(rid) | |
| # The server seeds the presets on every boot, so they always exist. Add any the caller left out. | |
| for r in catalog.builtin_rules(): | |
| if r['id'] not in seen: | |
| ctx.rules.append(Rule(r['id'], r['name'], list(r['entities']), list(r['keywords']), | |
| list(r['fileTypes']), r['severity'], True)) | |
| seen = set() | |
| for b in _dicts(raw.get('blockLists')): | |
| lid, name, kind = _s(b.get('id'), 64), _s(b.get('name'), 200), _s(b.get('kind')) | |
| if not lid or not name or kind not in ('web', 'app') or lid in seen: | |
| continue | |
| ctx.blockLists.append(BlockList(lid, name, kind, [e.lower() for e in _strs(b.get('entries'), 5000)], | |
| _b(b.get('builtin')) or lid.startswith('builtin_'))) | |
| seen.add(lid) | |
| for b in catalog.builtin_block_lists(): | |
| if b['id'] not in seen: | |
| ctx.blockLists.append(BlockList(b['id'], b['name'], b['kind'], list(b['entries']), True)) | |
| if isinstance(raw.get('webCategories'), list): | |
| ctx.webCategoriesKnown = True | |
| for w in _dicts(raw.get('webCategories')): | |
| name = _s(w.get('name'), 120) | |
| if name and not ctx.web_category(name): | |
| n = w.get('domains') | |
| ctx.webCategories.append(WebCategory(name, n if isinstance(n, int) and n >= 0 else 0)) | |
| conns = raw.get('connectors') | |
| if isinstance(conns, dict): | |
| ctx.connectorsKnown = True | |
| for ch in CONNECTOR_CHANNELS: | |
| for c in _dicts(conns.get(ch)): | |
| cid = _s(c.get('id'), 64) | |
| if not cid: | |
| continue | |
| ctx.connectors.setdefault(ch, []).append(Connector( | |
| id=cid, name=_s(c.get('name'), 200) or _s(c.get('teamName'), 200) or cid, | |
| hasAdminToken=_b(c.get('hasAdminToken')), | |
| remediationEnabled=_b(c.get('remediationEnabled')), | |
| provider=_s(c.get('provider'), 16) if ch == 'email' else '', | |
| )) | |
| builtin_keys = catalog.entity_keys() | |
| for x in _dicts(raw.get('detectors'), 500): | |
| label, name = _s(x.get('label'), 64).upper(), _s(x.get('name'), 120) | |
| # A custom detector may not shadow a built-in key: the platform refuses that too. | |
| if _LABEL.match(label) and label not in builtin_keys and not any(d.label == label for d in ctx.detectors): | |
| ctx.detectors.append(Detector(label, name or label.replace('_', ' ').title(), x.get('enabled') is not False)) | |
| ctx.disabledDetectors = {k.upper() for k in _strs(raw.get('disabledDetectors'))} | |
| if isinstance(raw.get('policies'), list): | |
| ctx.policiesKnown = True | |
| for p in _dicts(raw.get('policies')): | |
| pid = _s(p.get('id'), 64) | |
| if _s(p.get('name'), 200): | |
| ctx.policyNames.add(_s(p.get('name'), 200).lower()) | |
| if not pid or any(x.id == pid for x in ctx.allPolicies): | |
| continue | |
| ptype = _s(p.get('type')) or _type_of(p) | |
| if ptype not in catalog.POLICY_TYPES: | |
| continue | |
| summary = PolicySummary( | |
| id=pid, name=_s(p.get('name'), 200) or pid, type=ptype, | |
| groupId=_s(p.get('groupId'), 64) or 'default', | |
| action=_s(p.get('action')) or 'warn', | |
| connectorIds=_strs(p.get('connectorIds')), | |
| provider=_email_provider(p) if ptype == 'email' else '', | |
| active=p.get('active') is not False, | |
| controls={c for c in _strs(p.get('controls'), 200) if _CONTROL.match(c)}, | |
| ) | |
| if isinstance(p.get('controls'), list): | |
| ctx.controlsKnown = True | |
| if isinstance(p.get('blockedDomains'), list): | |
| ctx.blocksKnown = True | |
| summary.blockedDomains = {x.lower() for x in _strs(p.get('blockedDomains'), 500)} | |
| summary.blockedApps = {x.lower() for x in _strs(p.get('blockedApplications'), 500)} | |
| summary.webLists = _strs(p.get('webBlockListIds'), 100) | |
| summary.appLists = _strs(p.get('appBlockListIds'), 100) | |
| ctx.allPolicies.append(summary) | |
| if summary.active: | |
| ctx.policies.append(summary) | |
| return ctx | |
| def _email_provider(p: dict) -> str: | |
| """As the email form's emailProviderOf(): 'm365' only when saved so, otherwise the Gmail policy.""" | |
| if p.get('provider') == 'm365': | |
| return 'm365' | |
| ch = p.get('channels') | |
| em = ch.get('email') if isinstance(ch, dict) else None | |
| return 'm365' if isinstance(em, dict) and em.get('provider') == 'm365' else 'google' | |
| def _type_of(p: dict) -> str: | |
| """A full policy row (as GET /api/admin/policies returns it) has no type field: derive it.""" | |
| ch = p.get('channels') | |
| unknown = False | |
| if isinstance(ch, dict): | |
| for k, v in ch.items(): | |
| if isinstance(v, dict) and v.get('enabled') is True: | |
| if k in catalog.CHANNEL_TYPES: | |
| return k | |
| unknown = True | |
| # A channel the copilot does not know yet (a connector added to the platform later): | |
| # leave the policy out rather than mistake it for an endpoint policy. | |
| return '' if unknown else 'endpoint' | |