1
0
mirror of https://github.com/sredevopsorg/deepseek-kubernetes-sandbox.git synced 2026-11-04 09:53:24 +00:00

4 Commits

Author SHA1 Message Date
Nicolás Georger
f4c0b52ee9 Merge branch 'chore/changelog-dsh-v0.2.1-rc.5-r6' into fix/security-gateway-sessions
Signed-off-by: Nicolás Georger <info@sredevops.org>
2026-10-31 07:38:56 -03:00
github-actions[bot]
96837a43b6 chore(changelog): refresh for dsh-v0.2.1-rc.5-r6 2026-10-31 09:31:08 +00:00
SREDevOpsAgents
2eb5c82ace Merge remote-tracking branch 'origin/main' into fix/security-gateway-sessions
# Conflicts:
#	docs/versioning.md
#	versions.env
2026-10-31 00:55:39 -03:00
SREDevOpsAgents
ae8aba8241 fix(gateway)!: replace token cookies with revocable sessions and harden abuse controls
- Replace user:token cookies with opaque server-side sessions, revocable on logout, delete, recreate and expiry; bind every credential to the path user and add cross-user regression tests.
- Rate-limit /users and /login, add optional signup invite codes and form same-origin checks, and unify login failures to 401.
- Require explicit ALLOW_INSECURE_COOKIES for plain HTTP, use __Host-dsh_gw_session when secure, and fix secure cookie deletion.
- Strip client-supplied forwarding/SSO headers, add an optional upstream allowlist, per-user in-flight and WebSocket message caps, credential-free handshake errors, and sweep-time state pruning.
- Digest-pin base images, hash-pin gateway dependencies, verify DSH_COMMIT in the build, and run the gateway image as non-root with a pinned Python base.
- Update manifests, production checklist, architecture/security docs and add an SSO preflight script.

BREAKING CHANGE: existing dsh_gw_session=<user>:<token> cookies are invalid; users must sign in again. Unknown users on POST /login now return 401 instead of 404, and the gateway refuses COOKIE_SECURE=false unless ALLOW_INSECURE_COOKIES=1.
2026-10-31 00:54:05 -03:00
17 changed files with 386 additions and 561 deletions

5
.entire/.gitignore vendored
View File

@@ -1,5 +0,0 @@
tmp/
settings.local.json
metadata/
logs/
redactors/local/

View File

@@ -1,16 +0,0 @@
{
"version": 1,
"agent": "dsh",
"bridge": "@sredevopsorg/dsh-entire-bridge",
"hook_names": [
"session-start",
"turn-start",
"turn-end",
"compaction",
"session-end",
"subagent-start",
"subagent-end"
],
"installed_at": "2026-11-02T06:02:27.816Z",
"local_dev": false
}

View File

@@ -1,9 +0,0 @@
{
"enabled": true,
"telemetry": true,
"checkpoints": {
"primary": {
"type": "git-refs"
}
}
}

View File

@@ -35,8 +35,7 @@ disclosure once a fix is available.
exposure variant's policy is required, not optional: an exposure without it
is demo-only. Run `examples/dsh-agents-as-a-service/scripts/preflight-sso.sh`
after applying the variant; it checks the Secrets, gateway env, TLS
reference, leftover placeholders, accidental second paths, the gateway
Role's `patch` verb on `sandboxclaims` and the variant NetworkPolicies.
reference, leftover placeholders and accidental second paths.
- **Insecure-cookie guard.** TLS terminates outside the gateway. Set
COOKIE_SECURE=true for HTTPS and remove ALLOW_INSECURE_COOKIES; the gateway
refuses to start with COOKIE_SECURE=false unless ALLOW_INSECURE_COOKIES=1 is

View File

@@ -518,10 +518,8 @@ front of **oauth2-proxy**, which authenticates the browser against GitHub
reports **before** pointing real traffic at the Gateway. It verifies the
Secrets (including a valid oauth2-proxy cookie secret length), the gateway's
`AUTH_PROXY_HEADER`/`COOKIE_SECURE`, that the Gateway's TLS certificate
reference resolves, that the gateway ServiceAccount may `patch`
`sandboxclaims` (SSO token rotation), that the variant's NetworkPolicies are
applied, and that no `your-github-org`/`dsh-demo.example.com` placeholder was
left applied. Full verification steps are in the
reference resolves, and that no `your-github-org`/`dsh-demo.example.com`
placeholder was left applied. Full verification steps are in the
[exposure README](manifests/exposure/README.md).
> **Exposure without the variant NetworkPolicy is demo-only.** The SSO
@@ -601,7 +599,7 @@ applied by the base step.
| Every browser is logged out after a gateway rollout/restart | Expected: sessions are opaque ids in gateway memory and a restart drops them. Sign in again; a production deployment needs shared session state or per-request re-authentication. The DSH sandboxes and their data are unaffected |
| WebSocket closes with `1011` for a busy client | `MAX_IN_FLIGHT_PER_USER` (per-user connection cap) or an upstream/handshake failure closed the socket; check the gateway logs to tell them apart |
| WebSocket closes after a very large message from DSH | A message received from DSH exceeded `WS_MAX_MESSAGE_BYTES` (16 MiB), so the relay closed it instead of buffering; raise the limit only if DSH legitimately sends larger frames. Browser-to-DSH frames are bounded by uvicorn's own limit |
| `scripts/preflight-sso.sh` exits non-zero | It names the failing item: a missing Secret/key, a bad oauth2-proxy cookie-secret length, missing `AUTH_PROXY_HEADER`/`COOKIE_SECURE`, a dangling Gateway TLS reference, a leftover `your-github-org`/`dsh-demo.example.com` placeholder, a second path to the gateway (an Ingress), a gateway Role without `patch` on `sandboxclaims`, or a missing SSO NetworkPolicy. Fix all items before exposing the SSO variant |
| `scripts/preflight-sso.sh` exits non-zero | It names the failing item: a missing Secret/key, a bad oauth2-proxy cookie-secret length, missing `AUTH_PROXY_HEADER`/`COOKIE_SECURE`, a dangling Gateway TLS reference, a leftover `your-github-org`/`dsh-demo.example.com` placeholder, or a second path to the gateway (an Ingress). Fix all items before exposing the SSO variant |
| `409` on signup | User already has a claim; use `POST /login` with the existing token or delete the user first |
| Cookie set but browser keeps getting `401` | `COOKIE_SECURE=true` while serving over plain HTTP (secure cookies are not sent); use HTTPS or set `false` **and** `ALLOW_INSECURE_COOKIES=1` for local demos |
| WebSocket closes immediately (`4401`) | Missing/expired gateway cookie, or the upgrade's `Origin` does not match `Host` (CSWSH check); DSH rejecting `Host` instead surfaces as close `1011` — add the host to `DSH_TRUSTED_HOSTS` |

View File

