@miller-tech/uap 1.172.6 → 1.172.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.172.6",
3
+ "version": "1.172.7",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -98,6 +98,48 @@ REASON = (
98
98
  )
99
99
 
100
100
 
101
+ # Scripts invoked by the command, e.g. `bash deploy.sh`, `sh ./x.sh`, `./x.sh`,
102
+ # `source x.sh`. Every rule above reads the command TEXT, so moving a
103
+ # service-restart of the inference stack one level down -- into a file -- slipped
104
+ # past all of them. Not theoretical: it was used during this project's own
105
+ # sessions to cycle the stack while the gate reported nothing to block.
106
+ _SCRIPT_INVOCATION_RE = re.compile(
107
+ r"(?:^|[|;&]|\bsudo\b|\benv\b\s)\s*"
108
+ r"(?:(?:ba|z|k|da)?sh\s+|source\s+|\.\s+)?"
109
+ r"((?:\./|/|~/|\.\./)[^\s;|&<>()'\"]+|[\w./-]+\.(?:sh|bash|zsh))"
110
+ )
111
+ # Only small local files are worth reading; the cap keeps this off the hot path.
112
+ _MAX_SCRIPT_BYTES = 256 * 1024
113
+
114
+
115
+ def _referenced_script_bodies(cmd: str, limit: int = 4) -> list[tuple[str, str]]:
116
+ """(path, contents) for scripts this command would execute.
117
+
118
+ Best-effort and deliberately shallow: one level, at most `limit` files, and
119
+ any read error is skipped. A miss must degrade to today's behaviour
120
+ (text-only scanning), never to an exception that takes the whole gate down.
121
+ """
122
+ found: list[tuple[str, str]] = []
123
+ seen: set[str] = set()
124
+ for m in _SCRIPT_INVOCATION_RE.finditer(cmd):
125
+ raw = m.group(1)
126
+ if raw in seen:
127
+ continue
128
+ seen.add(raw)
129
+ try:
130
+ p = Path(raw).expanduser()
131
+ if not p.is_absolute():
132
+ p = Path.cwd() / p
133
+ if not p.is_file() or p.stat().st_size > _MAX_SCRIPT_BYTES:
134
+ continue
135
+ found.append((str(p), p.read_text(errors="replace")))
136
+ except Exception: # noqa: BLE001 - unreadable/oddly-named file: skip it
137
+ continue
138
+ if len(found) >= limit:
139
+ break
140
+ return found
141
+
142
+
101
143
  def main() -> None:
102
144
  operation, args = parse_cli()
103
145
  if operation not in BASH_OPS:
@@ -108,6 +150,11 @@ def main() -> None:
108
150
  for rule in RULES:
109
151
  if rule.search(cmd):
110
152
  emit(False, REASON)
153
+ # Same rules, applied to the body of any script the command would run.
154
+ for path, body in _referenced_script_bodies(cmd):
155
+ for rule in RULES:
156
+ if rule.search(body):
157
+ emit(False, f"{REASON} (matched inside the invoked script {path})")
111
158
  emit(True, "no infra-destructive pattern")
112
159
 
113
160