jes 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. jes/__init__.py +61 -0
  2. jes/_engine/__init__.py +6 -0
  3. jes/_engine/authority.py +135 -0
  4. jes/_engine/core.py +1152 -0
  5. jes/_engine/limits.py +220 -0
  6. jes/_engine/merge.py +84 -0
  7. jes/_engine/plan.py +797 -0
  8. jes/_engine/restore.py +105 -0
  9. jes/_engine/run_async.py +273 -0
  10. jes/_engine/run_sync.py +253 -0
  11. jes/_engine/sensitive.py +262 -0
  12. jes/_engine/uri.py +117 -0
  13. jes/_env.py +90 -0
  14. jes/backends/__init__.py +269 -0
  15. jes/backends/_codec.py +454 -0
  16. jes/backends/_http.py +170 -0
  17. jes/backends/_profiles.py +202 -0
  18. jes/backends/_tokens.py +66 -0
  19. jes/backends/litellm_judge.py +468 -0
  20. jes/backends/llama_guard.py +673 -0
  21. jes/backends/prompt_guard.py +437 -0
  22. jes/backends/system_one.py +682 -0
  23. jes/errors.py +57 -0
  24. jes/policies/UNICODE-LICENSE.txt +6 -0
  25. jes/policies/__init__.py +69 -0
  26. jes/policies/_candidates.py +275 -0
  27. jes/policies/_confusables_data.py +6721 -0
  28. jes/policies/_exploit_terms.py +27 -0
  29. jes/policies/_fold.py +156 -0
  30. jes/policies/_protocols.py +192 -0
  31. jes/policies/_ucd_data.py +2225 -0
  32. jes/policies/_unicode.py +72 -0
  33. jes/policies/defaults.py +33 -0
  34. jes/policies/judgments.py +373 -0
  35. jes/policies/pii.py +315 -0
  36. jes/policies/prompts.py +138 -0
  37. jes/policies/secrets.py +191 -0
  38. jes/policies/transforms.py +548 -0
  39. jes/py.typed +1 -0
  40. jes/questions.py +235 -0
  41. jes/recipes/__init__.py +34 -0
  42. jes/recipes/judgments.py +322 -0
  43. jes/recipes/prompts.py +49 -0
  44. jes/recipes/transforms.py +272 -0
  45. jes/redactions.py +337 -0
  46. jes/testing.py +428 -0
  47. jes/types.py +260 -0
  48. jes-1.0.0.dist-info/METADATA +400 -0
  49. jes-1.0.0.dist-info/RECORD +51 -0
  50. jes-1.0.0.dist-info/WHEEL +4 -0
  51. jes-1.0.0.dist-info/licenses/LICENSE +192 -0
