@miller-tech/uap 1.170.1 → 1.172.1
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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +26 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/browser/web-browser.d.ts +17 -0
- package/dist/browser/web-browser.d.ts.map +1 -1
- package/dist/browser/web-browser.js +36 -0
- package/dist/browser/web-browser.js.map +1 -1
- package/dist/cli/interaction.d.ts +29 -0
- package/dist/cli/interaction.d.ts.map +1 -0
- package/dist/cli/interaction.js +217 -0
- package/dist/cli/interaction.js.map +1 -0
- package/dist/cli/verify.d.ts +6 -0
- package/dist/cli/verify.d.ts.map +1 -1
- package/dist/cli/verify.js +112 -7
- package/dist/cli/verify.js.map +1 -1
- package/dist/delivery/execution-gate.d.ts +7 -0
- package/dist/delivery/execution-gate.d.ts.map +1 -1
- package/dist/delivery/execution-gate.js +42 -1
- package/dist/delivery/execution-gate.js.map +1 -1
- package/dist/delivery/fidelity.d.ts +16 -0
- package/dist/delivery/fidelity.d.ts.map +1 -1
- package/dist/delivery/fidelity.js +7 -0
- package/dist/delivery/fidelity.js.map +1 -1
- package/dist/delivery/interaction/driver.d.ts +60 -0
- package/dist/delivery/interaction/driver.d.ts.map +1 -0
- package/dist/delivery/interaction/driver.js +18 -0
- package/dist/delivery/interaction/driver.js.map +1 -0
- package/dist/delivery/interaction/manifest.d.ts +84 -0
- package/dist/delivery/interaction/manifest.d.ts.map +1 -0
- package/dist/delivery/interaction/manifest.js +241 -0
- package/dist/delivery/interaction/manifest.js.map +1 -0
- package/dist/delivery/interaction/mine.d.ts +54 -0
- package/dist/delivery/interaction/mine.d.ts.map +1 -0
- package/dist/delivery/interaction/mine.js +218 -0
- package/dist/delivery/interaction/mine.js.map +1 -0
- package/dist/delivery/interaction/runner.d.ts +61 -0
- package/dist/delivery/interaction/runner.d.ts.map +1 -0
- package/dist/delivery/interaction/runner.js +359 -0
- package/dist/delivery/interaction/runner.js.map +1 -0
- package/dist/delivery/interaction/types.d.ts +223 -0
- package/dist/delivery/interaction/types.d.ts.map +1 -0
- package/dist/delivery/interaction/types.js +19 -0
- package/dist/delivery/interaction/types.js.map +1 -0
- package/dist/delivery/interaction/verdict.d.ts +26 -0
- package/dist/delivery/interaction/verdict.d.ts.map +1 -0
- package/dist/delivery/interaction/verdict.js +139 -0
- package/dist/delivery/interaction/verdict.js.map +1 -0
- package/dist/delivery/interaction/watchdog.d.ts +82 -0
- package/dist/delivery/interaction/watchdog.d.ts.map +1 -0
- package/dist/delivery/interaction/watchdog.js +210 -0
- package/dist/delivery/interaction/watchdog.js.map +1 -0
- package/dist/delivery/interaction/web-driver.d.ts +102 -0
- package/dist/delivery/interaction/web-driver.d.ts.map +1 -0
- package/dist/delivery/interaction/web-driver.js +306 -0
- package/dist/delivery/interaction/web-driver.js.map +1 -0
- package/dist/delivery/interaction-gate.d.ts +45 -0
- package/dist/delivery/interaction-gate.d.ts.map +1 -0
- package/dist/delivery/interaction-gate.js +255 -0
- package/dist/delivery/interaction-gate.js.map +1 -0
- package/dist/delivery/mission-acceptance.d.ts +2 -0
- package/dist/delivery/mission-acceptance.d.ts.map +1 -1
- package/dist/delivery/mission-acceptance.js +23 -0
- package/dist/delivery/mission-acceptance.js.map +1 -1
- package/dist/delivery/vision-judge.d.ts +21 -0
- package/dist/delivery/vision-judge.d.ts.map +1 -1
- package/dist/delivery/vision-judge.js +96 -0
- package/dist/delivery/vision-judge.js.map +1 -1
- package/dist/delivery/visual-gate.js.map +1 -1
- package/dist/types/config.d.ts +20 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +7 -0
- package/dist/types/config.js.map +1 -1
- package/package.json +1 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/enforcement_self_protect.py +96 -5
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
|
@@ -54,12 +54,103 @@ BYPASS_PATTERNS = (
|
|
|
54
54
|
re.compile(r"UAP_USER_VALIDATION\s*=\s*['\"]?0", re.I),
|
|
55
55
|
)
|
|
56
56
|
# Destructive ops against the enforcer/policy surface.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
#
|
|
58
|
+
# HONEST SCOPE: this is a NUDGE, not a boundary. An agent that can write a file
|
|
59
|
+
# and then run it (`Write tmp.sh` + `bash tmp.sh`), or use `python3 -c`, or hide
|
|
60
|
+
# a path in a variable, walks straight past anything a regex over shell text can
|
|
61
|
+
# see. What this catches is the naive, direct form — which is what was actually
|
|
62
|
+
# observed in the wild. The real control is that a missing manifest FAILS under
|
|
63
|
+
# max fidelity (see interaction-gate: skipped verdicts block when fidelity.max),
|
|
64
|
+
# so deleting the acceptance criteria is not rewarded with a pass.
|
|
65
|
+
#
|
|
66
|
+
# Matched at COMMAND POSITION, never in prose: `echo "do not rm .uap/x"` is a
|
|
67
|
+
# string, not a removal. This repo has already paid for that distinction once
|
|
68
|
+
# (5e26c66, "gates must match commands, not prose that mentions them").
|
|
69
|
+
DESTRUCTIVE_VERBS = (
|
|
70
|
+
"rm", "unlink", "shred", "truncate", "mv", "chmod", "chown", "chattr",
|
|
71
|
+
"dd", "cp", "tee", "install", "sed", "find", "ln",
|
|
61
72
|
)
|
|
62
73
|
|
|
74
|
+
# Paths inside a protected tree that the agent legitimately writes. Without
|
|
75
|
+
# these the enforcer deadlocks the workflows it exists to support: the
|
|
76
|
+
# expert-review gate REQUIRES writing .uap/reviews/<branch>.json, and the visual
|
|
77
|
+
# and interaction gates write their own screenshots and evidence.
|
|
78
|
+
PROTECTED_EXEMPT = (
|
|
79
|
+
".uap/interaction/evidence",
|
|
80
|
+
"policies/waivers",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Deliberately NARROW inside .uap/: that directory is mostly runtime state the
|
|
84
|
+
# tooling writes constantly (verify-cadence, pending-deliver.jsonl, autoroute.log,
|
|
85
|
+
# visual screenshots, deliver logs) — the repo's own hook templates do
|
|
86
|
+
# `echo 0 > .uap/verify-cadence`. Guarding the whole tree would block the
|
|
87
|
+
# project's own plumbing while adding nothing: what must survive is the
|
|
88
|
+
# ACCEPTANCE CRITERIA and the project config, not the scratch state.
|
|
89
|
+
PROTECTED_TARGETS = (
|
|
90
|
+
".policy-tools",
|
|
91
|
+
"src/policies",
|
|
92
|
+
"policies/",
|
|
93
|
+
".uap/interaction",
|
|
94
|
+
".uap.json",
|
|
95
|
+
"anthropic-proxy.env",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
_SEGMENT_SPLIT = re.compile(r"(?:\|\||&&|[;\n|&])")
|
|
99
|
+
_ENV_ASSIGN = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*=\S*$")
|
|
100
|
+
_QUOTES = str.maketrans("", "", "\"'")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _mentions_protected(text: str) -> bool:
|
|
104
|
+
"""True when the text names a protected path and no exempt sub-path."""
|
|
105
|
+
low = text.translate(_QUOTES).lower()
|
|
106
|
+
# Normalise ./ and leading slashes so `./.uap`, `/.uap` and `.uap` agree.
|
|
107
|
+
low = low.replace("./", "/")
|
|
108
|
+
if any(ex in low for ex in PROTECTED_EXEMPT):
|
|
109
|
+
return False
|
|
110
|
+
# The .uap DIRECTORY ITSELF: `rm -rf .uap` / `find .uap -delete` destroy the
|
|
111
|
+
# manifest along with everything else, while `echo 0 > .uap/verify-cadence`
|
|
112
|
+
# names a deeper path and is ordinary tooling. So the bare directory is
|
|
113
|
+
# protected; a specific file under it is not (unless listed below).
|
|
114
|
+
for m in re.finditer(re.escape(".uap"), low):
|
|
115
|
+
if low[m.end():m.end() + 1] in ("", " ", '"', "'", "*"):
|
|
116
|
+
return True
|
|
117
|
+
for target in PROTECTED_TARGETS:
|
|
118
|
+
t = target.lower()
|
|
119
|
+
# Word-ish boundary so `.uap` matches `.uap`, `.uap/x` and `.uap.bak`
|
|
120
|
+
# but not an unrelated longer name like `.uapkeep`.
|
|
121
|
+
for m in re.finditer(re.escape(t), low):
|
|
122
|
+
tail = low[m.end():m.end() + 1]
|
|
123
|
+
if tail in ("", "/", ".", " ", '"', "'", "*"):
|
|
124
|
+
return True
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _bash_destructive(command: str) -> bool:
|
|
129
|
+
"""Destructive op against a protected path, judged per command segment."""
|
|
130
|
+
for segment in _SEGMENT_SPLIT.split(command or ""):
|
|
131
|
+
seg = segment.strip()
|
|
132
|
+
if not seg:
|
|
133
|
+
continue
|
|
134
|
+
# A redirect writes just as destructively as `rm`; the target may be
|
|
135
|
+
# quoted, ./-prefixed, or fd-numbered (`1> .uap/x`).
|
|
136
|
+
for m in re.finditer(r">>?", seg):
|
|
137
|
+
if _mentions_protected(seg[m.end():]):
|
|
138
|
+
return True
|
|
139
|
+
tokens = [t for t in seg.split() if not _ENV_ASSIGN.match(t)]
|
|
140
|
+
if not tokens:
|
|
141
|
+
continue
|
|
142
|
+
verb = tokens[0].rsplit("/", 1)[-1].lower()
|
|
143
|
+
if verb == "git" and len(tokens) > 1:
|
|
144
|
+
verb = f"git {tokens[1].lower()}"
|
|
145
|
+
if verb not in ("git clean", "git checkout"):
|
|
146
|
+
continue
|
|
147
|
+
elif verb not in DESTRUCTIVE_VERBS:
|
|
148
|
+
continue
|
|
149
|
+
if _mentions_protected(" ".join(tokens[1:])):
|
|
150
|
+
return True
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
|
|
63
154
|
OVERRIDE = os.environ.get("UAP_SELF_PROTECT_OFF") == "1"
|
|
64
155
|
|
|
65
156
|
|
|
@@ -123,7 +214,7 @@ def main() -> None:
|
|
|
123
214
|
"`deliver` tool instead of disabling the gate. "
|
|
124
215
|
"(Operator-only override: UAP_SELF_PROTECT_OFF=1.)",
|
|
125
216
|
)
|
|
126
|
-
if
|
|
217
|
+
if _bash_destructive(cmd):
|
|
127
218
|
emit(
|
|
128
219
|
False,
|
|
129
220
|
"BLOCKED: modifying/removing the policy enforcers or proxy env is "
|
|
Binary file
|