@@ -339,7 +339,7 @@ The gateway runs with a namespace-scoped ServiceAccount (`manifests/50-gateway.y
| API group | Resource | Verbs | Why |
| --- | --- | --- | --- |
| `extensions.agents.x-k8s.io` | `sandboxclaims` | `get`, `list`, `create`, `patch`, `delete` | signup, state, account deletion, token rotation |
| `extensions.agents.x-k8s.io` | `sandboxclaims` | `get`, `list`, `create`, `delete` | signup, state, account deletion |
| `agents.x-k8s.io` | `sandboxes` | `get`, `list`, `patch` | resolve DNS/pod, wake/suspend |
| `""` (core) | `pods` | `get`, `list` | resolve the pod behind a sandbox |
| `""` (core) | `pods/log` | `get` | launch-token handshake |
@@ -395,8 +395,7 @@ Notes and limits:
- **SSO is trust-on-hop.** `AUTH_PROXY_HEADER` makes the gateway trust the proxy-asserted
identity; the SSO variant must remain the only path to the Service, and its NetworkPolicy is
required, not optional. Run [`scripts/preflight-sso.sh`](../scripts/preflight-sso.sh) after
applying it: it fails when the Role does not grant `patch` on `sandboxclaims` (SSO token
rotation) or when the variant's NetworkPolicies are missing.
applying it.
## Failure modes
@@ -405,7 +404,6 @@ Notes and limits:
| DSH log line changed or rotated away | Proxy returns `503` (missing launch token) | Fix the parser or restart the pod so the token line is re-emitted |
| Probe on `/` | Pod `CrashLoopBackOff`, `401` in probe logs | Use `/favicon.svg` for readiness/liveness (shipped templates do) |
| Warm pool exhausted | JSON signup returns `202` (state `Waking`); form signup is slow | Increase `replicas` in the warm pool |
| Kubernetes API error (API down or throttled, missing RBAC verb) | HTTP `503` + `Retry-After`; WebSocket close `1011` | One credential-free log line with the API `status`/`reason`, plus a fixed body; the Kubernetes `Status` payload is never proxied. Check the ServiceAccount Role and the API server — RBAC is evaluated per request, so a Role fix needs no restart |
| Gateway restart | Idle sandboxes stop suspending; handshake cache and browser sessions lost | Idle clocks and handshake cache rebuild lazily; sessions do not, so browsers must sign in again after a rollout. Use a shared session store for production |
| Gateway configured `COOKIE_SECURE=false` without `ALLOW_INSECURE_COOKIES=1` | Gateway pod exits at startup / `CrashLoopBackOff` | Intentional guard against an insecure cookie on an HTTPS deployment; set `ALLOW_INSECURE_COOKIES=1` only for the local plain-HTTP demo, or set `COOKIE_SECURE=true` |
| Auth rate limit hit | `429` + `Retry-After` on signup/login | Per-client in-memory bucket (`AUTH_RATE_LIMIT`/`AUTH_RATE_WINDOW`); wait for the window or tune it. Behind a proxy, keying uses the rightmost `X-Forwarded-For` entry |
@@ -413,7 +411,7 @@ Notes and limits:
| Per-user concurrency cap hit | HTTP `503` + `Retry-After`, or WebSocket close `1011` | `MAX_IN_FLIGHT_PER_USER` protects the single gateway from one busy tenant; reduce concurrency or raise the cap deliberately. These are per replica |
| Oversized WebSocket message from DSH | Connection closes | `WS_MAX_MESSAGE_BYTES` (16 MiB) is enforced on upstream messages; raise it only if DSH legitimately needs larger frames |
| Session expiry / revocation | `401` (HTTP) or close `4401` (WebSocket) | Expected after logout, user delete, `/recreate`, `COOKIE_MAX_AGE` expiry or a gateway restart; sign in again |
| SSO variant applied without its NetworkPolicy (or with an Ingress) | Gateway accepts spoofed `X-Forwarded-User` | Demo-only configuration; keep `75-networkpolicies.yaml`, remove the second path, and run `scripts/preflight-sso.sh`, which fails when either policy is missing |
| SSO variant applied without its NetworkPolicy (or with an Ingress) | Gateway accepts spoofed `X-Forwarded-User` | Demo-only configuration; keep `75-networkpolicies.yaml`, remove the second path, and run `scripts/preflight-sso.sh` |
| Browser aborts a request (tab reload, back navigation) during a slow wake or handshake | No response reaches the client; nothing appears in the access log | If the abort lands before the response starts, the body read raises `ClientDisconnect` and the app answers `499` (`CLIENT_CLOSED_REQUEST`), which cannot reach the departed peer. Nothing reached DSH, no ERROR traceback is logged, and the in-flight slot is released. A request already streaming ends with its upstream status. |
| DSH auth cookie expired mid-session | Proxy `401` once, then recovers | Gateway refreshes the handshake once |
| Upstream pod name changed after resume | Cached cookie keyed by old pod UID is useless | Cache is invalidated on suspend; next request re-handshakes |

View File

@@ -338,10 +338,8 @@ The SSO policy is what turns the trust boundary in the
The `dsh-gateway` Service must still stay ClusterIP; do not apply both exposure
variants. After applying the SSO variant, run
[`scripts/preflight-sso.sh`](../scripts/preflight-sso.sh): it checks the
gateway's SSO env, the Secrets, the TLS reference, leftover placeholders,
accidental second paths (such as an Ingress), the gateway Role's `patch` verb on
`sandboxclaims` (SSO token rotation) and that both SSO NetworkPolicies are
applied.
gateway's SSO env, the Secrets, the TLS reference, leftover placeholders and
accidental second paths (such as an Ingress).
Verify the negative case from a sandbox pod (it is not the proxy):

View File

@@ -175,11 +175,9 @@ oauth2-proxy's egress to the gateway, DNS and public HTTPS.
| Sandbox not provisioned, wake timeout, handshake failure | `503` + `Retry-After: 10`. The handshake error body is a fixed message: it never contains the launch token, the handshake URL or pod/credential details. |
| User over `MAX_IN_FLIGHT_PER_USER` | `503` + `Retry-After` (HTTP); the existing in-flight requests are untouched |
| Upstream connection/protocol failure | `502` |
| Kubernetes API error (API unreachable/throttled, RBAC `403`, `5xx`) | `503` + `Retry-After: 10`. The body is a fixed message; the Kubernetes `Status` payload (which can name cluster objects) is never proxied, and the API `status`/`reason` is logged once |
| WS auth failure (unknown user, bad token, cross-origin) | accept, then close `4401` |
| WS per-user concurrency cap | accept, then close `1011` |
| WS upstream/handshake failure | accept, then close `1011` |
| WS Kubernetes API error | accept, then close `1011` |
| WS message from DSH over `WS_MAX_MESSAGE_BYTES` | the upstream/relay closes the connection (websockets' message-too-big path) |
A close code can only be delivered after the WebSocket upgrade is accepted;
@@ -232,8 +230,7 @@ would never be sent). HTTPS deployments must set `COOKIE_SECURE=true`.
The gateway's ServiceAccount needs, in its namespace:
* `sandboxclaims` (`extensions.agents.x-k8s.io`): get, list, create, patch, delete
(patch rotates the token-hash annotation when a session is minted)
* `sandboxclaims` (`extensions.agents.x-k8s.io`): get, list, create, delete
* `sandboxes` (`agents.x-k8s.io`): get, list, patch
* `pods`: get, list
* `pods/log`: get

View File

@@ -1510,13 +1510,7 @@ against the JSON API. The browser session is an HttpOnly cookie.</p>
user = websocket.path_params["user"]
if not valid_user(user):
return await self._ws_reject(websocket, 4401)
try:
claim = await self.k8s.get_claim(user)
except ApiException:
# Starlette has no exception handler for WebSocket scopes, so an
# unhandled API error would escape as a traceback and an unclean
# close. 1011 keeps the HTTP 503 meaning on the WS channel.
return await self._ws_reject(websocket, 1011)
claim = await self.k8s.get_claim(user)
if claim is None:
return await self._ws_reject(websocket, 4401)
token, cookie_user = self.credentials(websocket.headers, websocket.cookies)
@@ -1752,28 +1746,6 @@ async def client_gone(request: Request, exc: ClientDisconnect) -> Response:
return Response(status_code=CLIENT_CLOSED_REQUEST)
async def k8s_api_error(request: Request, exc: ApiException) -> Response:
"""Answer a Kubernetes API failure with 503 instead of a bare 500.
The gateway is the only path between the browser and the cluster, so an
API outage, a throttle or a missing RBAC verb is a server-side
availability problem, not a client error. A 503 keeps ingress and
browser retry semantics honest, and the body is a fixed message: the
Kubernetes ``Status`` payload can name cluster objects and is never
proxied. The API ``status``/``reason`` is logged once, credential-free.
"""
print(
"gateway: kubernetes API error: "
f"status={getattr(exc, 'status', None)} reason={getattr(exc, 'reason', None)}",
flush=True,
)
return JSONResponse(
{"error": "cluster API unavailable, retry shortly"},
status_code=503,
headers={"Retry-After": "10"},
)
def create_app(
settings: Settings | None = None,
k8s=None,
@@ -1806,7 +1778,7 @@ def create_app(
]
app = Starlette(
routes=routes,
exception_handlers={ClientDisconnect: client_gone, ApiException: k8s_api_error},
exception_handlers={ClientDisconnect: client_gone},
lifespan=_lifespan(gateway, http_client if owns_http_client else None),
)
app.state.gateway = gateway

View File

@@ -911,9 +911,9 @@ multidict==7.2.1 \
--hash=sha256:fc45ff19520bc5321dcd9c6dd7df6f35ddd894eed35e5be65d1828a9c3f5e7fb \
--hash=sha256:fcfebcb537f419e415b6e2bfc77ddbd33abe3c036f0105410a25a14741df9c31 \
--hash=sha256:fd24c4425fdb8e822601335602375c6d0cb020f7a368e1d5842eb7925a9c8748
oauthlib==4.0.1 \
--hash=sha256:3d73febdb6faa00f277c81fb04be7b7586fb96fc3b7f0b9c772dada69a25ede7 \
--hash=sha256:498a298876e996301950a5b053d12c31628bb7b895db03666430c69ce182eb61
oauthlib==4.0.0 \
--hash=sha256:624c28c13a0a59cabf9747dfa52af63be3e512a7f2714df16e91b5b3a145e6cd \
--hash=sha256:efb274799819440f95b4ab3b818869f1ce9ae26c5beacba0201d1a1b76b54f86
packaging==26.3 \
--hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \
--hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c
@@ -1207,12 +1207,12 @@ pydantic-core==2.50.2 \
pygments==2.21.0 \
--hash=sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9 \
--hash=sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c
pytest==9.2.0 \
--hash=sha256:07acdcf88ec174f907dc01af70bf52d49b014bbab03faeeade31c96b18c2e588 \
--hash=sha256:97c4f3b1f3c7414aa36465e09b8220f1d03627993bd51b1282e193753c80557b
pytest-asyncio==1.4.1 \
--hash=sha256:507afa78ec77c6661164ef1a2368bc7820383fd1a14b2a7f813de8b5a92949cc \
--hash=sha256:e8266eb094e5ee9ffdb2068c9836f33e209ea77a970eb846933d416b5602669b
pytest==9.1.1 \
--hash=sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313 \
--hash=sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c
pytest-asyncio==1.4.0 \
--hash=sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1 \
--hash=sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42
pytest-cov==7.1.0 \
--hash=sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2 \
--hash=sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678
@@ -1222,9 +1222,9 @@ python-dateutil==3.0.0 \
python-dotenv==1.2.4 \
--hash=sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc \
--hash=sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0
python-multipart==0.0.33 \
--hash=sha256:8f16c07b36add9da6b2ee87d3efcaf0a45a6de9c3d0a5dd94e9ccf7675a7bc45 \
--hash=sha256:b8112424a6abd162ec08d390565dd113ad699f2fe6fef3c987b8bbcbfe9e390d
python-multipart==0.0.32 \
--hash=sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e \
--hash=sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23
pyyaml==6.0.3 \
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
@@ -1305,25 +1305,25 @@ requests==2.34.2 \
requests-oauthlib==2.0.0 \
--hash=sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36 \
--hash=sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9
ruff==0.17.3 \
--hash=sha256:029c37cbd3de48ca37aa12117bead2d065f15da17d66bf84e0d4274013705db2 \
--hash=sha256:27bb571ac78fef178fe5118d2827df95c2aae74a48fff2b15f6acd03af5ff5bb \
--hash=sha256:39405f341deec934b4289634324ad695f72df2970f9121582872eaf5b722f0f5 \
--hash=sha256:4590b9d86c0b1543ebb09094254e191cd43fe8edaf330baa035aab03da251532 \
--hash=sha256:46539cb031b01fd29ae0a02142483c46640b233ee12bb1c1b690bffa1555d5ca \
--hash=sha256:56b8ffb3f3b3cbccb8b76b71b38261b7ed982ef5d20f5b447b1b61a7f4949b24 \
--hash=sha256:68074094f55ca3d29ab19491f640282f7a84061c4c7977aa5094b968ca457e9a \
--hash=sha256:692fdb46d0fd9c71e380947dc5fc72f2c3f881073bc1f739e4579376231affbe \
--hash=sha256:6a754c0341bc9ca151b7b335988b3263921c08859f84ca219b70cee825571b6f \
--hash=sha256:7fa4b0f931cdbcb8a52044f370a3eb429fb42eb88807b0e800fcaa98dd42b24e \
--hash=sha256:81fce74bcd6be0e9da7c67c7553fd0f1f12964a2052cd728ef917b937a5ca1d9 \
--hash=sha256:a57049c8addb3662073859bb55a7ad35aa54f8a7c9ed268911d1333c5aadaaa9 \
--hash=sha256:ab5fa7ed5ce18554ea69d850ad162cbaa0c85fc47c08d83a569f806681c9a6ad \
--hash=sha256:ab86b84cd9d05e56d329742c0cabdcbe2d1d56c98f4a04aab9b5b66196febfb4 \
--hash=sha256:b75cc113b3aca388933d8296b667b1ac401a80317ea3074c9b0a66541199da29 \
--hash=sha256:bbde18beccd98c29a227c63c99022e3443b99258e08326df6425dfe0443705ef \
--hash=sha256:c673c170e27834d1262e3a9c1e97bdc9b9c3b180c63d89173ce69747232474c1 \
--hash=sha256:e407b4a6852853a9a2cdce96963e94ad9775578bb44e7561a0f2829f3cc04b11
ruff==0.17.2 \
--hash=sha256:122258f6ecde0e0dd1bb60b24263c3edde4338caf723fca711cc729f9bfd414a \
--hash=sha256:195ad918027f817c119310ca89a42d347887dfc28934aaa869325e9c5dc9d962 \
--hash=sha256:1b59d447f197bef9ef48a22ba1a6016137753c6099e9bac9c36eb566e422424c \
--hash=sha256:2d086be452eed686aa51271ecf2cbe5037956517cc6ee39a17b4489ac12f8bbe \
--hash=sha256:39c5b55c960515cdb32be16e69efb5734c589c06a0eb38a22694524a336b889d \
--hash=sha256:583bd67bb9e7061dd09bc46a0a884bae2bbd214dbcd48e509813612619683869 \
--hash=sha256:5875a16b0de70b43cb81eabea5ae5e8f5d1b2fd1b5e6ed07f80cfe5019d0bd5a \
--hash=sha256:6bce7d1f5165701ae18f5df85c65afe78cddfa6c5fb4b9bdb0014d60388f3edd \
--hash=sha256:7cfd783590edf2b77317882631900f6a13ea2e8eacefe6ebf2370d2715299160 \
--hash=sha256:7f8fba429d6ac4128ab29cfb8fa6240d2fa671d04adf7f84d3b22fc7b6b6bea4 \
--hash=sha256:84d632402d14c23b488f941db23712d6736a013225162062d34558c3f3c780eb \
--hash=sha256:8c21b4ab24485358f17291a4f8dc5399b834e963b8efedd920fe4fdb02081bb4 \
--hash=sha256:92a80d2f44584dabb0189b3a6c393e37e525e04942838482010575cb81945be7 \
--hash=sha256:96a65e755d8dba094707fb23ab602111d9a31ec2835b3a6992a1914a8fcb211e \
--hash=sha256:b7d0906677d89bbf3cf73cde64b5bbe2ab35df3ae43e49ee2627301e91265bac \
--hash=sha256:ba405cbd5ec7bda1f555d5e52be1fd68d02608d4d95d24591bdac92cfacb579f \
--hash=sha256:c555a877f8f41447e318101cfefea9bf12dfa9f82eedf90c376e57e069f917d0 \
--hash=sha256:c60f93fec7142dba5b8f487f94bf2f6231dae24dc11e4c48648347c8b0720004
six==1.17.0 \
--hash=sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 \
--hash=sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81
@@ -1444,161 +1444,161 @@ watchfiles==1.3.0 \
websocket-client==1.9.2 \
--hash=sha256:0fcb57545848be86992e128218fd96dd87a6769ffdb1a968dff79632b85604d0 \
--hash=sha256:e1a673830a9c7bfa47b1cd3d5e4178f4c9651d80a4eab02c9c23a1c3ec6250ce
websockets==17.4 \
--hash=sha256:00ad98e4bb0df7a6711c645eec16d5a9fdf99f0692bd4f5b6cb85a68677ba8df \
--hash=sha256:0132e3cbd3f5cfc1ec77588961b302d72a02e2603b82c2c23fd5fb59dc4fa206 \
--hash=sha256:023dc13bdc42a55e152acc81c39c90ec6cc4159ed17d23c6d73460fa2a73ab16 \
--hash=sha256:02f380df26de14999ecace203fe1396ac14d1c6132afc7924eb6f8c8b646c69d \
--hash=sha256:03ddf4eb76ced8725dcbb000ff60b0fb8d7330ed011f6dc725a1925c5fe02051 \
--hash=sha256:043945a43873c7c11a3f75238d475c95f902e967de329eb8763704546cfaa6b6 \
--hash=sha256:046ed16d3d83d64594e4a40655fef061ccf36059d8c30a01feca8a9481fe13b8 \
--hash=sha256:06ea46717553cdd10f2682126cf7a66e91c8ed17b6969f4a95e94b4e01d06188 \
--hash=sha256:09d3939b70df0c8ad2da145ebd50978bccaee1d565e838b0e7921a34d38571eb \
--hash=sha256:0a57b99f2e28922b5a2434317580fd23fdf118caff4c5b752f5452836426205a \
--hash=sha256:0c22a9c6b2349204f56123dd0ca7779e989d68e336d0dc02ad823485d44925de \
--hash=sha256:0dcce83837328e6795225ead920d3aa8d867cc9d6922aa558b0e9111599fdbb9 \
--hash=sha256:0e51546a3bedadd80dfa5c2efaed840ac51b8632d8db7f9f502175f5349382a9 \
--hash=sha256:156221ad7638b5abccefd6f798916bf3f8ffd6ac51480eb4ba5b05df914ccbf3 \
--hash=sha256:16550e24ac22c27e0a728100d8de196b5f054bab6748ef9f0b168fb8b3c32e35 \
--hash=sha256:18d3710becc612ec6f0229425bd6495133dfcbf30f7b6569585acc8ed2f1b452 \
--hash=sha256:1962f3bfde085af18878f1bb1aafb300c9a6ac33da886d0b0d97e33c9ce7a222 \
--hash=sha256:203e42eb77e06f85778a908b34c5ad032f34e98a68ef33920d6685c1e65a9420 \
--hash=sha256:2103982762460a764a7ef0021443bb471f46d45ecc6858276e4fe699ebac6b94 \
--hash=sha256:25eb661d8ba7e2b85ebb4e7a1bb9f6a3280910ed10b84330a7abfb5ed32d2764 \
--hash=sha256:29b615c2d5dd883f89c107a782681b73a7aa8b2bd894130310e45eb09b143913 \
--hash=sha256:2a9cb5bbfc33b4ebd3c8d3714d6e09805437f60a14977774e4bd11b5ace46c23 \
--hash=sha256:2b23dacf7a8a88afe92f77bcdbf4cf043a84692bac2f2da02f4011c687e19b48 \
--hash=sha256:2fd562372d4afaf18d1c7f1c68e39bd32818bb16d5f57f778a4a4ed88eedcaae \
--hash=sha256:32110d954d9d0e51f36edb0396673bf4d35193a0a80ba7013bf7f7d58a33ca07 \
--hash=sha256:332b88022d0acd47c44158bcd43f47f14eaddcd979247f242b1a33291c45cdd1 \
--hash=sha256:361f9a21a33191d5287e7a75f508fc3b9bf47aaffb0241198d6b7be3384f294e \
--hash=sha256:37ed7782972545e67d97ef9a172e9499d25459b1e32cb99d1c2a30c572f2441b \
--hash=sha256:3acc45494c08a4d27375a2c28474537f68910219f42624a08011221b04623d04 \
--hash=sha256:3b76837cd051d8875913f3934b27205f7a592f78b8a4f4a1f3abc36a2420c5bc \
--hash=sha256:3b78b39377630a70aa2198e5f03be416e690364a046b1d8af80a9263733083d0 \
--hash=sha256:3d27153a0413696767b98b5d96173a2a7e27cbfca02000a6069cea7b977765a7 \
--hash=sha256:3d512e3a6c528c42ce220ed9c3caff83c6fdcd98a1b98249f08ccfc66ad111b1 \
--hash=sha256:4073ab7cefe5a2e7dc368c1f01eb27716dc8ea8f1c69e9b7725ebce05aa53cf7 \
--hash=sha256:42d7a6e818214336cf7af9a3aae5c6923f94f09fa07ac5aab98268ba2a98a6d5 \
--hash=sha256:4441d655a53185ef1b01b1d42ad9b3a96b905110a9219043e3fdaec855ba3b6e \
--hash=sha256:47beedf07a706140b50786457e082497ee6b5970c41e49bcd1572ee3f4c73f80 \
--hash=sha256:48c83103f82fce36191a9e3a8a80731d4340e2da544eae8c5aaaf6a45280e7d0 \
--hash=sha256:4b79ea31cf277c72d2307c6cb8bd32a2c151959e80a2f24fa85df620c5f2860c \
--hash=sha256:4c792e6cce24d08f92199d907785c9e64f74c357deeed3dbaf7d699ed5930b64 \
--hash=sha256:4d2636a5b61c69e32db0e74b57073dd4a66f1ad195e9398c5f01bba41090deea \
--hash=sha256:4fb2db1f649b6464711846b5bb9c1611bd906ce939d9460cbd1fa419552cd6c3 \
--hash=sha256:506623128d7a55b726a5a46e4c9a8eae4c9dd0f04ff60b041fe7df85b9d034fe \
--hash=sha256:51adfc30f467077293a6695d8149bcef501c0728386f3a491054f835dadb60b2 \
--hash=sha256:52c31d123f5adf14dec694c2a4036bf42c523df7cefc641d31cd05653de56e49 \
--hash=sha256:5830f94a7190a33e55d06d89242ea951ee2009c3a27fc31538f3ac9386b27edd \
--hash=sha256:5cec3e7fbc911ff4fcf43b24aaf1b96906381ad36030f42897def3ff4b78729e \
--hash=sha256:5da7f7f1ecf866186f195f7ecc374c915e1838496b86f2f3b41da27c798a25c3 \
--hash=sha256:5ec906bb21b35e66cfdcc2ea0133f249f52b7d89e3e45ec8d2bd2d84a0255d7d \
--hash=sha256:5f772007dfba8941873dbd276b6a6845428cc740888b5c6c37bf483b1ea34b42 \
--hash=sha256:648adde345cfd13335342e23cfe94871c7f7f55a43fb254f3b95acb071072968 \
--hash=sha256:6531540aa63e6864cb0615a3a5da70ae03191334507852a5385320bb7916df3f \
--hash=sha256:6597a1f7413189b4bc58437babcdf39b79da416e5c477ae98323a88ecc108188 \
--hash=sha256:6686d29eaafddeeab9e48af92103dc0d26161035faa4be083b8b488f1ab47219 \
--hash=sha256:679eef0123861ca381dd8fd9bdc1920e87636ac55eae6cff875c53dcb05fbcf8 \
--hash=sha256:6afc32a7a1a40b071070419537df3559d26907086556769683fa97b7b6e90fd5 \
--hash=sha256:6b061ea7ca94966af7cd7a87cb189ff15972c103244611a2b1e8408c04f1dbe6 \
--hash=sha256:6cf4c002268da5c11cae9083aec71ac943bce9d95e0f83c8bf9a95a3ce421fbb \
--hash=sha256:6e6558efbb256b532c9f06a21ba42bcac729718e365c505819f181f25e5c0eca \
--hash=sha256:6fd8cac4907fec8302726d49e6969acfffaf720bc39b1cee23f473b81f4dce01 \
--hash=sha256:70293c25d79d1f084fdd665894481547575e429d2a75e8d72caec2f6b6b07af8 \
--hash=sha256:71f76bb8e59be847330b8a8d3753f85397677e128f9f9692c215f8cf721cefc7 \
--hash=sha256:725be1aff55f1c873a79cea0f612df9dff21a9d2c2e05783665b824b8aa7c24e \
--hash=sha256:72d0a731eccf482d5661c6711abfcd5921f3dbfbbb0789061e1918ef4bc89c70 \
--hash=sha256:7390e060f830b3d132f484b21ac2783a2d227b682ef62bb8146e1c1b4ca0e45a \
--hash=sha256:73b00645316121105274fd266ed54a20e6514650126d399cdea39876ab1e7b04 \
--hash=sha256:74e46409666c358b93fce0d8c6f4cb107d8dd7cba1302a38d49adf6fa8193c7e \
--hash=sha256:75b32cf33ea40f945f226f97bc1d43151e1a5adff21f420b5e63c468b1a28114 \
--hash=sha256:769e4f7b090e10cae4c082e3e39b9458ec2444505df84953c16c0468b16539c4 \
--hash=sha256:7849a096d6fdba3f2bdf849eb89f2d233a24400c92faa3efb25fa8dc615b706c \
--hash=sha256:799c5a23126c9589cb10b6c6b54f9087246940dad20cd74bf3f06fc9ae3bbab5 \
--hash=sha256:7a7e9321822ca59ba56fa8744c3e3f01ef74d547aafe0d383d000d7a4d11eb79 \
--hash=sha256:7b23db4b469d9e051ac74d96db9bf61e27c9054de64f8263fefa32bf72867ba1 \
--hash=sha256:7b4ee34acefa9ba1333f02b817982f1e4127f6f9b975017a707c4e738d7f9fb9 \
--hash=sha256:829bcaa90be8737c132d9515d6a466e8528e3b3d050d3f3466f36ea94d3beb48 \
--hash=sha256:8588edf317fbe4f16a949bc5a6ccdd22b6e6fd5b4745d128bc40bccf31024ce5 \
--hash=sha256:868744c68e9342768888c7326604da2228c19bb6946aa46b5f9e1ac32ea8d40b \
--hash=sha256:88ba8a439b2bad97bb69c38db5bf0ec16a061ee834cf0f244089186ee803e899 \
--hash=sha256:8b45d40f07081b377f0b837ddbfba4a9ab4a89a7b569d3c095436564e767a27b \
--hash=sha256:8c00c5c49f80a588a2c4f99d519d2abed4ce26cdca11273041bc8b7e60af60de \
--hash=sha256:8c51ac7b31578a7275650f580aac985940985b6d2e57247ac6d5e07f2c936cd6 \
--hash=sha256:8d148b4b295224d3a19e7bd9f02ebe7344de254b3b2c4d0628ce42ade0bca119 \
--hash=sha256:8f32a6cb0b101170abc2d8053af1473a2a29ef2a06d7130994ee8455a50f5dbf \
--hash=sha256:8fd30d217a4275107667fe1d4f601e2d50c797d0727148cfbb384536d65f04d3 \
--hash=sha256:927d602fb8fb595a69e6b1ae998a6ec19851d0fb9391759456e6425090996647 \
--hash=sha256:94622cf24e80d03054ceb69a06a86c950e12fe993ed06b933f7895232cacbc3e \
--hash=sha256:954d43574f72be244b65f0fa61e2f814214b024f2ec849f487aa2f553f7c6e71 \
--hash=sha256:98f16db5e79f2605194c0f899d0532005bb12269e698bf96f62a5635bcf33010 \
--hash=sha256:9a4e95d56994a45ac76541853796720436ffe462957d0b1b89e87ff3d3b1627e \
--hash=sha256:9ae1429ee9e52b139167ed0169757806a27ed7307e942e8c62037a9184e9843b \
--hash=sha256:9e282f35ece8895b9fa5af406fc6a4cb42f01e1009525cf46641de584781c83b \
--hash=sha256:9ff89e36451a19775e7556d95ebfa4a0b24b84cc87565d6b5d0ec8ea82bf3f2c \
--hash=sha256:a0457561e8a87a6a3b509e21c35084d7d207ced262139de3f738e9676a476bbd \
--hash=sha256:a50bd9b44dd9b7b845802030b4d88610c01c7f95571b4cbd3a1aeec17a34c9fd \
--hash=sha256:a703f23ca15a51251fc94f1774683f5aa511588a7ad6bbb83960cdb2a4dcd978 \
--hash=sha256:a920e99155d75d1b1c08172da8aaa7200e7b30871fb628d1631d7891a333e30e \
--hash=sha256:a9b0026538719f7a532998d84640ab2e91ca1a051ce4b8d924fdcb607307e921 \
--hash=sha256:ab9e4bd60796866c578e3afa0a17c98636887827a39c2e238a61989c18fd8e7b \
--hash=sha256:accb5e9492b9bc9c9aeec5b72ea8f2ddcbefc6143d1c626fba960ecbdc89807e \
--hash=sha256:ad2e9e152bec6c4f7e4cdb4adcea6b708400090eec04bfe5ee5b30d368ffd721 \
--hash=sha256:adc30e5d064c9e33049e825408fa4e952f4e8a0cf4c329dc2ded72e1bb5bae08 \
--hash=sha256:b529ad6c81ad21db2f4e3d6e33db78ce3b9f272066b438b5d673361f9282898d \
--hash=sha256:b6c7f91520c29420639925fd1cecceac9ca07366b50c09ea24eac1cd116b4866 \
--hash=sha256:b7ea61af293a153f2d67430038cf0efc10140caa623f2bdf5a9f5a457ff20f57 \
--hash=sha256:b8451f31ae24620cc9372acd2728d87922f2bb0cae3fa57aed68b152844cdf08 \
--hash=sha256:bbb6bed49f083e2ec8ae0bb21c00c7c5171ab8e08a8b008c61a43fc6c944fdac \
--hash=sha256:bc581579885728bb54ef15000295c20e6a64a200b1b73d5cfca71879a3eb3e1f \
--hash=sha256:bcad49104711f88b2b7c3ba166de172857d837248205e541b044a552558fecc3 \
--hash=sha256:bfc86dff091104eec770c29ea1831dbe191968a70aa2d8ae8eda3240d863970a \
--hash=sha256:c00f0c45851a2c61efffd03dde8fb4d594026b5cc18196c94e15460f1225f2ed \
--hash=sha256:c0cc2cb47face4dae64bd70a9268dbebddb3e48c1b48cf6d7b6ac1471609fd88 \
--hash=sha256:c2db7b9e2d726f7e051bedb67abcf460b84b11437b2f9fdacda7e6931dace85b \
--hash=sha256:c44776f82b04e623eb9e1b81fcd17ac6e9808ae1ba5cdf8edce1f7c869a95a9b \
--hash=sha256:c564d1e6531611bf87078c28780456ecc75459dcca189629fff2fe7c020d8e67 \
--hash=sha256:c568e72f5425a74616daeb824afe28da460cbeea036432f41c6af5380b83300d \
--hash=sha256:c5e970d3996c597186c9dbb6e77a8048737a834ac03cb13186a54999e0e1c31e \
--hash=sha256:c634053459278cf31fb404ddb5ecd38124e4609e8b609166da621edc2d5796db \
--hash=sha256:c63c0d7832956d5f3bb77888b93c854569d13f806289ff75c43926d25c6e5fd2 \
--hash=sha256:c6bd2c9781915592b209160d0f017d4c7c82ad53075e6b0c24d2a89299e7f9e9 \
--hash=sha256:c74954409ea5789f7a60daa5f94580c00ad0b60b20751c47b35c4784877b5057 \
--hash=sha256:c7a56140fcbf4662cb263754a754c651a16fe2196cae1fd232d18f89acd30c83 \
--hash=sha256:c7b996c02de5e032cb63dc65482b73693b7ecaa586654126be2749ddea239c40 \
--hash=sha256:c7f66a53e9b7ec831abb15e3d9b6cee8f52d6a24cd0a374786bf46c3ec218bc6 \
--hash=sha256:c8052c3058c402d53602583da5ddcf1a15a63ab1efe0222f47c7be59944e6463 \
--hash=sha256:c9f8fdb7bbefc4907c2bb3593f810f2b67a2d5329e1d38724a1aa3d763cf63eb \
--hash=sha256:cbdf4b42f4514422051889424fd03bc269be8c5d751bf39ec29ad761590bd10d \
--hash=sha256:cc0cd4065a65ac98f3e2742ee9f314da9d224db49b07dc17d3a20cef0d79658d \
--hash=sha256:cebad8f4796248b91fc2168515e507e5cb6b663a32befd09f3b1e7920acdcb1a \
--hash=sha256:cf99debb17227a50620aee16647bb33a0387f5fa5418d628666c0f05745e0d2a \
--hash=sha256:cfbbba4597f19ad717f79fd3f2a67ae7efae647bd6a61e14554e1b5ad242a5bf \
--hash=sha256:d0acd8191c0e5a61d1c27bfa33b6ec8431982299f5d71c02129aa4f16f182ad0 \
--hash=sha256:d0b6a9bd86f865ebc9d847a1eb0a655a0e2b447cbcde743dda97c4298415cc0b \
--hash=sha256:d0f943b53bb1d7389d72a5380078670e5fcc34a1328142148b72d20fd82031c7 \
--hash=sha256:d48795c7d64ca1c42e3d61fcc6478cb15a19b6ad3f9c882bc8d8dee49d4a420f \
--hash=sha256:d8255971f6789cf0cb365e3e22b9b166eba978548a26241eaa5b7af0440d885a \
--hash=sha256:ddab54dc0ec46ed09ef9ac131252cb5740ed21fbe6fc145f3c6fed0b575a8f15 \
--hash=sha256:dde9cd67f18803949ebf96de8aba12b8ec5ee3115e34c75a2db85a3b0a6c20d5 \
--hash=sha256:de29795f23833cdfb68ba45c8a5cc0ec49778ea5deb670188f4465bba5930d25 \
--hash=sha256:e0feb03a338f8f5e819ae23a73aabb7b46fd3b73f15f7df782dd12d99e2b02ad \
--hash=sha256:e30550965c78223439815dbdf40c93eb8931dfbf12427110dcfcaeebef76feb6 \
--hash=sha256:e3e80cad85ba68c07c1e8d4ccc9cf51e63bf6a73d6bf631640be947bd72b6b63 \
--hash=sha256:e4beaef2f4796558e738e15ca0b8802e35f419a9fa374a978e41706f43c48b26 \
--hash=sha256:e6d2a185ec4ff0478089305abd833da3a9fda8803eb77325b89ebeae5585a3b7 \
--hash=sha256:ed7fe197b8bb66eef4f62c052e33752d456d2fdda74805469d4bd954950ab339 \
--hash=sha256:ee48728a07566c32e097d267f4d4d01b85123c9ae748a42da02185b908cbedc4 \
--hash=sha256:ee6c4e0085bff5f6621bf9c53452584dcb91ebd993ce841e1f4061ac12b6b556 \
--hash=sha256:ef03fb4b3685df0ed9dc6a074a090f030345cad2c23c61818da3e08e693a9caa \
--hash=sha256:f01a680d4b66fd15cc7513fae55c673cc8cc340d41340305b7f9a782abdbefed \
--hash=sha256:f0494d3d97502e270282cc6a1f8648cd7335b4fe8d5c452006e5b7f9d62b8892 \
--hash=sha256:f24bed98595b9d854da8d6debaf82754abf3e8fe63ec90505ef560566814df7e \
--hash=sha256:f42671900e0b602d05a074c52fd3d757c2f8e5c4f73f771794dae1aa4aea5f0e \
--hash=sha256:f5b1d315a615cec81a79e2ce3a94221dc5c23e7fd4012897085d3b5e5a5638d0 \
--hash=sha256:f5f06f59e19aa0770aaf651ce91c196fa620b35aed49a7e6c36e7335f3f83db7 \
--hash=sha256:fcac44d917672ad6257ad64b80b5168306f168a78cab5c0612e4c699caed18cf
websockets==17.3 \
--hash=sha256:018fab26140ce221c3853454a608e4e7004f4f10641cb97819dcd5b917bb2e99 \
--hash=sha256:07246d4f0293ef0b87eff3d7dd88c1f03dd9f678fa39f6de87b2af8504e7e0de \
--hash=sha256:078d1d41f45ee34eed5a4f3bbe7c588caecbdd6e12dfca73e8c1b0e803773793 \
--hash=sha256:0824e6ecee838cc28e6481062574c7fde49f9a2cedfacd36f0e91cb4b37fd6fe \
--hash=sha256:09f007b2150eff015b2109f006e2ac2012d376f41486defa88ae78a776b00cff \
--hash=sha256:0a0bcf66289b9d017c175562c35c5304b5cc3ed56aded994ae30b0a9654ba405 \
--hash=sha256:0a657b51e4a5f4ac577c11e706ff9a884ea5aaf3e2666bae283a251c63e66acb \
--hash=sha256:0c63ad657695e8f1a48624754cb6b464118ac50d4c1d477c26461c98390f0a62 \
--hash=sha256:0d20d6ea5aabbeba2e054d33e405192ef75dc12947bbd00ec97d23b14969d325 \
--hash=sha256:0e65260a1b1d7b81651f47343d836de70b88b02358ae3658efa6382104ec37b1 \
--hash=sha256:0f78bb2e82fe88912c9d7b25c98e57a9b08655579af89f164fd4c0657a075d62 \
--hash=sha256:10b24e836ee0233ca078e1244f6ba40343a22127a9a736f46a7e7b18de2cc711 \
--hash=sha256:13cffaedde6e06183860fc92d88fe1d190abda73837fe4c14f5d4803c472f5dd \
--hash=sha256:13eace1b315345ebac5b27821f5dcce24e5cf9976ab18f79e00a59bdd67e5d19 \
--hash=sha256:15decc0fe293d9e3f924bd483f3d76f3d0ff26845112a470e3f8842fec2c82a1 \
--hash=sha256:1c7dd93a1c9f89297471493674b1fc1d9467cafd45374f2172213046bdb3a329 \
--hash=sha256:1dae5cd6c92d4440b15f20aa2987baa73c47ea14baa0fec8536a542e82e0ab33 \
--hash=sha256:1db2604e6aedb7a2cb2f6e0575d6c9a852ccac8239703a930ac83b63309177a5 \
--hash=sha256:2129c9a5fc05a230ce088745a790af073e582b584badc7b05db067ee326f56d7 \
--hash=sha256:23046098ebf844753cfd211033624a8247520e5bf2194c24cb1a8c222917acff \
--hash=sha256:23cb6f6d64e3a389bb8ba150f947f9a6c8c0aca383e814ca3c5cffab738d5646 \
--hash=sha256:26838e2d95d7004c52e8c7b6b51676c872093a3b55a497824f899116a15a8a55 \
--hash=sha256:2789d203babb6ceb2770aadc2394c1f99263ec37fba57a93064f9a8ad899e8ff \
--hash=sha256:28d1935c16782a1e3650c9baa79069b016fff739e292e4cb14bbb830d6930491 \
--hash=sha256:29b01520c39ef2f23c88b002f11e6ef4165675f6c92f5f3578fd587d69b5a5fc \
--hash=sha256:2a377c7132b1e69be7a50d7434d7f26f69e93c70166ebb6d8f8cabf802ac4506 \
--hash=sha256:2b06213c8e1ce93b18d0476d7a5e647436c8f23d099888c9065e930e80f4bed5 \
--hash=sha256:2c460aeb12c2bd1c204944d9e9199595bf9e505eb542018d304bf9e63cb60cad \
--hash=sha256:2d08ca4bf5a9cdb6fd81b86b51bd5cfb10527d3a1199888f2b02cc6c6a3d5f80 \
--hash=sha256:2d875224bac1a05a20acade268a7a0e3498e7f8cf890acb7c2b23bacd2bd3659 \
--hash=sha256:2e99440ef446c7833690c1754e23b0188d440f3cb89812b0764c697a7880cb33 \
--hash=sha256:2fa79b9a48ae59744316c71a34cb9f76f30c93e117338522c5135cb7eac10351 \
--hash=sha256:32029441af953e980b9940f042b337fe4ad9a97fa8b17a4ed878ec67b5b89ef4 \
--hash=sha256:33221e49be79d7bfe6d12bc52ef9458b256ab74fa8ac5660acfa3065de1c7870 \
--hash=sha256:34c78052277053bcb09810ac8e9ba4029f9e3e277833fc18ec1c928a6246ac91 \
--hash=sha256:35381b575f70a08d4241e73c0cde4672bb9b2a9aae8767ca6b7fb61305a052c8 \
--hash=sha256:35fe35d20baa661cef4a12ee7bc42eaf2376d43ef9816ab29dd47ca957f7a73a \
--hash=sha256:39f532fa0d9026de4b9315a175998646112776baad54d55348435c11b05d034e \
--hash=sha256:3c4f631dc8d00e470cde3ec0a35d4b58a817bea592411956f1cf4099dbb306b3 \
--hash=sha256:3d78d93846eddc990551c1c31914d90d71957ca3af468969826f7ed0d7d1d51c \
--hash=sha256:411aa0fb234f42a1444dea1e177890ddfc577b36ffdfafec25cb0d2c818e1af8 \
--hash=sha256:41665c7ea01d3ae497a0c61fd22d3424230d18782a5fceb79f04db9ccb2042c9 \
--hash=sha256:4170556762c6fd2913d99dfdd8dbb4c927584899df7facb1034627e355263c45 \
--hash=sha256:43f270a5f21e12db08c73d83849a877c02ab7b7d0fb6e2718b5101d9c810212f \
--hash=sha256:443fa28652682d2a3ec3eca49af1b87cb2523561257683e62e03a98967b22138 \
--hash=sha256:45cc1ccb12ced6d242335159e8221733c8696da5ad0b6ceef6debb0f5ce89110 \
--hash=sha256:46ae05aa1aecd47d4d7de0f05ce2d1d2eb418f8de614964d754cc3b9a409c400 \
--hash=sha256:49fb5b4960ebe1bc557b435da8687deef1302a08f030a33c5606fa6fb11b773b \
--hash=sha256:4a9133dbaedc6f1af358127275676171d9a1bb3e61f47ee62b2ff9acb78af3d0 \
--hash=sha256:4aa85b34c21cf97b3470793d0bf0763d32bfd1e67b83067a0a3ba8dc3474dacf \
--hash=sha256:4d5f2492cb2192aab2d42e57f2caa2159b4fd20fde06f859ec13354f524b176c \
--hash=sha256:4e7b5d23ef144b32645d97bd99f382c4394c443395f45fe1576786838d26e308 \
--hash=sha256:4f7431e71072962d3ed1768038200aa4f1e76d9c2d7bedd554d57a55faaf6644 \
--hash=sha256:508775efa11d26aec186d10154359f52276e2baf9ca201b52356330883276dfd \
--hash=sha256:5142798871a248b422f353e0684d51dfa119de3403a6fa0904b7cb806d9790ce \
--hash=sha256:52a2ca6f401fb49a8d5d9e0e48ade5f58f1bdda33132907b0e4e3b702628fa4e \
--hash=sha256:53209dffd91b0aefed9ea630fa6ad5c2944d6210ba3a8a3a8664dc1575289b14 \
--hash=sha256:534ed583fd4323de45d196535a444cebd1af2105e6e4e0cdcbf8cea266a8747a \
--hash=sha256:54fcd24944e6d127d198c28dc363967b7131ff0c97833962c2ef2048018de02d \
--hash=sha256:55494475206113dbaf731dc8c5ffd5e1094175b753b7bbaad09fe3d7df61165c \
--hash=sha256:5670a762c7ae388bf8aa04199fd436180a4d28318dca9c1eae7b38604676dbfd \
--hash=sha256:56a76556ab04ab54a675acce2cac8b4e74ea2cec558a7c9ed37e0367b04b5d50 \
--hash=sha256:56d43c311f3519fb1057b6114dc24e9060bc3fb6aedf4aa11160484154b66b63 \
--hash=sha256:5868a02c4f6d698ddd19b4c9742748c03dec045289915806845189d96bc3d314 \
--hash=sha256:58e5d1e935a90878a935c7d2737a25c71cf4f1c13b6e6bef454ab722c4f338bb \
--hash=sha256:5ad409b7ea102339041281117cf2dadfe71edbb653dc48037cc55d516fb7f448 \
--hash=sha256:5af7070d80d278832cbca9c3c3dd44b30a26dcfa3ae1e0f6f19ff34edc27b689 \
--hash=sha256:5d0c871efc696ef5eb8514df64b86ab28736db753ebb42a2101f3b562f4849c0 \
--hash=sha256:5e0c0ed37472c4729f3001066510a656486f08f149dda1ebfd3dfe4450c9756e \
--hash=sha256:5e1c174b366565e101f903f9d1cc96d5508f805759dd37d012743f1c73ec0d7b \
--hash=sha256:62059d739af7fc035ed6e63c5390118a60a5e9aa5a5541cd0486a83e741842c7 \
--hash=sha256:623d4b44f64efdf235b1e8dce266057073d93cde6197e7d7684f20c297f67f30 \
--hash=sha256:628efe13630ac3397e7d1278b6be6f22f37a86d638a324334b4cd43c1daf9928 \
--hash=sha256:6342f79d6f50e680c8aa59e0615d745e867e51ffd59c77093be60b7c433067af \
--hash=sha256:63b87c93e28957e6dc2bb92d31727a863c9bf4a4daa080f0995fdcb0242c9166 \
--hash=sha256:65e937576141ac50fac32fa9736dbb3e0e4a7769f91be004011a09216c6ab05f \
--hash=sha256:66027e401c70d0cf55021b91b8a7ec2cd5810e20602f945b4fe6ae8b37ed232b \
--hash=sha256:6644eecd99c4e8cdf72e646e17b391bb70b054f44becde37dcdc48cbec7e1527 \
--hash=sha256:6705af9d1005127302c04d9f1533ba56e289336c465923ef878430e99295a0b9 \
--hash=sha256:6a8248b1ba8861e48e4c7ced3895a1264d2a3b617de72ec94172ce6e64bf16c7 \
--hash=sha256:6b14914e67044724c31a9360c7b89e9d070117c630746eefdc1620d967545acd \
--hash=sha256:6b7b540bb321f7f0a7b8f5d107f941bb361e3a154c0b594dae0394997b91b743 \
--hash=sha256:71250e010eede33c1d638e2c7a98288520d67f782fd5eceecaeca3129233a09a \
--hash=sha256:722ab747ff5dc28070b1a8c020dba6466f13f2ab56bc251ad301fefa2454aa1e \
--hash=sha256:724224d4c457207271239114bf43afafc3eca4a1b4661ccdd428d11869a03bbd \
--hash=sha256:729989759feb81ff6493879a0d60a0bd7d2eee41001bbec0381a080318439382 \
--hash=sha256:740bba4223fa5216d4d6c5dcd29e697f37229b8a61b69e1a50527b0ea993ab2c \
--hash=sha256:7bdc658c9474864893e0b6b94f1390bf6a912952df1870dd93bb7d1a902b5628 \
--hash=sha256:7d53fc4b90ef6e11de639dc18744d9be8cbd70ccb5ce80027aaffe7b1ab0215a \
--hash=sha256:7fa69212ea60ea24e2d8aff23fe102b1f87f1b27a320f92d2e7b3468997a496a \
--hash=sha256:80326bc571164bbbb6bead2e35d0c943b23b24fde629032197c58151529d24d8 \
--hash=sha256:80578e91764bfca297ddca322c00a3136d993b829e9839e7fa378a19c1fcc25d \
--hash=sha256:80a6e37e235780f189558ab804f3cbc01c18f5c578995739b49613d544d34ebf \
--hash=sha256:8135a549e27e9941a70e2d2156676ef2ffeff4b06e9d564dbaaae963482afdef \
--hash=sha256:82e60c00cfb8493a5ba27cdf9b3695fdd153f666f73e11f18968f78ead1d8705 \
--hash=sha256:856bbb24f2ee6436af7609267e73309e4bb0a0f9982f79f1c2e01019279c6671 \
--hash=sha256:85d6daa3a7ca404570ae130babbeb347ef9d3faca5300fb13cfa4bb48c3d30d1 \
--hash=sha256:8879b6a4040ee925c638548238ab7fe612cf5fa8752fe847346da0da8be81c3f \
--hash=sha256:8b3bede7d583bc9f47d8693a29984882e59077db1a5238ad977fc70ae8169741 \
--hash=sha256:8dbb3862aa649de95660b6337d97101977f160b5b354d07b82fe309874d2c8bc \
--hash=sha256:8f244dfee05ea29b8064701880865eb1684f3a704a5665bd10b64694444dbbd4 \
--hash=sha256:8f7469408740cf06a79b01605f2ae0b2acc8839c03fcbbf05da49baee12d3302 \
--hash=sha256:90cc9973c51811918247a78d9ab2f54871296e4e37e69a98aba4d3c9acedbf62 \
--hash=sha256:90d8c4fa5ba293cf92de351fbc292cdaadb1a1d58d031a1a97ff9b8fb6250ec7 \
--hash=sha256:94c02b0702656f083c098bdbd93bce22a7aa7a2b34ba56d2472efb67dab7cf58 \
--hash=sha256:9662a9fe457820c60365b3209e03cbd8e4a817195d55de65a80fa680b4bea136 \
--hash=sha256:997617dd7856c5dad742bf6893b872319156dd43f47587541a59e4a852d52bbc \
--hash=sha256:99c5637b74e2805ee4de9e2a43c8b45f678e50abb1c2da9880f0372f6498ba2f \
--hash=sha256:9a215749c9a88ef2842e880215193e56ae60b856773c99702b078236bc6d4adb \
--hash=sha256:9bde5d82d7ac4859e0cb3a35e148f537a8d4e56aa43f42582b5f263982f095ae \
--hash=sha256:a004c1fe5a72c496f28c6c1d8c2dc5cfe3278d99478e18f8b838c70a912b366f \
--hash=sha256:a0e2e7c2c1a4f25db7b6596738d810c10732e77f852247300a1bc49e364d6dc9 \
--hash=sha256:a22c4956a4d858200dba83f0691bb692d77b0eeddfca80157820d20b85dea4f1 \
--hash=sha256:a7f391838e8adcf1f2fe71561d9e5a9f74ea7ffa5052eb2db329aac677383136 \
--hash=sha256:a9eacb382f400bb5865e7e6d24bbe709a84510291e707f169dd4a24ee4a5ac6a \
--hash=sha256:ace8dd1efa5f44c482d091aa38322e20e3ffe5adcdba6b67ad9f4e7da58f3f68 \
--hash=sha256:ade76f8c84ade325bbed96806357fffd353fcc29a5166d6dc6d39381f6d9f76c \
--hash=sha256:af37a1e6b6bd506b597d5fb4cf111fb527d1b2223608a5d441d4738827cfd166 \
--hash=sha256:af7c474f0d8f4d2a196370e85033873c7b063a0b5da9a4f143aa023e3bd25407 \
--hash=sha256:b225c656efa2dedecc81651d2290170af25887b7de4f38c5efc7c5ae2b9442ab \
--hash=sha256:b459d29c8b82a420a98fa0ce8e9cf787ce0062d98cc90604ef9574fb3cc26ff8 \
--hash=sha256:bc6f87d03e3691154673aaa8f08991723d6e3394c83ef2875c7a9049eac9595c \
--hash=sha256:bc8fd230ef013951900c1fda100eebe4a4b1b407dde2a44186995042dda2c628 \
--hash=sha256:bd645b5d2f810a181c44f4a71135e7c365b44f4be9ed3d1892635be13a857553 \
--hash=sha256:be7be57097a65a8fab3d0f0a10d12931deb626a7d8082eb732b1ae41f3a202e3 \
--hash=sha256:c15a165673bb3fb57facbf040edf5c0556d20ccd2e0ccc5f23ebb69fb715fdc1 \
--hash=sha256:c4b3f2c7d84f303da873b634d0beef83b5e1137294c3de4e23102841dac0cf4a \
--hash=sha256:c534c9524a2acd0b97b7022074bec3784ac273c683cf9535087e437672ea8531 \
--hash=sha256:c95d25b5382ee0e6191ecafdeabefdc1f7bff8dfee29239b9b79e760ef3b04bd \
--hash=sha256:c9d06edfd974e918b40e0662a7e76dac13125529ee5ec9fbe42dc0d6faa209c3 \
--hash=sha256:cdb8e4b0f6a41b857c74c03116e8ffbef59ef8e533e934b532843178990d01d5 \
--hash=sha256:ce39283ef08b0f28478e920d4d89a1fc169176e568e8a6a821332673145522eb \
--hash=sha256:cfef7f7aa434a1e632e0ebda14b39f4f1d7975e0fce5c77ea7b43156fabf9bd8 \
--hash=sha256:d2605a3b2af8d66f8b75312d223642c065ec773446c04566d9030ad5e2db13c9 \
--hash=sha256:d338813a440bf6d2f0df55140d3f3080284410b1ebfe9df50e3847bcdb1a17bb \
--hash=sha256:d355b22270be8062360b9df2ee0b10277590789a1059257916fb9e256a0cff80 \
--hash=sha256:d68da281ac208b6236ffa8beef23fe7c7c956d8bf09b421d447232fd94441b35 \
--hash=sha256:dafbb58a149d1ebd5767b3f064f911c5ee0897608005e51c3904b0ada2a8d99c \
--hash=sha256:dc2b495a92b3971966bf102e73589f950db3ec1ca6713265355ce7771d97b199 \
--hash=sha256:dd0f3037d501178a761fd2814370aca547f79e99a200a61a1f6e7b79ec3d78b9 \
--hash=sha256:de2c12555bf05546f3ee75733f2c81de70aab7f530e86d0d2162b0ddcb3c39ae \
--hash=sha256:e164c4a6868d11988c7f2386e3278ccff21c665cd7d08279b62709dd37a3167c \
--hash=sha256:ed59cb4ee258674a6ed9b8515e42079db02cb3be94f133fdd3f200183a40c49d \
--hash=sha256:ef07e0b6b879f699a16fc7a513b974246fdeaef44908a021130cf4afe6a1c89c \
--hash=sha256:ef2950896673a9809e8e5ab857525924fbcacfc98b858b0509ccf50d341f80f4 \
--hash=sha256:f09f145b89ea292cf6c25fd7c8c0d90207fd6a9e54c7828499669996a1e5bdcc \
--hash=sha256:f27e7e8a85512b6a4b490d5756edde8e6772883a5800e1476172e44eda3f7d7c \
--hash=sha256:f300f28dff74ff4148c21e6971e4de6ca0c34e0086a3d95c017c5174ebf85ca5 \
--hash=sha256:f3ed747b7651668131029c720fbc32c7ee2d129bdad200e6c8f4037b20f7913a \
--hash=sha256:f87f02afe05c1c246012e3de100a77cfbabd17db709fe93cf074271ab239b312 \
--hash=sha256:fa87ea2ad64e59fe5622c1dc5716106b6d6e7e4b26b848cb5f5710a75c292ef5 \
--hash=sha256:fc23e72bd7f8a8e540fed2244524d0a9aeb6ae3325f3d56f04a7a3debe5b04c2 \
--hash=sha256:fdd00937f15f5f93c8e53d8060a8c4c010431ab595a9b5b50ddd569a04603944 \
--hash=sha256:fe7a168d805c8a7bf1c2de55b7ab2bc958586bfd88d0e87235a92cac66b590a7
yarl==1.25.1 \
--hash=sha256:0136d640dfa9b0523853e411430a99f8a91eca85774c6420285a33b755bc6de3 \
--hash=sha256:03dd38de09bc213e9a8b29761eec33ee1d5318dac0e49d8af36e4d27830e23a7 \

View File

@@ -789,9 +789,9 @@ multidict==7.2.1 \
--hash=sha256:fc45ff19520bc5321dcd9c6dd7df6f35ddd894eed35e5be65d1828a9c3f5e7fb \
--hash=sha256:fcfebcb537f419e415b6e2bfc77ddbd33abe3c036f0105410a25a14741df9c31 \
--hash=sha256:fd24c4425fdb8e822601335602375c6d0cb020f7a368e1d5842eb7925a9c8748
oauthlib==4.0.1 \
--hash=sha256:3d73febdb6faa00f277c81fb04be7b7586fb96fc3b7f0b9c772dada69a25ede7 \
--hash=sha256:498a298876e996301950a5b053d12c31628bb7b895db03666430c69ce182eb61
oauthlib==4.0.0 \
--hash=sha256:624c28c13a0a59cabf9747dfa52af63be3e512a7f2714df16e91b5b3a145e6cd \
--hash=sha256:efb274799819440f95b4ab3b818869f1ce9ae26c5beacba0201d1a1b76b54f86
propcache==0.5.4 \
--hash=sha256:004e685b315646c410771836e72a44f143bbe624f29653a42687815069a303d5 \
--hash=sha256:02c0a34f16889cf800f10f0247a564d8ce6eeab6ffcd7c87198f769067eb8432 \
@@ -1082,9 +1082,9 @@ python-dateutil==3.0.0 \
python-dotenv==1.2.4 \
--hash=sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc \
--hash=sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0
python-multipart==0.0.33 \
--hash=sha256:8f16c07b36add9da6b2ee87d3efcaf0a45a6de9c3d0a5dd94e9ccf7675a7bc45 \
--hash=sha256:b8112424a6abd162ec08d390565dd113ad699f2fe6fef3c987b8bbcbfe9e390d
python-multipart==0.0.32 \
--hash=sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e \
--hash=sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23
pyyaml==6.0.3 \
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
--hash=sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a \
@@ -1285,161 +1285,161 @@ watchfiles==1.3.0 \
websocket-client==1.9.2 \
--hash=sha256:0fcb57545848be86992e128218fd96dd87a6769ffdb1a968dff79632b85604d0 \
--hash=sha256:e1a673830a9c7bfa47b1cd3d5e4178f4c9651d80a4eab02c9c23a1c3ec6250ce
websockets==17.4 \
--hash=sha256:00ad98e4bb0df7a6711c645eec16d5a9fdf99f0692bd4f5b6cb85a68677ba8df \
--hash=sha256:0132e3cbd3f5cfc1ec77588961b302d72a02e2603b82c2c23fd5fb59dc4fa206 \
--hash=sha256:023dc13bdc42a55e152acc81c39c90ec6cc4159ed17d23c6d73460fa2a73ab16 \
--hash=sha256:02f380df26de14999ecace203fe1396ac14d1c6132afc7924eb6f8c8b646c69d \
--hash=sha256:03ddf4eb76ced8725dcbb000ff60b0fb8d7330ed011f6dc725a1925c5fe02051 \
--hash=sha256:043945a43873c7c11a3f75238d475c95f902e967de329eb8763704546cfaa6b6 \
--hash=sha256:046ed16d3d83d64594e4a40655fef061ccf36059d8c30a01feca8a9481fe13b8 \
--hash=sha256:06ea46717553cdd10f2682126cf7a66e91c8ed17b6969f4a95e94b4e01d06188 \
--hash=sha256:09d3939b70df0c8ad2da145ebd50978bccaee1d565e838b0e7921a34d38571eb \
--hash=sha256:0a57b99f2e28922b5a2434317580fd23fdf118caff4c5b752f5452836426205a \
--hash=sha256:0c22a9c6b2349204f56123dd0ca7779e989d68e336d0dc02ad823485d44925de \
--hash=sha256:0dcce83837328e6795225ead920d3aa8d867cc9d6922aa558b0e9111599fdbb9 \
--hash=sha256:0e51546a3bedadd80dfa5c2efaed840ac51b8632d8db7f9f502175f5349382a9 \
--hash=sha256:156221ad7638b5abccefd6f798916bf3f8ffd6ac51480eb4ba5b05df914ccbf3 \
--hash=sha256:16550e24ac22c27e0a728100d8de196b5f054bab6748ef9f0b168fb8b3c32e35 \
--hash=sha256:18d3710becc612ec6f0229425bd6495133dfcbf30f7b6569585acc8ed2f1b452 \
--hash=sha256:1962f3bfde085af18878f1bb1aafb300c9a6ac33da886d0b0d97e33c9ce7a222 \
--hash=sha256:203e42eb77e06f85778a908b34c5ad032f34e98a68ef33920d6685c1e65a9420 \
--hash=sha256:2103982762460a764a7ef0021443bb471f46d45ecc6858276e4fe699ebac6b94 \
--hash=sha256:25eb661d8ba7e2b85ebb4e7a1bb9f6a3280910ed10b84330a7abfb5ed32d2764 \
--hash=sha256:29b615c2d5dd883f89c107a782681b73a7aa8b2bd894130310e45eb09b143913 \
--hash=sha256:2a9cb5bbfc33b4ebd3c8d3714d6e09805437f60a14977774e4bd11b5ace46c23 \
--hash=sha256:2b23dacf7a8a88afe92f77bcdbf4cf043a84692bac2f2da02f4011c687e19b48 \
--hash=sha256:2fd562372d4afaf18d1c7f1c68e39bd32818bb16d5f57f778a4a4ed88eedcaae \
--hash=sha256:32110d954d9d0e51f36edb0396673bf4d35193a0a80ba7013bf7f7d58a33ca07 \
--hash=sha256:332b88022d0acd47c44158bcd43f47f14eaddcd979247f242b1a33291c45cdd1 \
--hash=sha256:361f9a21a33191d5287e7a75f508fc3b9bf47aaffb0241198d6b7be3384f294e \
--hash=sha256:37ed7782972545e67d97ef9a172e9499d25459b1e32cb99d1c2a30c572f2441b \
--hash=sha256:3acc45494c08a4d27375a2c28474537f68910219f42624a08011221b04623d04 \
--hash=sha256:3b76837cd051d8875913f3934b27205f7a592f78b8a4f4a1f3abc36a2420c5bc \
--hash=sha256:3b78b39377630a70aa2198e5f03be416e690364a046b1d8af80a9263733083d0 \
--hash=sha256:3d27153a0413696767b98b5d96173a2a7e27cbfca02000a6069cea7b977765a7 \
--hash=sha256:3d512e3a6c528c42ce220ed9c3caff83c6fdcd98a1b98249f08ccfc66ad111b1 \
--hash=sha256:4073ab7cefe5a2e7dc368c1f01eb27716dc8ea8f1c69e9b7725ebce05aa53cf7 \
--hash=sha256:42d7a6e818214336cf7af9a3aae5c6923f94f09fa07ac5aab98268ba2a98a6d5 \
--hash=sha256:4441d655a53185ef1b01b1d42ad9b3a96b905110a9219043e3fdaec855ba3b6e \
--hash=sha256:47beedf07a706140b50786457e082497ee6b5970c41e49bcd1572ee3f4c73f80 \
--hash=sha256:48c83103f82fce36191a9e3a8a80731d4340e2da544eae8c5aaaf6a45280e7d0 \
--hash=sha256:4b79ea31cf277c72d2307c6cb8bd32a2c151959e80a2f24fa85df620c5f2860c \
--hash=sha256:4c792e6cce24d08f92199d907785c9e64f74c357deeed3dbaf7d699ed5930b64 \
--hash=sha256:4d2636a5b61c69e32db0e74b57073dd4a66f1ad195e9398c5f01bba41090deea \
--hash=sha256:4fb2db1f649b6464711846b5bb9c1611bd906ce939d9460cbd1fa419552cd6c3 \
--hash=sha256:506623128d7a55b726a5a46e4c9a8eae4c9dd0f04ff60b041fe7df85b9d034fe \
--hash=sha256:51adfc30f467077293a6695d8149bcef501c0728386f3a491054f835dadb60b2 \
--hash=sha256:52c31d123f5adf14dec694c2a4036bf42c523df7cefc641d31cd05653de56e49 \
--hash=sha256:5830f94a7190a33e55d06d89242ea951ee2009c3a27fc31538f3ac9386b27edd \
--hash=sha256:5cec3e7fbc911ff4fcf43b24aaf1b96906381ad36030f42897def3ff4b78729e \
--hash=sha256:5da7f7f1ecf866186f195f7ecc374c915e1838496b86f2f3b41da27c798a25c3 \
--hash=sha256:5ec906bb21b35e66cfdcc2ea0133f249f52b7d89e3e45ec8d2bd2d84a0255d7d \
--hash=sha256:5f772007dfba8941873dbd276b6a6845428cc740888b5c6c37bf483b1ea34b42 \
--hash=sha256:648adde345cfd13335342e23cfe94871c7f7f55a43fb254f3b95acb071072968 \
--hash=sha256:6531540aa63e6864cb0615a3a5da70ae03191334507852a5385320bb7916df3f \
--hash=sha256:6597a1f7413189b4bc58437babcdf39b79da416e5c477ae98323a88ecc108188 \
--hash=sha256:6686d29eaafddeeab9e48af92103dc0d26161035faa4be083b8b488f1ab47219 \
--hash=sha256:679eef0123861ca381dd8fd9bdc1920e87636ac55eae6cff875c53dcb05fbcf8 \
--hash=sha256:6afc32a7a1a40b071070419537df3559d26907086556769683fa97b7b6e90fd5 \
--hash=sha256:6b061ea7ca94966af7cd7a87cb189ff15972c103244611a2b1e8408c04f1dbe6 \
--hash=sha256:6cf4c002268da5c11cae9083aec71ac943bce9d95e0f83c8bf9a95a3ce421fbb \
--hash=sha256:6e6558efbb256b532c9f06a21ba42bcac729718e365c505819f181f25e5c0eca \
--hash=sha256:6fd8cac4907fec8302726d49e6969acfffaf720bc39b1cee23f473b81f4dce01 \
--hash=sha256:70293c25d79d1f084fdd665894481547575e429d2a75e8d72caec2f6b6b07af8 \
--hash=sha256:71f76bb8e59be847330b8a8d3753f85397677e128f9f9692c215f8cf721cefc7 \
--hash=sha256:725be1aff55f1c873a79cea0f612df9dff21a9d2c2e05783665b824b8aa7c24e \
--hash=sha256:72d0a731eccf482d5661c6711abfcd5921f3dbfbbb0789061e1918ef4bc89c70 \
--hash=sha256:7390e060f830b3d132f484b21ac2783a2d227b682ef62bb8146e1c1b4ca0e45a \
--hash=sha256:73b00645316121105274fd266ed54a20e6514650126d399cdea39876ab1e7b04 \
--hash=sha256:74e46409666c358b93fce0d8c6f4cb107d8dd7cba1302a38d49adf6fa8193c7e \
--hash=sha256:75b32cf33ea40f945f226f97bc1d43151e1a5adff21f420b5e63c468b1a28114 \
--hash=sha256:769e4f7b090e10cae4c082e3e39b9458ec2444505df84953c16c0468b16539c4 \
--hash=sha256:7849a096d6fdba3f2bdf849eb89f2d233a24400c92faa3efb25fa8dc615b706c \
--hash=sha256:799c5a23126c9589cb10b6c6b54f9087246940dad20cd74bf3f06fc9ae3bbab5 \
--hash=sha256:7a7e9321822ca59ba56fa8744c3e3f01ef74d547aafe0d383d000d7a4d11eb79 \
--hash=sha256:7b23db4b469d9e051ac74d96db9bf61e27c9054de64f8263fefa32bf72867ba1 \
--hash=sha256:7b4ee34acefa9ba1333f02b817982f1e4127f6f9b975017a707c4e738d7f9fb9 \
--hash=sha256:829bcaa90be8737c132d9515d6a466e8528e3b3d050d3f3466f36ea94d3beb48 \
--hash=sha256:8588edf317fbe4f16a949bc5a6ccdd22b6e6fd5b4745d128bc40bccf31024ce5 \
--hash=sha256:868744c68e9342768888c7326604da2228c19bb6946aa46b5f9e1ac32ea8d40b \
--hash=sha256:88ba8a439b2bad97bb69c38db5bf0ec16a061ee834cf0f244089186ee803e899 \
--hash=sha256:8b45d40f07081b377f0b837ddbfba4a9ab4a89a7b569d3c095436564e767a27b \
--hash=sha256:8c00c5c49f80a588a2c4f99d519d2abed4ce26cdca11273041bc8b7e60af60de \
--hash=sha256:8c51ac7b31578a7275650f580aac985940985b6d2e57247ac6d5e07f2c936cd6 \
--hash=sha256:8d148b4b295224d3a19e7bd9f02ebe7344de254b3b2c4d0628ce42ade0bca119 \
--hash=sha256:8f32a6cb0b101170abc2d8053af1473a2a29ef2a06d7130994ee8455a50f5dbf \
--hash=sha256:8fd30d217a4275107667fe1d4f601e2d50c797d0727148cfbb384536d65f04d3 \
--hash=sha256:927d602fb8fb595a69e6b1ae998a6ec19851d0fb9391759456e6425090996647 \
--hash=sha256:94622cf24e80d03054ceb69a06a86c950e12fe993ed06b933f7895232cacbc3e \
--hash=sha256:954d43574f72be244b65f0fa61e2f814214b024f2ec849f487aa2f553f7c6e71 \
--hash=sha256:98f16db5e79f2605194c0f899d0532005bb12269e698bf96f62a5635bcf33010 \
--hash=sha256:9a4e95d56994a45ac76541853796720436ffe462957d0b1b89e87ff3d3b1627e \
--hash=sha256:9ae1429ee9e52b139167ed0169757806a27ed7307e942e8c62037a9184e9843b \
--hash=sha256:9e282f35ece8895b9fa5af406fc6a4cb42f01e1009525cf46641de584781c83b \
--hash=sha256:9ff89e36451a19775e7556d95ebfa4a0b24b84cc87565d6b5d0ec8ea82bf3f2c \
--hash=sha256:a0457561e8a87a6a3b509e21c35084d7d207ced262139de3f738e9676a476bbd \
--hash=sha256:a50bd9b44dd9b7b845802030b4d88610c01c7f95571b4cbd3a1aeec17a34c9fd \
--hash=sha256:a703f23ca15a51251fc94f1774683f5aa511588a7ad6bbb83960cdb2a4dcd978 \
--hash=sha256:a920e99155d75d1b1c08172da8aaa7200e7b30871fb628d1631d7891a333e30e \
--hash=sha256:a9b0026538719f7a532998d84640ab2e91ca1a051ce4b8d924fdcb607307e921 \
--hash=sha256:ab9e4bd60796866c578e3afa0a17c98636887827a39c2e238a61989c18fd8e7b \
--hash=sha256:accb5e9492b9bc9c9aeec5b72ea8f2ddcbefc6143d1c626fba960ecbdc89807e \
--hash=sha256:ad2e9e152bec6c4f7e4cdb4adcea6b708400090eec04bfe5ee5b30d368ffd721 \
--hash=sha256:adc30e5d064c9e33049e825408fa4e952f4e8a0cf4c329dc2ded72e1bb5bae08 \
--hash=sha256:b529ad6c81ad21db2f4e3d6e33db78ce3b9f272066b438b5d673361f9282898d \
--hash=sha256:b6c7f91520c29420639925fd1cecceac9ca07366b50c09ea24eac1cd116b4866 \
--hash=sha256:b7ea61af293a153f2d67430038cf0efc10140caa623f2bdf5a9f5a457ff20f57 \
--hash=sha256:b8451f31ae24620cc9372acd2728d87922f2bb0cae3fa57aed68b152844cdf08 \
--hash=sha256:bbb6bed49f083e2ec8ae0bb21c00c7c5171ab8e08a8b008c61a43fc6c944fdac \
--hash=sha256:bc581579885728bb54ef15000295c20e6a64a200b1b73d5cfca71879a3eb3e1f \
--hash=sha256:bcad49104711f88b2b7c3ba166de172857d837248205e541b044a552558fecc3 \
--hash=sha256:bfc86dff091104eec770c29ea1831dbe191968a70aa2d8ae8eda3240d863970a \
--hash=sha256:c00f0c45851a2c61efffd03dde8fb4d594026b5cc18196c94e15460f1225f2ed \
--hash=sha256:c0cc2cb47face4dae64bd70a9268dbebddb3e48c1b48cf6d7b6ac1471609fd88 \
--hash=sha256:c2db7b9e2d726f7e051bedb67abcf460b84b11437b2f9fdacda7e6931dace85b \
--hash=sha256:c44776f82b04e623eb9e1b81fcd17ac6e9808ae1ba5cdf8edce1f7c869a95a9b \
--hash=sha256:c564d1e6531611bf87078c28780456ecc75459dcca189629fff2fe7c020d8e67 \
--hash=sha256:c568e72f5425a74616daeb824afe28da460cbeea036432f41c6af5380b83300d \
--hash=sha256:c5e970d3996c597186c9dbb6e77a8048737a834ac03cb13186a54999e0e1c31e \
--hash=sha256:c634053459278cf31fb404ddb5ecd38124e4609e8b609166da621edc2d5796db \
--hash=sha256:c63c0d7832956d5f3bb77888b93c854569d13f806289ff75c43926d25c6e5fd2 \
--hash=sha256:c6bd2c9781915592b209160d0f017d4c7c82ad53075e6b0c24d2a89299e7f9e9 \
--hash=sha256:c74954409ea5789f7a60daa5f94580c00ad0b60b20751c47b35c4784877b5057 \
--hash=sha256:c7a56140fcbf4662cb263754a754c651a16fe2196cae1fd232d18f89acd30c83 \
--hash=sha256:c7b996c02de5e032cb63dc65482b73693b7ecaa586654126be2749ddea239c40 \
--hash=sha256:c7f66a53e9b7ec831abb15e3d9b6cee8f52d6a24cd0a374786bf46c3ec218bc6 \
--hash=sha256:c8052c3058c402d53602583da5ddcf1a15a63ab1efe0222f47c7be59944e6463 \
--hash=sha256:c9f8fdb7bbefc4907c2bb3593f810f2b67a2d5329e1d38724a1aa3d763cf63eb \
--hash=sha256:cbdf4b42f4514422051889424fd03bc269be8c5d751bf39ec29ad761590bd10d \
--hash=sha256:cc0cd4065a65ac98f3e2742ee9f314da9d224db49b07dc17d3a20cef0d79658d \
--hash=sha256:cebad8f4796248b91fc2168515e507e5cb6b663a32befd09f3b1e7920acdcb1a \
--hash=sha256:cf99debb17227a50620aee16647bb33a0387f5fa5418d628666c0f05745e0d2a \
--hash=sha256:cfbbba4597f19ad717f79fd3f2a67ae7efae647bd6a61e14554e1b5ad242a5bf \
--hash=sha256:d0acd8191c0e5a61d1c27bfa33b6ec8431982299f5d71c02129aa4f16f182ad0 \
--hash=sha256:d0b6a9bd86f865ebc9d847a1eb0a655a0e2b447cbcde743dda97c4298415cc0b \
--hash=sha256:d0f943b53bb1d7389d72a5380078670e5fcc34a1328142148b72d20fd82031c7 \
--hash=sha256:d48795c7d64ca1c42e3d61fcc6478cb15a19b6ad3f9c882bc8d8dee49d4a420f \
--hash=sha256:d8255971f6789cf0cb365e3e22b9b166eba978548a26241eaa5b7af0440d885a \
--hash=sha256:ddab54dc0ec46ed09ef9ac131252cb5740ed21fbe6fc145f3c6fed0b575a8f15 \
--hash=sha256:dde9cd67f18803949ebf96de8aba12b8ec5ee3115e34c75a2db85a3b0a6c20d5 \
--hash=sha256:de29795f23833cdfb68ba45c8a5cc0ec49778ea5deb670188f4465bba5930d25 \
--hash=sha256:e0feb03a338f8f5e819ae23a73aabb7b46fd3b73f15f7df782dd12d99e2b02ad \
--hash=sha256:e30550965c78223439815dbdf40c93eb8931dfbf12427110dcfcaeebef76feb6 \
--hash=sha256:e3e80cad85ba68c07c1e8d4ccc9cf51e63bf6a73d6bf631640be947bd72b6b63 \
--hash=sha256:e4beaef2f4796558e738e15ca0b8802e35f419a9fa374a978e41706f43c48b26 \
--hash=sha256:e6d2a185ec4ff0478089305abd833da3a9fda8803eb77325b89ebeae5585a3b7 \
--hash=sha256:ed7fe197b8bb66eef4f62c052e33752d456d2fdda74805469d4bd954950ab339 \
--hash=sha256:ee48728a07566c32e097d267f4d4d01b85123c9ae748a42da02185b908cbedc4 \
--hash=sha256:ee6c4e0085bff5f6621bf9c53452584dcb91ebd993ce841e1f4061ac12b6b556 \
--hash=sha256:ef03fb4b3685df0ed9dc6a074a090f030345cad2c23c61818da3e08e693a9caa \
--hash=sha256:f01a680d4b66fd15cc7513fae55c673cc8cc340d41340305b7f9a782abdbefed \
--hash=sha256:f0494d3d97502e270282cc6a1f8648cd7335b4fe8d5c452006e5b7f9d62b8892 \
--hash=sha256:f24bed98595b9d854da8d6debaf82754abf3e8fe63ec90505ef560566814df7e \
--hash=sha256:f42671900e0b602d05a074c52fd3d757c2f8e5c4f73f771794dae1aa4aea5f0e \
--hash=sha256:f5b1d315a615cec81a79e2ce3a94221dc5c23e7fd4012897085d3b5e5a5638d0 \
--hash=sha256:f5f06f59e19aa0770aaf651ce91c196fa620b35aed49a7e6c36e7335f3f83db7 \
--hash=sha256:fcac44d917672ad6257ad64b80b5168306f168a78cab5c0612e4c699caed18cf
websockets==17.3 \
--hash=sha256:018fab26140ce221c3853454a608e4e7004f4f10641cb97819dcd5b917bb2e99 \
--hash=sha256:07246d4f0293ef0b87eff3d7dd88c1f03dd9f678fa39f6de87b2af8504e7e0de \
--hash=sha256:078d1d41f45ee34eed5a4f3bbe7c588caecbdd6e12dfca73e8c1b0e803773793 \
--hash=sha256:0824e6ecee838cc28e6481062574c7fde49f9a2cedfacd36f0e91cb4b37fd6fe \
--hash=sha256:09f007b2150eff015b2109f006e2ac2012d376f41486defa88ae78a776b00cff \
--hash=sha256:0a0bcf66289b9d017c175562c35c5304b5cc3ed56aded994ae30b0a9654ba405 \
--hash=sha256:0a657b51e4a5f4ac577c11e706ff9a884ea5aaf3e2666bae283a251c63e66acb \
--hash=sha256:0c63ad657695e8f1a48624754cb6b464118ac50d4c1d477c26461c98390f0a62 \
--hash=sha256:0d20d6ea5aabbeba2e054d33e405192ef75dc12947bbd00ec97d23b14969d325 \
--hash=sha256:0e65260a1b1d7b81651f47343d836de70b88b02358ae3658efa6382104ec37b1 \
--hash=sha256:0f78bb2e82fe88912c9d7b25c98e57a9b08655579af89f164fd4c0657a075d62 \
--hash=sha256:10b24e836ee0233ca078e1244f6ba40343a22127a9a736f46a7e7b18de2cc711 \
--hash=sha256:13cffaedde6e06183860fc92d88fe1d190abda73837fe4c14f5d4803c472f5dd \
--hash=sha256:13eace1b315345ebac5b27821f5dcce24e5cf9976ab18f79e00a59bdd67e5d19 \
--hash=sha256:15decc0fe293d9e3f924bd483f3d76f3d0ff26845112a470e3f8842fec2c82a1 \
--hash=sha256:1c7dd93a1c9f89297471493674b1fc1d9467cafd45374f2172213046bdb3a329 \
--hash=sha256:1dae5cd6c92d4440b15f20aa2987baa73c47ea14baa0fec8536a542e82e0ab33 \
--hash=sha256:1db2604e6aedb7a2cb2f6e0575d6c9a852ccac8239703a930ac83b63309177a5 \
--hash=sha256:2129c9a5fc05a230ce088745a790af073e582b584badc7b05db067ee326f56d7 \
--hash=sha256:23046098ebf844753cfd211033624a8247520e5bf2194c24cb1a8c222917acff \
--hash=sha256:23cb6f6d64e3a389bb8ba150f947f9a6c8c0aca383e814ca3c5cffab738d5646 \
--hash=sha256:26838e2d95d7004c52e8c7b6b51676c872093a3b55a497824f899116a15a8a55 \
--hash=sha256:2789d203babb6ceb2770aadc2394c1f99263ec37fba57a93064f9a8ad899e8ff \
--hash=sha256:28d1935c16782a1e3650c9baa79069b016fff739e292e4cb14bbb830d6930491 \
--hash=sha256:29b01520c39ef2f23c88b002f11e6ef4165675f6c92f5f3578fd587d69b5a5fc \
--hash=sha256:2a377c7132b1e69be7a50d7434d7f26f69e93c70166ebb6d8f8cabf802ac4506 \
--hash=sha256:2b06213c8e1ce93b18d0476d7a5e647436c8f23d099888c9065e930e80f4bed5 \
--hash=sha256:2c460aeb12c2bd1c204944d9e9199595bf9e505eb542018d304bf9e63cb60cad \
--hash=sha256:2d08ca4bf5a9cdb6fd81b86b51bd5cfb10527d3a1199888f2b02cc6c6a3d5f80 \
--hash=sha256:2d875224bac1a05a20acade268a7a0e3498e7f8cf890acb7c2b23bacd2bd3659 \
--hash=sha256:2e99440ef446c7833690c1754e23b0188d440f3cb89812b0764c697a7880cb33 \
--hash=sha256:2fa79b9a48ae59744316c71a34cb9f76f30c93e117338522c5135cb7eac10351 \
--hash=sha256:32029441af953e980b9940f042b337fe4ad9a97fa8b17a4ed878ec67b5b89ef4 \
--hash=sha256:33221e49be79d7bfe6d12bc52ef9458b256ab74fa8ac5660acfa3065de1c7870 \
--hash=sha256:34c78052277053bcb09810ac8e9ba4029f9e3e277833fc18ec1c928a6246ac91 \
--hash=sha256:35381b575f70a08d4241e73c0cde4672bb9b2a9aae8767ca6b7fb61305a052c8 \
--hash=sha256:35fe35d20baa661cef4a12ee7bc42eaf2376d43ef9816ab29dd47ca957f7a73a \
--hash=sha256:39f532fa0d9026de4b9315a175998646112776baad54d55348435c11b05d034e \
--hash=sha256:3c4f631dc8d00e470cde3ec0a35d4b58a817bea592411956f1cf4099dbb306b3 \
--hash=sha256:3d78d93846eddc990551c1c31914d90d71957ca3af468969826f7ed0d7d1d51c \
--hash=sha256:411aa0fb234f42a1444dea1e177890ddfc577b36ffdfafec25cb0d2c818e1af8 \
--hash=sha256:41665c7ea01d3ae497a0c61fd22d3424230d18782a5fceb79f04db9ccb2042c9 \
--hash=sha256:4170556762c6fd2913d99dfdd8dbb4c927584899df7facb1034627e355263c45 \
--hash=sha256:43f270a5f21e12db08c73d83849a877c02ab7b7d0fb6e2718b5101d9c810212f \
--hash=sha256:443fa28652682d2a3ec3eca49af1b87cb2523561257683e62e03a98967b22138 \
--hash=sha256:45cc1ccb12ced6d242335159e8221733c8696da5ad0b6ceef6debb0f5ce89110 \
--hash=sha256:46ae05aa1aecd47d4d7de0f05ce2d1d2eb418f8de614964d754cc3b9a409c400 \
--hash=sha256:49fb5b4960ebe1bc557b435da8687deef1302a08f030a33c5606fa6fb11b773b \
--hash=sha256:4a9133dbaedc6f1af358127275676171d9a1bb3e61f47ee62b2ff9acb78af3d0 \
--hash=sha256:4aa85b34c21cf97b3470793d0bf0763d32bfd1e67b83067a0a3ba8dc3474dacf \
--hash=sha256:4d5f2492cb2192aab2d42e57f2caa2159b4fd20fde06f859ec13354f524b176c \
--hash=sha256:4e7b5d23ef144b32645d97bd99f382c4394c443395f45fe1576786838d26e308 \
--hash=sha256:4f7431e71072962d3ed1768038200aa4f1e76d9c2d7bedd554d57a55faaf6644 \
--hash=sha256:508775efa11d26aec186d10154359f52276e2baf9ca201b52356330883276dfd \
--hash=sha256:5142798871a248b422f353e0684d51dfa119de3403a6fa0904b7cb806d9790ce \
--hash=sha256:52a2ca6f401fb49a8d5d9e0e48ade5f58f1bdda33132907b0e4e3b702628fa4e \
--hash=sha256:53209dffd91b0aefed9ea630fa6ad5c2944d6210ba3a8a3a8664dc1575289b14 \
--hash=sha256:534ed583fd4323de45d196535a444cebd1af2105e6e4e0cdcbf8cea266a8747a \
--hash=sha256:54fcd24944e6d127d198c28dc363967b7131ff0c97833962c2ef2048018de02d \
--hash=sha256:55494475206113dbaf731dc8c5ffd5e1094175b753b7bbaad09fe3d7df61165c \
--hash=sha256:5670a762c7ae388bf8aa04199fd436180a4d28318dca9c1eae7b38604676dbfd \
--hash=sha256:56a76556ab04ab54a675acce2cac8b4e74ea2cec558a7c9ed37e0367b04b5d50 \
--hash=sha256:56d43c311f3519fb1057b6114dc24e9060bc3fb6aedf4aa11160484154b66b63 \
--hash=sha256:5868a02c4f6d698ddd19b4c9742748c03dec045289915806845189d96bc3d314 \
--hash=sha256:58e5d1e935a90878a935c7d2737a25c71cf4f1c13b6e6bef454ab722c4f338bb \
--hash=sha256:5ad409b7ea102339041281117cf2dadfe71edbb653dc48037cc55d516fb7f448 \
--hash=sha256:5af7070d80d278832cbca9c3c3dd44b30a26dcfa3ae1e0f6f19ff34edc27b689 \
--hash=sha256:5d0c871efc696ef5eb8514df64b86ab28736db753ebb42a2101f3b562f4849c0 \
--hash=sha256:5e0c0ed37472c4729f3001066510a656486f08f149dda1ebfd3dfe4450c9756e \
--hash=sha256:5e1c174b366565e101f903f9d1cc96d5508f805759dd37d012743f1c73ec0d7b \
--hash=sha256:62059d739af7fc035ed6e63c5390118a60a5e9aa5a5541cd0486a83e741842c7 \
--hash=sha256:623d4b44f64efdf235b1e8dce266057073d93cde6197e7d7684f20c297f67f30 \
--hash=sha256:628efe13630ac3397e7d1278b6be6f22f37a86d638a324334b4cd43c1daf9928 \
--hash=sha256:6342f79d6f50e680c8aa59e0615d745e867e51ffd59c77093be60b7c433067af \
--hash=sha256:63b87c93e28957e6dc2bb92d31727a863c9bf4a4daa080f0995fdcb0242c9166 \
--hash=sha256:65e937576141ac50fac32fa9736dbb3e0e4a7769f91be004011a09216c6ab05f \
--hash=sha256:66027e401c70d0cf55021b91b8a7ec2cd5810e20602f945b4fe6ae8b37ed232b \
--hash=sha256:6644eecd99c4e8cdf72e646e17b391bb70b054f44becde37dcdc48cbec7e1527 \
--hash=sha256:6705af9d1005127302c04d9f1533ba56e289336c465923ef878430e99295a0b9 \
--hash=sha256:6a8248b1ba8861e48e4c7ced3895a1264d2a3b617de72ec94172ce6e64bf16c7 \
--hash=sha256:6b14914e67044724c31a9360c7b89e9d070117c630746eefdc1620d967545acd \
--hash=sha256:6b7b540bb321f7f0a7b8f5d107f941bb361e3a154c0b594dae0394997b91b743 \
--hash=sha256:71250e010eede33c1d638e2c7a98288520d67f782fd5eceecaeca3129233a09a \
--hash=sha256:722ab747ff5dc28070b1a8c020dba6466f13f2ab56bc251ad301fefa2454aa1e \
--hash=sha256:724224d4c457207271239114bf43afafc3eca4a1b4661ccdd428d11869a03bbd \
--hash=sha256:729989759feb81ff6493879a0d60a0bd7d2eee41001bbec0381a080318439382 \
--hash=sha256:740bba4223fa5216d4d6c5dcd29e697f37229b8a61b69e1a50527b0ea993ab2c \
--hash=sha256:7bdc658c9474864893e0b6b94f1390bf6a912952df1870dd93bb7d1a902b5628 \
--hash=sha256:7d53fc4b90ef6e11de639dc18744d9be8cbd70ccb5ce80027aaffe7b1ab0215a \
--hash=sha256:7fa69212ea60ea24e2d8aff23fe102b1f87f1b27a320f92d2e7b3468997a496a \
--hash=sha256:80326bc571164bbbb6bead2e35d0c943b23b24fde629032197c58151529d24d8 \
--hash=sha256:80578e91764bfca297ddca322c00a3136d993b829e9839e7fa378a19c1fcc25d \
--hash=sha256:80a6e37e235780f189558ab804f3cbc01c18f5c578995739b49613d544d34ebf \
--hash=sha256:8135a549e27e9941a70e2d2156676ef2ffeff4b06e9d564dbaaae963482afdef \
--hash=sha256:82e60c00cfb8493a5ba27cdf9b3695fdd153f666f73e11f18968f78ead1d8705 \
--hash=sha256:856bbb24f2ee6436af7609267e73309e4bb0a0f9982f79f1c2e01019279c6671 \
--hash=sha256:85d6daa3a7ca404570ae130babbeb347ef9d3faca5300fb13cfa4bb48c3d30d1 \
--hash=sha256:8879b6a4040ee925c638548238ab7fe612cf5fa8752fe847346da0da8be81c3f \
--hash=sha256:8b3bede7d583bc9f47d8693a29984882e59077db1a5238ad977fc70ae8169741 \
--hash=sha256:8dbb3862aa649de95660b6337d97101977f160b5b354d07b82fe309874d2c8bc \
--hash=sha256:8f244dfee05ea29b8064701880865eb1684f3a704a5665bd10b64694444dbbd4 \
--hash=sha256:8f7469408740cf06a79b01605f2ae0b2acc8839c03fcbbf05da49baee12d3302 \
--hash=sha256:90cc9973c51811918247a78d9ab2f54871296e4e37e69a98aba4d3c9acedbf62 \
--hash=sha256:90d8c4fa5ba293cf92de351fbc292cdaadb1a1d58d031a1a97ff9b8fb6250ec7 \
--hash=sha256:94c02b0702656f083c098bdbd93bce22a7aa7a2b34ba56d2472efb67dab7cf58 \
--hash=sha256:9662a9fe457820c60365b3209e03cbd8e4a817195d55de65a80fa680b4bea136 \
--hash=sha256:997617dd7856c5dad742bf6893b872319156dd43f47587541a59e4a852d52bbc \
--hash=sha256:99c5637b74e2805ee4de9e2a43c8b45f678e50abb1c2da9880f0372f6498ba2f \
--hash=sha256:9a215749c9a88ef2842e880215193e56ae60b856773c99702b078236bc6d4adb \
--hash=sha256:9bde5d82d7ac4859e0cb3a35e148f537a8d4e56aa43f42582b5f263982f095ae \
--hash=sha256:a004c1fe5a72c496f28c6c1d8c2dc5cfe3278d99478e18f8b838c70a912b366f \
--hash=sha256:a0e2e7c2c1a4f25db7b6596738d810c10732e77f852247300a1bc49e364d6dc9 \
--hash=sha256:a22c4956a4d858200dba83f0691bb692d77b0eeddfca80157820d20b85dea4f1 \
--hash=sha256:a7f391838e8adcf1f2fe71561d9e5a9f74ea7ffa5052eb2db329aac677383136 \
--hash=sha256:a9eacb382f400bb5865e7e6d24bbe709a84510291e707f169dd4a24ee4a5ac6a \
--hash=sha256:ace8dd1efa5f44c482d091aa38322e20e3ffe5adcdba6b67ad9f4e7da58f3f68 \
--hash=sha256:ade76f8c84ade325bbed96806357fffd353fcc29a5166d6dc6d39381f6d9f76c \
--hash=sha256:af37a1e6b6bd506b597d5fb4cf111fb527d1b2223608a5d441d4738827cfd166 \
--hash=sha256:af7c474f0d8f4d2a196370e85033873c7b063a0b5da9a4f143aa023e3bd25407 \
--hash=sha256:b225c656efa2dedecc81651d2290170af25887b7de4f38c5efc7c5ae2b9442ab \
--hash=sha256:b459d29c8b82a420a98fa0ce8e9cf787ce0062d98cc90604ef9574fb3cc26ff8 \
--hash=sha256:bc6f87d03e3691154673aaa8f08991723d6e3394c83ef2875c7a9049eac9595c \
--hash=sha256:bc8fd230ef013951900c1fda100eebe4a4b1b407dde2a44186995042dda2c628 \
--hash=sha256:bd645b5d2f810a181c44f4a71135e7c365b44f4be9ed3d1892635be13a857553 \
--hash=sha256:be7be57097a65a8fab3d0f0a10d12931deb626a7d8082eb732b1ae41f3a202e3 \
--hash=sha256:c15a165673bb3fb57facbf040edf5c0556d20ccd2e0ccc5f23ebb69fb715fdc1 \
--hash=sha256:c4b3f2c7d84f303da873b634d0beef83b5e1137294c3de4e23102841dac0cf4a \
--hash=sha256:c534c9524a2acd0b97b7022074bec3784ac273c683cf9535087e437672ea8531 \
--hash=sha256:c95d25b5382ee0e6191ecafdeabefdc1f7bff8dfee29239b9b79e760ef3b04bd \
--hash=sha256:c9d06edfd974e918b40e0662a7e76dac13125529ee5ec9fbe42dc0d6faa209c3 \
--hash=sha256:cdb8e4b0f6a41b857c74c03116e8ffbef59ef8e533e934b532843178990d01d5 \
--hash=sha256:ce39283ef08b0f28478e920d4d89a1fc169176e568e8a6a821332673145522eb \
--hash=sha256:cfef7f7aa434a1e632e0ebda14b39f4f1d7975e0fce5c77ea7b43156fabf9bd8 \
--hash=sha256:d2605a3b2af8d66f8b75312d223642c065ec773446c04566d9030ad5e2db13c9 \
--hash=sha256:d338813a440bf6d2f0df55140d3f3080284410b1ebfe9df50e3847bcdb1a17bb \
--hash=sha256:d355b22270be8062360b9df2ee0b10277590789a1059257916fb9e256a0cff80 \
--hash=sha256:d68da281ac208b6236ffa8beef23fe7c7c956d8bf09b421d447232fd94441b35 \
--hash=sha256:dafbb58a149d1ebd5767b3f064f911c5ee0897608005e51c3904b0ada2a8d99c \
--hash=sha256:dc2b495a92b3971966bf102e73589f950db3ec1ca6713265355ce7771d97b199 \
--hash=sha256:dd0f3037d501178a761fd2814370aca547f79e99a200a61a1f6e7b79ec3d78b9 \
--hash=sha256:de2c12555bf05546f3ee75733f2c81de70aab7f530e86d0d2162b0ddcb3c39ae \
--hash=sha256:e164c4a6868d11988c7f2386e3278ccff21c665cd7d08279b62709dd37a3167c \
--hash=sha256:ed59cb4ee258674a6ed9b8515e42079db02cb3be94f133fdd3f200183a40c49d \
--hash=sha256:ef07e0b6b879f699a16fc7a513b974246fdeaef44908a021130cf4afe6a1c89c \
--hash=sha256:ef2950896673a9809e8e5ab857525924fbcacfc98b858b0509ccf50d341f80f4 \
--hash=sha256:f09f145b89ea292cf6c25fd7c8c0d90207fd6a9e54c7828499669996a1e5bdcc \
--hash=sha256:f27e7e8a85512b6a4b490d5756edde8e6772883a5800e1476172e44eda3f7d7c \
--hash=sha256:f300f28dff74ff4148c21e6971e4de6ca0c34e0086a3d95c017c5174ebf85ca5 \
--hash=sha256:f3ed747b7651668131029c720fbc32c7ee2d129bdad200e6c8f4037b20f7913a \
--hash=sha256:f87f02afe05c1c246012e3de100a77cfbabd17db709fe93cf074271ab239b312 \
--hash=sha256:fa87ea2ad64e59fe5622c1dc5716106b6d6e7e4b26b848cb5f5710a75c292ef5 \
--hash=sha256:fc23e72bd7f8a8e540fed2244524d0a9aeb6ae3325f3d56f04a7a3debe5b04c2 \
--hash=sha256:fdd00937f15f5f93c8e53d8060a8c4c010431ab595a9b5b50ddd569a04603944 \
--hash=sha256:fe7a168d805c8a7bf1c2de55b7ab2bc958586bfd88d0e87235a92cac66b590a7
yarl==1.25.1 \
--hash=sha256:0136d640dfa9b0523853e411430a99f8a91eca85774c6420285a33b755bc6de3 \
--hash=sha256:03dd38de09bc213e9a8b29761eec33ee1d5318dac0e49d8af36e4d27830e23a7 \

View File

@@ -1176,14 +1176,12 @@ async def test_delete_missing_claim_is_404(env):
@pytest.mark.asyncio
async def test_unexpected_api_error_returns_503(env):
async def test_unexpected_api_error_propagates(env):
add_user(env.k8s)
env.k8s.get_claim_error = ApiException(status=500)
async with asgi_client(env) as client:
response = await client.get("/users/alice")
assert response.status_code == 503
assert response.headers["retry-after"] == "10"
assert response.json() == {"error": "cluster API unavailable, retry shortly"}
with pytest.raises(ApiException):
await client.get("/users/alice")
@pytest.mark.asyncio
@@ -1833,16 +1831,6 @@ def test_ws_unauthenticated_closes_4401(env):
assert exc.value.code == 4401
def test_ws_kubernetes_api_error_closes_1011(env):
add_user(env.k8s)
env.k8s.get_claim_error = ApiException(status=503)
with TestClient(env.app) as client:
with client.websocket_connect("/u/alice/api/remote.mux") as ws:
with pytest.raises(WebSocketDisconnect) as exc:
ws.receive_text()
assert exc.value.code == 1011
def test_ws_cookie_cross_origin_closes_4401(env):
add_user(env.k8s)
with TestClient(env.app) as client:
@@ -2161,19 +2149,6 @@ def test_remote_user_returns_valid_and_rejects_invalid(env):
assert g.remote_user({}) is None
@pytest.mark.asyncio
async def test_sso_landing_returns_503_when_claim_patch_is_forbidden(env):
"""A missing RBAC verb on ``patch sandboxclaims`` used to escape as a 500."""
enable_sso(env)
env.k8s.claims["alice"] = {"metadata": {"name": claim_name("alice")}}
env.k8s.patch_error = ApiException(status=403)
async with asgi_client(env) as client:
response = await client.get("/", headers={"X-Forwarded-User": "alice"})
assert response.status_code == 503
assert response.headers["retry-after"] == "10"
assert response.json() == {"error": "cluster API unavailable, retry shortly"}
@pytest.mark.asyncio
async def test_sso_landing_new_user_shows_provisioning(env):
enable_sso(env)

View File

@@ -26,8 +26,7 @@ metadata:
namespace: dsh-demo
---
# Least privilege:
# - claims are created/deleted per user (signup/delete) and patched only to
# rotate the token-hash annotation when a session is minted;
# - claims are created/deleted per user (signup/delete);
# - sandboxes are read, and patched only to flip operatingMode (suspend/resume);
# - pods are read, and pods/log is read to capture DSH's launch token from
# the startup log line (`dsh web: ...?token=...`).
@@ -40,7 +39,7 @@ metadata:
rules:
- apiGroups: ["extensions.agents.x-k8s.io"]
resources: ["sandboxclaims"]
verbs: ["get", "list", "create", "patch", "delete"]
verbs: ["get", "list", "create", "delete"]
- apiGroups: ["agents.x-k8s.io"]
resources: ["sandboxes"]
verbs: ["get", "list", "patch"]

View File

@@ -139,15 +139,13 @@ kubectl apply -f manifests/exposure/gateway-api-sso/
# 5. Preflight: fails loudly on missing Secrets, a bad oauth2-proxy cookie
# secret, missing gateway SSO env, a dangling TLS reference, leftover
# placeholders, a second path to the gateway, a Role without `patch` on
# sandboxclaims, or missing SSO NetworkPolicies.
# placeholders, or a second path to the gateway.
./scripts/preflight-sso.sh
```
The preflight is read-only and exits non-zero on any failure, naming the exact
fix. Run it again after rotating a Secret or changing the public host; it also
verifies that the oauth2-proxy cookie secret is a valid AES key length (16, 24
or 32 raw bytes, or URL-safe unpadded base64 that decodes to one of those).
verifies that the oauth2-proxy cookie secret decodes to 16, 24 or 32 bytes.
### SSO trust boundary

View File

@@ -1,6 +1,5 @@
# REQUIRED with the SSO exposure variant: enforce the trust boundary at the
# network layer. Applying the SSO variant without this file is demo-only.
# `scripts/preflight-sso.sh` fails while either policy below is missing.
#
# The chain is Traefik (Gateway API) -> oauth2-proxy -> dsh-gateway. These
# policies make it the ONLY chain:

View File

@@ -20,14 +20,7 @@
# applied oauth2-proxy args, Gateway listeners or HTTPRoute hostnames;
# 6. (warning) no Ingress in the namespace creates a second path to
# dsh-gateway. With SSO enabled the Service must be reachable only through
# oauth2-proxy;
# 7. the gateway ServiceAccount may `patch` sandboxclaims. The SSO landing
# path rotates the token-hash annotation whenever the browser has no valid
# gateway session (first visit, expired/foreign cookie, gateway restart),
# so without that verb every such sign-in answers 503;
# 8. the SSO variant's required NetworkPolicies are applied. Without them any
# Pod in the cluster can reach dsh-gateway:8080 and spoof the identity
# header, so the exposure is demo-only.
# oauth2-proxy.
#
# Exit status: 0 when every check passes (warnings allowed), 1 on any failure.
# Every failure prints the fix. This script only reads cluster state.
@@ -42,9 +35,6 @@
# OAUTH_SECRET oauth2-proxy Secret name (default: oauth2-proxy)
# TLS_SECRET TLS Secret name the Gateway should reference (default:
# dsh-demo-tls)
# GATEWAY_ROLE Role/RoleBinding name that grants the gateway access
# (default: dsh-gateway; only used when impersonation is
# unavailable and the permission must be read statically)
set -euo pipefail
cd "$(dirname "$0")/.."
@@ -53,7 +43,6 @@ GATEWAY_DEPLOY="${GATEWAY_DEPLOY:-dsh-gateway}"
OAUTH_DEPLOY="${OAUTH_DEPLOY:-oauth2-proxy}"
OAUTH_SECRET="${OAUTH_SECRET:-oauth2-proxy}"
TLS_SECRET="${TLS_SECRET:-dsh-demo-tls}"
GATEWAY_ROLE="${GATEWAY_ROLE:-dsh-gateway}"
FAILED=0
pass() { printf 'PASS %s\n' "$*"; }
@@ -94,38 +83,21 @@ check_secret_key "$OAUTH_SECRET" client-secret \
check_secret_key "$OAUTH_SECRET" cookie-secret \
"Create it from manifests/exposure/gateway-api-sso/73-oauth2-proxy-secret.yaml.example."
# oauth2-proxy accepts the cookie secret either as raw bytes of length 16, 24
# or 32, or as URL-safe unpadded base64 that decodes to one of those lengths
# (pkg/encryption.SecretBytes). The documented generator,
# `python3 -c 'import secrets; print(secrets.token_urlsafe(32))'`, produces the
# second form: 43 base64 characters that decode to 32 bytes.
# The cookie secret must be URL-safe unpadded base64 of 16, 24 or 32 bytes;
# oauth2-proxy refuses anything else (the classic error is "44 bytes").
if COOKIE_B64=$(kubectl -n "$NS" get secret "$OAUTH_SECRET" \
-o jsonpath='{.data.cookie-secret}' 2>/dev/null); then
if [ -n "$COOKIE_B64" ]; then
COOKIE_RAW=$(printf '%s' "$COOKIE_B64" | base64 -d 2>/dev/null || true)
COOKIE_LEN=${#COOKIE_RAW}
COOKIE_FORM=raw
case "$COOKIE_LEN" in
16 | 24 | 32) ;;
*)
# Mirror SecretBytes: only a strictly URL-safe base64 string is decoded;
# anything else is used as raw bytes (and is then the wrong length).
COOKIE_FORM=base64
case "$COOKIE_RAW" in
"" | *[!A-Za-z0-9_=-]*) COOKIE_LEN=0 ;;
*)
COOKIE_LEN=$(printf '%s' "$COOKIE_RAW" | tr -- '-_' '+/' | tr -d '=\n' \
| base64 -d 2>/dev/null | wc -c || true)
;;
esac
;;
esac
case "$COOKIE_LEN" in
16 | 24 | 32) pass "oauth2-proxy cookie-secret is $COOKIE_FORM with a $COOKIE_LEN-byte key" ;;
*)
fail "oauth2-proxy cookie-secret is not a valid length ($COOKIE_LEN bytes). It must be 16, 24 or 32 raw bytes, or URL-safe unpadded base64 that decodes to one of those lengths. Generate it with: python3 -c 'import secrets; print(secrets.token_urlsafe(32))'"
;;
esac
if ! COOKIE_LEN=$(printf '%s' "$COOKIE_B64" | base64 -d 2>/dev/null | wc -c); then
fail "Secret $OAUTH_SECRET key 'cookie-secret' is not valid base64. Generate it with: python3 -c 'import secrets; print(secrets.token_urlsafe(32))'"
else
case "$COOKIE_LEN" in
16 | 24 | 32) pass "oauth2-proxy cookie-secret decodes to $COOKIE_LEN bytes" ;;
*)
fail "oauth2-proxy cookie-secret decodes to $COOKIE_LEN bytes; it must be 16, 24 or 32. Generate a URL-safe unpadded value with: python3 -c 'import secrets; print(secrets.token_urlsafe(32))'"
;;
esac
fi
fi
fi
@@ -167,51 +139,6 @@ if env_is_set ALLOW_INSECURE_COOKIES; then
warn "ALLOW_INSECURE_COOKIES is still set on deploy/$GATEWAY_DEPLOY. It is ignored while COOKIE_SECURE=true but is a footgun: remove it with 'kubectl -n $NS set env deploy/$GATEWAY_DEPLOY ALLOW_INSECURE_COOKIES-'."
fi
echo
echo "== Gateway RBAC (SSO token rotation)"
# The SSO landing path patches the token-hash annotation on the user's claim
# whenever the browser has no valid gateway session: first visit, an expired or
# foreign cookie, or a gateway restart (sessions live in the gateway's memory).
# Without `patch` every such GET / answers 503 and the user cannot sign in.
GATEWAY_SA=$(kubectl -n "$NS" get deployment "$GATEWAY_DEPLOY" \
-o jsonpath='{.spec.template.spec.serviceAccountName}' 2>/dev/null || true)
GATEWAY_SA=${GATEWAY_SA:-default}
CAN_I=$(kubectl auth can-i patch sandboxclaims.extensions.agents.x-k8s.io \
-n "$NS" --as="system:serviceaccount:$NS:$GATEWAY_SA" 2>&1 || true)
# read_gateway_rules: one "apiGroups|resources|verbs" line per rule of the
# Role (or ClusterRole) the gateway RoleBinding points at. Used only when
# `kubectl auth can-i --as` is unavailable (a read-only kubeconfig cannot
# impersonate); it is a static check, not an authoritative one.
read_gateway_rules() {
local rules_jsonpath kind name
rules_jsonpath='{range .rules[*]}{range .apiGroups[*]}{@}{","}{end}{"|"}{range .resources[*]}{@}{","}{end}{"|"}{range .verbs[*]}{@}{","}{end}{"\n"}{end}'
kind=$(kubectl -n "$NS" get rolebinding "$GATEWAY_ROLE" \
-o jsonpath='{.roleRef.kind}' 2>/dev/null || true)
name=$(kubectl -n "$NS" get rolebinding "$GATEWAY_ROLE" \
-o jsonpath='{.roleRef.name}' 2>/dev/null || true)
case "$kind" in
Role) kubectl -n "$NS" get role "$name" -o jsonpath="$rules_jsonpath" 2>/dev/null || true ;;
ClusterRole) kubectl get clusterrole "$name" -o jsonpath="$rules_jsonpath" 2>/dev/null || true ;;
esac
}
if [ "$CAN_I" = "yes" ]; then
pass "ServiceAccount $GATEWAY_SA can patch sandboxclaims (token rotation)"
elif [ "$CAN_I" = "no" ]; then
fail "ServiceAccount $GATEWAY_SA cannot patch sandboxclaims: SSO sign-in answers 503 whenever the browser has no valid gateway session (after a gateway restart, cookie expiry or in a new browser). Fix: grant 'patch' on sandboxclaims to Role $GATEWAY_ROLE (the shipped Role in manifests/50-gateway.yaml has it; re-applying just the Role/RoleBinding is enough). RBAC is evaluated per request; no gateway restart is needed."
else
RULES=$(read_gateway_rules)
if printf '%s\n' "$RULES" | awk -F'|' \
'$1 ~ /(^|,)extensions\.agents\.x-k8s\.io(,|$)/ && $2 ~ /(^|,)sandboxclaims(,|$)/ && $3 ~ /(^|,)patch(,|$)/ { found = 1 } END { exit found ? 0 : 1 }'; then
pass "the gateway Role grants patch on sandboxclaims (static check; impersonation unavailable)"
elif [ -n "$RULES" ]; then
fail "Role $GATEWAY_ROLE does not grant 'patch' on sandboxclaims: SSO sign-in answers 503 whenever the browser has no valid gateway session. Fix: grant that verb to the Role (the shipped Role in manifests/50-gateway.yaml has it; re-applying just the Role/RoleBinding is enough). RBAC is evaluated per request; no gateway restart is needed."
else
warn "could not verify that ServiceAccount $GATEWAY_SA may patch sandboxclaims ($CAN_I). Check manually that Role $GATEWAY_ROLE grants 'patch' on extensions.agents.x-k8s.io/sandboxclaims."
fi
fi
echo
echo "== SSO objects and placeholders"
if kubectl -n "$NS" get deployment "$OAUTH_DEPLOY" >/dev/null 2>&1; then
@@ -299,18 +226,6 @@ if kubectl -n "$NS" get ingress >/dev/null 2>&1; then
fi
fi
# The SSO variant's policies are part of the variant: without them the
# gateway Service is reachable by any Pod, which can spoof the identity header.
echo
echo "== SSO NetworkPolicies (required with this variant)"
for POLICY in dsh-gateway-ingress oauth2-proxy-ingress; do
if kubectl -n "$NS" get networkpolicy "$POLICY" >/dev/null 2>&1; then
pass "NetworkPolicy $POLICY exists"
else
fail "NetworkPolicy $POLICY is missing: any Pod in the cluster can reach dsh-gateway:8080 and spoof X-Forwarded-User, so the SSO identity is not trustworthy. Fix: kubectl apply -f manifests/exposure/gateway-api-sso/75-networkpolicies.yaml"
fi
done
echo
if [ "$FAILED" -ne 0 ]; then
echo "preflight-sso: FAILED - fix the items above before exposing the gateway." >&2

View File

@@ -29,6 +29,13 @@ NODE_RUNTIME_IMAGE=docker.io/node:24-trixie-slim@sha256:54f84b4cf8432b21aaffd5d3
# Base image for the example gateway (examples/dsh-agents-as-a-service/gateway).
GATEWAY_PYTHON_IMAGE=docker.io/python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159
# Base images for the main DSH Web image (root Dockerfile), pinned by digest.
NODE_BUILD_IMAGE=docker.io/node:24-trixie@sha256:8c761eca2bf7eec965f946cf47b8090143cb41f45f2f8699af0cc0298d2d2d19
NODE_RUNTIME_IMAGE=docker.io/node:24-trixie-slim@sha256:54f84b4cf8432b21aaffd5d3ce8d41e12cea0d10d33c09d2f3c9879d49d6b446
# Base image for the example gateway (examples/dsh-agents-as-a-service/gateway).
GATEWAY_PYTHON_IMAGE=docker.io/python:3.12-slim@sha256:aa943ce411423c7582288f18707ff66eddcbaeb510502d747a72aeb34f30d159
# Control-plane versions used by the examples and their manifests.
# The matching SHA-256s pin the release manifests that CI downloads and
# applies; update both the version and the digest when bumping either pin.