jes/__init__.py ADDED
@@ -0,0 +1,61 @@
1
+ """jes public API."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from jes._engine import AsyncGuard, Guard
6
+ from jes.errors import (
7
+ BackendError,
8
+ DeadlineExceeded,
9
+ PolicyError,
10
+ PolicyExecutionError,
11
+ RedactionError,
12
+ )
13
+ from jes.questions import Choice, Score, Threshold, YesNo
14
+ from jes.redactions import Redactions
15
+ from jes.types import (
16
+ Finding,
17
+ FindingLocation,
18
+ History,
19
+ InputResult,
20
+ Message,
21
+ Provenance,
22
+ ScanResult,
23
+ ScoreResult,
24
+ Span,
25
+ State,
26
+ ThresholdProvenance,
27
+ Timings,
28
+ Usage,
29
+ )
30
+
31
+ __version__ = "1.0.0"
32
+
33
+ __all__ = [
34
+ "AsyncGuard",
35
+ "BackendError",
36
+ "Choice",
37
+ "DeadlineExceeded",
38
+ "Finding",
39
+ "FindingLocation",
40
+ "Guard",
41
+ "History",
42
+ "InputResult",
43
+ "Message",
44
+ "PolicyError",
45
+ "PolicyExecutionError",
46
+ "Provenance",
47
+ "RedactionError",
48
+ "Redactions",
49
+ "ScanResult",
50
+ "Score",
51
+ "ScoreResult",
52
+ "Span",
53
+ "State",
54
+ "Threshold",
55
+ "ThresholdProvenance",
56
+ "Timings",
57
+ "Usage",
58
+ "YesNo",
59
+ "__version__",
60
+ ]
61
+
@@ -0,0 +1,6 @@
1
+ """Private engine implementation."""
2
+
3
+ from jes._engine.run_async import AsyncGuard
4
+ from jes._engine.run_sync import Guard
5
+
6
+ __all__ = ["AsyncGuard", "Guard"]
@@ -0,0 +1,135 @@
1
+ """Sanitization stamps and occurrence-based token authority."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import hmac
7
+ import json
8
+ import re
9
+ from collections.abc import Iterable, Sequence
10
+ from dataclasses import replace
11
+
12
+ from jes.redactions import Redactions
13
+ from jes.types import (
14
+ _EMPTY_AUTHORITY,
15
+ Finding,
16
+ SanitizationStamp,
17
+ ScanResult,
18
+ _TokenAuthority,
19
+ _TokenAuthorityManifest,
20
+ )
21
+
22
+ _TOKEN_RE = re.compile(r"\[JES_v[0-9]+_[^\]\r\n]{1,256}\]")
23
+
24
+
25
+ def findings_digest(findings: Sequence[Finding]) -> str:
26
+ payload = [
27
+ {
28
+ "policy": finding.policy,
29
+ "label": finding.label,
30
+ "action": finding.action,
31
+ "question": finding.question,
32
+ "locations": [
33
+ {
34
+ "target": location.target,
35
+ "start": location.span.start,
36
+ "end": location.span.end,
37
+ "index": location.index,
38
+ "role": location.role,
39
+ "item": location.item_ordinal,
40
+ }
41
+ for location in finding.locations
42
+ ],
43
+ }
44
+ for finding in findings
45
+ ]
46
+ return hashlib.sha256(
47
+ json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()
48
+ ).hexdigest()
49
+
50
+
51
+ def authority_digest(entries: Sequence[_TokenAuthority]) -> str:
52
+ payload = [
53
+ {
54
+ "token": entry.token,
55
+ "start": entry.span.start,
56
+ "end": entry.span.end,
57
+ "origin": entry.origin_result,
58
+ "reusable": entry.reusable,
59
+ }
60
+ for entry in entries
61
+ ]
62
+ return hashlib.sha256(
63
+ json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()
64
+ ).hexdigest()
65
+
66
+
67
+ def make_manifest(entries: Iterable[_TokenAuthority]) -> _TokenAuthorityManifest:
68
+ frozen = tuple(entries)
69
+ return _TokenAuthorityManifest(entries=frozen, digest=authority_digest(frozen))
70
+
71
+
72
+ def empty_manifest() -> _TokenAuthorityManifest:
73
+ return _EMPTY_AUTHORITY
74
+
75
+
76
+ def stamp_payload(stamp: SanitizationStamp) -> bytes:
77
+ values = (
78
+ stamp.result_id,
79
+ stamp.stage,
80
+ stamp.config_digest,
81
+ stamp.text_digest,
82
+ stamp.store_id or "",
83
+ stamp.scope_id or "",
84
+ stamp.decision,
85
+ "1" if stamp.complete else "0",
86
+ stamp.findings_digest,
87
+ stamp.authority_digest,
88
+ )
89
+ return "\0".join(values).encode()
90
+
91
+
92
+ def sign_stamp(key: bytes, stamp: SanitizationStamp) -> str:
93
+ return hmac.new(key, stamp_payload(stamp), "sha256").hexdigest()
94
+
95
+
96
+ def attach_authority(result: ScanResult, manifest: _TokenAuthorityManifest) -> None:
97
+ object.__setattr__(result, "_authority", manifest)
98
+
99
+
100
+ def tokens_in(text: str) -> tuple[str, ...]:
101
+ return tuple(match.group() for match in _TOKEN_RE.finditer(text))
102
+
103
+
104
+ def extract_generation_tokens(result: ScanResult) -> frozenset[str]:
105
+ manifest = result._authority
106
+ if not manifest.entries:
107
+ return frozenset()
108
+ present = set(tokens_in(result.sanitized))
109
+ return frozenset(entry.token for entry in manifest.entries if entry.token in present)
110
+
111
+
112
+ def verify_stamp(
113
+ key: bytes,
114
+ result: ScanResult,
115
+ *,
116
+ config_digest: str,
117
+ redactions: Redactions,
118
+ ) -> bool:
119
+ stamp = result.sanitization
120
+ if len(stamp.tag) != 64:
121
+ return False
122
+ unsigned = replace(stamp, tag="")
123
+ if not hmac.compare_digest(stamp.tag, sign_stamp(key, unsigned)):
124
+ return False
125
+ if stamp.config_digest != config_digest:
126
+ return False
127
+ if stamp.store_id != redactions.id or stamp.scope_id != redactions.scope_id:
128
+ return False
129
+ if stamp.decision != result.decision or stamp.complete != result.complete:
130
+ return False
131
+ if stamp.text_digest != hashlib.sha256(result.sanitized.encode()).hexdigest():
132
+ return False
133
+ if stamp.findings_digest != findings_digest(result.findings):
134
+ return False
135
+ return stamp.authority_digest == result._authority.digest