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.
- jes/__init__.py +61 -0
- jes/_engine/__init__.py +6 -0
- jes/_engine/authority.py +135 -0
- jes/_engine/core.py +1152 -0
- jes/_engine/limits.py +220 -0
- jes/_engine/merge.py +84 -0
- jes/_engine/plan.py +797 -0
- jes/_engine/restore.py +105 -0
- jes/_engine/run_async.py +273 -0
- jes/_engine/run_sync.py +253 -0
- jes/_engine/sensitive.py +262 -0
- jes/_engine/uri.py +117 -0
- jes/_env.py +90 -0
- jes/backends/__init__.py +269 -0
- jes/backends/_codec.py +454 -0
- jes/backends/_http.py +170 -0
- jes/backends/_profiles.py +202 -0
- jes/backends/_tokens.py +66 -0
- jes/backends/litellm_judge.py +468 -0
- jes/backends/llama_guard.py +673 -0
- jes/backends/prompt_guard.py +437 -0
- jes/backends/system_one.py +682 -0
- jes/errors.py +57 -0
- jes/policies/UNICODE-LICENSE.txt +6 -0
- jes/policies/__init__.py +69 -0
- jes/policies/_candidates.py +275 -0
- jes/policies/_confusables_data.py +6721 -0
- jes/policies/_exploit_terms.py +27 -0
- jes/policies/_fold.py +156 -0
- jes/policies/_protocols.py +192 -0
- jes/policies/_ucd_data.py +2225 -0
- jes/policies/_unicode.py +72 -0
- jes/policies/defaults.py +33 -0
- jes/policies/judgments.py +373 -0
- jes/policies/pii.py +315 -0
- jes/policies/prompts.py +138 -0
- jes/policies/secrets.py +191 -0
- jes/policies/transforms.py +548 -0
- jes/py.typed +1 -0
- jes/questions.py +235 -0
- jes/recipes/__init__.py +34 -0
- jes/recipes/judgments.py +322 -0
- jes/recipes/prompts.py +49 -0
- jes/recipes/transforms.py +272 -0
- jes/redactions.py +337 -0
- jes/testing.py +428 -0
- jes/types.py +260 -0
- jes-1.0.0.dist-info/METADATA +400 -0
- jes-1.0.0.dist-info/RECORD +51 -0
- jes-1.0.0.dist-info/WHEEL +4 -0
- 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
|
+
|
jes/_engine/__init__.py
ADDED
jes/_engine/authority.py
ADDED
|
@@ -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
|