@miller-tech/uap 1.127.0 → 1.128.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/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +1 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/deliver.d.ts +4 -0
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +26 -4
- package/dist/cli/deliver.js.map +1 -1
- package/dist/delivery/agentic-executor.d.ts +11 -0
- package/dist/delivery/agentic-executor.d.ts.map +1 -1
- package/dist/delivery/agentic-executor.js +16 -3
- package/dist/delivery/agentic-executor.js.map +1 -1
- package/dist/delivery/snapshot.d.ts +45 -5
- package/dist/delivery/snapshot.d.ts.map +1 -1
- package/dist/delivery/snapshot.js +304 -21
- package/dist/delivery/snapshot.js.map +1 -1
- package/docs/INDEX.md +7 -1
- package/docs/architecture/OVERVIEW.md +6 -1
- package/docs/guides/DELIVER.md +13 -0
- package/docs/guides/SANDBOX.md +99 -0
- package/docs/reference/CONFIGURATION.md +2 -0
- package/package.json +3 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/templates/hooks/uap-policy-gate.sh +62 -3
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +50 -1
|
@@ -155,7 +155,16 @@ ANTHROPIC_API_BASE = os.environ.get(
|
|
|
155
155
|
ANTHROPIC_API_KEY = os.environ.get("ANTHROPIC_API_KEY", "")
|
|
156
156
|
ANTHROPIC_PASSTHROUGH_MODELS = os.environ.get("ANTHROPIC_PASSTHROUGH_MODELS", "")
|
|
157
157
|
PROXY_PORT = int(os.environ.get("PROXY_PORT", "4000"))
|
|
158
|
-
|
|
158
|
+
# Bind loopback by DEFAULT (security audit: an unauthenticated 0.0.0.0 listener
|
|
159
|
+
# let any LAN host drive the local model and reach cloud passthrough). To run
|
|
160
|
+
# the proxy as a shared LAN service, set PROXY_HOST=0.0.0.0 AND set
|
|
161
|
+
# PROXY_AUTH_TOKEN so the exposure is credential-gated.
|
|
162
|
+
PROXY_HOST = os.environ.get("PROXY_HOST", "127.0.0.1")
|
|
163
|
+
# Optional shared secret. When set, every request to a model route must present
|
|
164
|
+
# it as `Authorization: Bearer <token>` or `X-Uap-Proxy-Token: <token>`. Unset
|
|
165
|
+
# (default) = no check, which is safe only because the default bind is loopback.
|
|
166
|
+
# The health probe stays open so liveness checks don't need the secret.
|
|
167
|
+
PROXY_AUTH_TOKEN = os.environ.get("PROXY_AUTH_TOKEN", "").strip()
|
|
159
168
|
PROXY_LOG_LEVEL = os.environ.get("PROXY_LOG_LEVEL", "INFO").upper()
|
|
160
169
|
PROXY_READ_TIMEOUT = float(os.environ.get("PROXY_READ_TIMEOUT", "180"))
|
|
161
170
|
PROXY_GENERATION_TIMEOUT = float(os.environ.get("PROXY_GENERATION_TIMEOUT", "300"))
|
|
@@ -3051,6 +3060,46 @@ app = FastAPI(
|
|
|
3051
3060
|
lifespan=lifespan,
|
|
3052
3061
|
)
|
|
3053
3062
|
|
|
3063
|
+
|
|
3064
|
+
# Open paths that never require the shared secret (liveness / discovery), so a
|
|
3065
|
+
# LAN health check or an SDK model-list probe works without the token.
|
|
3066
|
+
_PROXY_AUTH_OPEN_PATHS = frozenset({"/health", "/", "/v1/models"})
|
|
3067
|
+
|
|
3068
|
+
|
|
3069
|
+
@app.middleware("http")
|
|
3070
|
+
async def _shared_secret_auth(request: Request, call_next):
|
|
3071
|
+
"""Gate every request behind PROXY_AUTH_TOKEN when it is set.
|
|
3072
|
+
|
|
3073
|
+
No-op when the token is unset (the default; safe only because the default
|
|
3074
|
+
bind is loopback). When set — the intended posture for a shared LAN service
|
|
3075
|
+
(PROXY_HOST=0.0.0.0) — a request must present the token as
|
|
3076
|
+
`Authorization: Bearer <token>` or `X-Uap-Proxy-Token: <token>`; otherwise
|
|
3077
|
+
401. Uses a constant-time compare to avoid a timing oracle.
|
|
3078
|
+
"""
|
|
3079
|
+
if PROXY_AUTH_TOKEN and request.url.path not in _PROXY_AUTH_OPEN_PATHS and request.method != "OPTIONS":
|
|
3080
|
+
provided = request.headers.get("x-uap-proxy-token", "")
|
|
3081
|
+
if not provided:
|
|
3082
|
+
auth = request.headers.get("authorization", "")
|
|
3083
|
+
if auth.lower().startswith("bearer "):
|
|
3084
|
+
provided = auth[7:].strip()
|
|
3085
|
+
import hmac as _hmac
|
|
3086
|
+
|
|
3087
|
+
if not (provided and _hmac.compare_digest(provided, PROXY_AUTH_TOKEN)):
|
|
3088
|
+
return Response(
|
|
3089
|
+
content=json.dumps(
|
|
3090
|
+
{
|
|
3091
|
+
"type": "error",
|
|
3092
|
+
"error": {
|
|
3093
|
+
"type": "authentication_error",
|
|
3094
|
+
"message": "missing or invalid proxy token (set X-Uap-Proxy-Token or Authorization: Bearer)",
|
|
3095
|
+
},
|
|
3096
|
+
}
|
|
3097
|
+
),
|
|
3098
|
+
status_code=401,
|
|
3099
|
+
media_type="application/json",
|
|
3100
|
+
)
|
|
3101
|
+
return await call_next(request)
|
|
3102
|
+
|
|
3054
3103
|
# NOTE: Concurrency control is enforced by _acquire_upstream_slot() inside
|
|
3055
3104
|
# _post_with_retry (the single point where we hit llama.cpp). An earlier
|
|
3056
3105
|
# implementation also added an HTTP middleware that acquired the same
|