diff --git a/CHANGELOG.md b/CHANGELOG.md index b2413466..0b766258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **`SecurityOpt` SELinux and system-paths directives are now policy-evaluable.** Three opt-in `request_body.container_create` knobs (all default off — zero behavior change): `deny_selinux_disable` denies `label=disable` and the legacy `label:disable` colon form (which turn off SELinux confinement); `deny_selinux_label_override` denies `label=user:`/`role:`/`type:`/`level:` SELinux context customization; `deny_unconfined_system_paths` denies `systempaths=unconfined` **and** requests that set `MaskedPaths`/`ReadonlyPaths` to an explicit empty array — the Docker CLI translates `--security-opt systempaths=unconfined` into `MaskedPaths: []` client-side, so direct API callers could otherwise clear the masked-path protections without ever sending the SecurityOpt string. Both vectors are covered. - **Swarm services gained seccomp/AppArmor confinement-mode rails**, completing `ContainerSpec.Privileges` parity with container-create. Three opt-in `request_body.service` knobs (all default off): `deny_unconfined_seccomp` (denies `Privileges.Seccomp.Mode: "unconfined"`), `deny_custom_seccomp_profiles` (denies `Mode: "custom"`, and fail-closed denies a `Seccomp` object carrying a `Profile` blob with no `Mode` — an inline profile the proxy cannot vet can encode an allow-everything policy), and `deny_unconfined_apparmor` (denies `Privileges.AppArmor.Mode: "disabled"`, swarm's equivalent of unconfined). -- **Three bundled presets for the lookout Docker agent and drydock self-update (12 → 15 presets).** `lookout.yaml` covers container lifecycle, image pull/remove, `GET /containers/*/logs` streaming, and event/network/volume/Swarm-service reads with exec denied; `lookout-with-exec.yaml` adds interactive exec (`/containers/*/exec`, `/exec/*/start`, `/exec/*/resize`, `/exec/*/json`). Both disable response redaction so container inspect data forwards intact through the tri-tool topology (sockguard → lookout → drydock) and set `insecure_allow_read_exfiltration: true` for the logs path. `drydock-with-selfupdate.yaml` extends the drydock preset with the exec paths drydock's self-update finalize callback needs, pinned to the finalize entrypoint argv via `allowed_commands`. A ready-to-run `examples/compose/lookout/` stack ships alongside. +- **Three bundled presets for the Portwing Docker agent and drydock self-update (12 → 15 presets).** `portwing.yaml` covers container lifecycle, image pull/remove, `GET /containers/*/logs` streaming, and event/network/volume/Swarm-service reads with exec denied; `portwing-with-exec.yaml` adds interactive exec (`/containers/*/exec`, `/exec/*/start`, `/exec/*/resize`, `/exec/*/json`). Both Portwing presets disable response redaction so container inspect data forwards intact through the tri-tool topology (sockguard → Portwing → drydock) and set `insecure_allow_read_exfiltration: true` for the logs path. `drydock-with-selfupdate.yaml` extends the drydock preset with the exec paths drydock's self-update finalize callback needs, pinned to the finalize entrypoint argv via `allowed_commands`. A ready-to-run `examples/compose/portwing/` stack ships alongside. ### Fixed @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **The rate-limit token bucket hot path is now allocation-free.** Bucket state (token count + refill timestamp) packs into a single `atomic.Uint64` (16.16 fixed-point tokens, millisecond timestamp), eliminating the per-admission heap allocation: the hot-path benchmark went from 1 alloc/16 B to 0 allocs/0 B per op (~47 → ~36 ns/op). Two consequences: `limits.rate.burst` now has a validated upper bound of 65535 (configs above it are rejected at startup with a descriptive error; `tokens_per_second` is implicitly bounded the same way since burst ≥ tps), and refill granularity is milliseconds rather than nanoseconds — negligible for every supported rate. +- **Dependency refresh.** Bumped `sigstore/sigstore-go` v1.2.0 → v1.2.1 (image-trust path; no behavior change) and refreshed the docs/website toolchain — Biome 2.4.16 → 2.5.0, Tailwind 4.3.0 → 4.3.1 (docs now in lockstep with website), fumadocs 16.10.0 → 16.10.3, lucide-react 1.17 → 1.18, `@radix-ui/react-slot` 1.2 → 1.3. Lockfile regenerated from scratch so the existing `postcss` override resolves cleanly (`npm audit` reports 0 vulnerabilities). ## [1.3.0] - 2026-06-11 diff --git a/README.md b/README.md index 3fe63236..dc99b30f 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ To run fully unprivileged with a unix socket, pre-create a host directory with t - **v1.2.0 shipped on 2026-06-02** — operational resilience for a wedged daemon. An opt-in **readiness probe** (`health.readiness.*`, default `/ready`) issues a real `GET /containers/json` against the Docker API and returns `503` when the daemon accepts connections but no longer answers — the gap the raw-dial `/health` watchdog misses. An opt-in **`upstream.request_timeout`** bounds finite proxied requests with a total deadline, converting a hung body or heavy read into a fast `504` (`reason_code=upstream_request_timeout`) while exempting streaming and long-lived endpoints. New metrics `sockguard_upstream_api_up` + `sockguard_upstream_readiness_checks_total` mirror the watchdog. The bundled **drydock preset** now allowlists the stock `runc` runtime so drydock recreation stops getting 403'd out of the box. Dependency hygiene: the Go toolchain moves to `1.26.4` (clearing two *reachable* stdlib advisories, GO-2026-5037 / GO-2026-5039), plus the `go-minor` / `npm-minor` / `actions-minor` groups; `govulncheck` reports zero vulnerabilities. - **v1.1.0 shipped on 2026-06-01** — image-trust verification wired end to end: registry digest resolution, cosign signature discovery (classic tag + OCI 1.1 referrers), digest-pinned forwarding, keyed (PEM) and keyless (Fulcio + Rekor) both enforced, swarm-service create/update now subject to the same image-trust policy as container create. A 21-finding security audit landed alongside: closed request-inspection bypasses (plugin multipart, BuildKit `# syntax=`, gzip bombs, swarm-service capability/sysctl/image-trust escapes), read-side sub-resource visibility gating, new `allowed_runtimes` allowlist, hardened config/admin paths (signed-bundle TOCTOU, PID-only peer rejection, admin-listener CIDR backstop), response redaction extended to `HostConfig.Mounts[].Source` and service `PreviousSpec`. CodeQL `actions` analysis and supply-chain dependency hygiene (`govulncheck` reports zero vulnerabilities) round out the release. - **v1.0.0 shipped on 2026-05-20** with the public proxy contract locked: YAML schema, CLI flags, env vars, admin endpoints, and Prometheus metric names are now under the v1.x compatibility promise. -- **15 bundled presets** cover drydock, Traefik, Portainer, Watchtower, Homepage, Homarr, Diun, Autoheal, read-only, CIS Docker Benchmark, GitHub Actions self-hosted runner, GitLab Runner, lookout, lookout with exec, and drydock with self-update. +- **15 bundled presets** cover drydock, Traefik, Portainer, Watchtower, Homepage, Homarr, Diun, Autoheal, read-only, CIS Docker Benchmark, GitHub Actions self-hosted runner, GitLab Runner, Portwing, Portwing with exec, and drydock with self-update. - **Expanded QA hardening** added proxy-vs-daemon differential tests, real-dockerd preset conformance, fuzz corpora for routing and visibility, weekly soak testing, and TLS edge-case coverage. - **Supply-chain verification** covers release images across GHCR, Docker Hub, and Quay.io using the same cosign commands documented for operators. @@ -241,7 +241,7 @@ Most existing socket proxies stop at method/path or regex filtering. Tecnativa a |---|---|---| | 🛡️ | **Default-Deny Posture** | Everything blocked unless explicitly allowed. No match means deny. | | 🎛️ | **Granular Control** | Allow start/stop while blocking create/exec. Per-operation POST controls with glob matching. | -| 📋 | **YAML Configuration** | Declarative rules, glob path patterns, first-match-wins evaluation, and canonical path matching that strips API versions, collapses dot segments, and decodes escaped separators before policy evaluation. 15 bundled workload presets (including CIS Docker Benchmark, self-hosted GitHub Actions runners, GitLab Runner, and lookout) plus the default config. | +| 📋 | **YAML Configuration** | Declarative rules, glob path patterns, first-match-wins evaluation, and canonical path matching that strips API versions, collapses dot segments, and decodes escaped separators before policy evaluation. 15 bundled workload presets (including CIS Docker Benchmark, self-hosted GitHub Actions runners, GitLab Runner, and Portwing) plus the default config. | | 📊 | **Structured Access Logging** | JSON access logs with method, raw path, normalized path, decision, matched rule, latency, canonical request ID, W3C `traceparent` correlation fields, and client info. Use `normalized_path` for SIEM correlation and policy analysis; raw `path` is preserved for forensic replay. Canonical request IDs are generated from a buffered pool so request logging does not block on a fresh entropy read per request. | | 🔐 | **mTLS for Remote TCP** | Non-loopback TCP listeners require mutual TLS by default. Plaintext TCP is explicit legacy mode only. | | 🌐 | **Client ACL Primitives** | Optional source-CIDR admission checks, client-container label ACLs, listener certificate selectors (CN/DNS/IP/URI SAN/SPKI), profile certificate selectors (CN/DNS/IP/URI/SPIFFE/SPKI), and unix peer credentials let one proxy differentiate callers before the global rule set runs. When mTLS is enabled, certificate selectors follow the verified client leaf certificate rather than an unverified peer slice entry. | @@ -269,11 +269,11 @@ Most existing socket proxies stop at method/path or regex filtering. Tecnativa a ### Bundled presets (15) -[drydock](app/configs/drydock.yaml) · [drydock with self-update](app/configs/drydock-with-selfupdate.yaml) · [lookout](app/configs/lookout.yaml) · [lookout with exec](app/configs/lookout-with-exec.yaml) · [Traefik](app/configs/traefik.yaml) · [Portainer](app/configs/portainer.yaml) · [Watchtower](app/configs/watchtower.yaml) · [Homepage](app/configs/homepage.yaml) · [Homarr](app/configs/homarr.yaml) · [Diun](app/configs/diun.yaml) · [Autoheal](app/configs/autoheal.yaml) · [read-only](app/configs/readonly.yaml) · [CIS Docker Benchmark](app/configs/cis-docker-benchmark.yaml) · [GitHub Actions self-hosted runner](app/configs/github-actions-runner.yaml) · [GitLab Runner](app/configs/gitlab-runner.yaml) +[drydock](app/configs/drydock.yaml) · [drydock with self-update](app/configs/drydock-with-selfupdate.yaml) · [Portwing](app/configs/portwing.yaml) · [Portwing with exec](app/configs/portwing-with-exec.yaml) · [Traefik](app/configs/traefik.yaml) · [Portainer](app/configs/portainer.yaml) · [Watchtower](app/configs/watchtower.yaml) · [Homepage](app/configs/homepage.yaml) · [Homarr](app/configs/homarr.yaml) · [Diun](app/configs/diun.yaml) · [Autoheal](app/configs/autoheal.yaml) · [read-only](app/configs/readonly.yaml) · [CIS Docker Benchmark](app/configs/cis-docker-benchmark.yaml) · [GitHub Actions self-hosted runner](app/configs/github-actions-runner.yaml) · [GitLab Runner](app/configs/gitlab-runner.yaml) ### Ready-to-run compose examples -[drydock](examples/compose/drydock/) · [lookout](examples/compose/lookout/) · [Traefik](examples/compose/traefik/) · [Portainer](examples/compose/portainer/) · [Watchtower](examples/compose/watchtower/) · [GitHub Actions self-hosted runner](examples/compose/github-actions-runner/) · [GitLab Runner](examples/compose/gitlab-runner/) · [CIS Docker Benchmark gate](examples/compose/cis-docker-benchmark/) +[drydock](examples/compose/drydock/) · [Portwing](examples/compose/portwing/) · [Traefik](examples/compose/traefik/) · [Portainer](examples/compose/portainer/) · [Watchtower](examples/compose/watchtower/) · [GitHub Actions self-hosted runner](examples/compose/github-actions-runner/) · [GitLab Runner](examples/compose/gitlab-runner/) · [CIS Docker Benchmark gate](examples/compose/cis-docker-benchmark/) Each example pairs a downstream Docker API consumer with a `sockguard.yaml` overlay and a short README covering audience, exposed API surface, and security tradeoffs. diff --git a/app/configs/lookout-with-exec.yaml b/app/configs/portwing-with-exec.yaml similarity index 83% rename from app/configs/lookout-with-exec.yaml rename to app/configs/portwing-with-exec.yaml index 426afa7c..50ae3d94 100644 --- a/app/configs/lookout-with-exec.yaml +++ b/app/configs/portwing-with-exec.yaml @@ -1,10 +1,10 @@ -# Sockguard — Lookout with Exec Preset +# Sockguard — Portwing with Exec Preset # -# Extends the lookout preset with exec support for interactive terminal access -# through the lookout agent (e.g. terminal-over-websocket or drydock-driven -# exec sessions in lookout's edge mode). +# Extends the portwing preset with exec support for interactive terminal access +# through the Portwing agent (e.g. terminal-over-websocket or drydock-driven +# exec sessions in Portwing's edge mode). # -# Allows: everything in lookout.yaml plus: +# Allows: everything in portwing.yaml plus: # POST /containers/{id}/exec — create an exec instance # POST /exec/{id}/start — start the exec (raw HTTP/1.1 upgrade) # POST /exec/{id}/resize — resize the PTY @@ -12,7 +12,7 @@ # # Exec body inspection: allow_privileged is disabled. allow_root_user is # enabled because most container workloads run as root and the caller -# (lookout or drydock) needs unrestricted exec for interactive sessions. +# (Portwing or drydock) needs unrestricted exec for interactive sessions. # If your deployment enforces non-root containers, set allow_root_user: false # and optionally add allowed_commands to pin the permitted argv prefixes. # @@ -26,15 +26,15 @@ # allow_root_user with an allowed_commands list (see drydock-with-selfupdate.yaml # for the pinned-command pattern) and drop insecure_allow_body_blind_writes. # -# Use this preset instead of lookout.yaml when: -# - Lookout's terminal/exec feature is in use -# - Drydock drives exec calls through the lookout edge mode -# - You need exec for container debugging via the lookout UI +# Use this preset instead of portwing.yaml when: +# - Portwing's terminal/exec feature is in use +# - Drydock drives exec calls through the Portwing edge mode +# - You need exec for container debugging via the Portwing UI # # Security note: exec grants arbitrary command execution inside any container -# that lookout can reach. Keep the proxy socket access-controlled (unix peer -# credentials or client CIDR allowlist) so only the lookout process can call -# the exec paths. See lookout.yaml for the exec-disabled baseline. +# that Portwing can reach. Keep the proxy socket access-controlled (unix peer +# credentials or client CIDR allowlist) so only the Portwing process can call +# the exec paths. See portwing.yaml for the exec-disabled baseline. upstream: socket: /var/run/docker.sock @@ -49,7 +49,7 @@ health: path: /health # Response redaction — all three disabled for the drydock passthrough topology. -# See lookout.yaml header for standalone-mode guidance. +# See portwing.yaml header for standalone-mode guidance. response: redact_mount_paths: false redact_container_env: false @@ -61,7 +61,7 @@ response: insecure_allow_body_blind_writes: true insecure_allow_read_exfiltration: true -# Container-create and image-pull inspection mirrors lookout.yaml. +# Container-create and image-pull inspection mirrors portwing.yaml. # Exec body inspection: allow_privileged denied, root user allowed for # interactive sessions. To pin allowed commands, replace allow_root_user # with an allowed_commands list (argv prefix allowlist). @@ -90,9 +90,9 @@ rules: action: allow # Container reads — list, inspect, stats, top, changes, and logs. - # /containers/*/logs is required by lookout's GetContainerLogs(). + # /containers/*/logs is required by Portwing's GetContainerLogs(). # /containers/*/archive, /containers/*/export, and /containers/*/attach - # are intentionally omitted — bulk-data exfiltration paths lookout does not use. + # are intentionally omitted — bulk-data exfiltration paths Portwing does not use. - match: { method: GET, path: "/containers/json" } action: allow - match: { method: GET, path: "/containers/*/json" } @@ -178,4 +178,4 @@ rules: # Deny everything else - match: { method: "*", path: "/**" } action: deny - reason: "not allowed by lookout-with-exec preset" + reason: "not allowed by portwing-with-exec preset" diff --git a/app/configs/lookout.yaml b/app/configs/portwing.yaml similarity index 86% rename from app/configs/lookout.yaml rename to app/configs/portwing.yaml index c5c7a0c4..574b56d8 100644 --- a/app/configs/lookout.yaml +++ b/app/configs/portwing.yaml @@ -1,13 +1,13 @@ -# Sockguard — Lookout Preset +# Sockguard — Portwing Preset # -# Optimized for the lookout Docker agent (https://github.com/CodesWhat/lookout). +# Optimized for the Portwing Docker agent (https://github.com/CodesWhat/portwing). # Allows: container list/inspect/stats/top/changes/logs, lifecycle (start/stop/ # restart/kill/rename/update/wait/create/remove), image pull/inspect/ # remove, /events, narrow network/volume/distribution reads, Swarm # service reads. # Denies: exec, build, secrets, plugins, raw archive/export/attach streams. # -# Log streaming: lookout's GetContainerLogs() calls GET /containers/{id}/logs +# Log streaming: Portwing's GetContainerLogs() calls GET /containers/{id}/logs # (including follow=1 for live streaming). This path is classified as a # read-exfiltration endpoint by sockguard's startup validator because logs can # contain secrets. insecure_allow_read_exfiltration: true below acknowledges @@ -18,11 +18,11 @@ # flag and accept that GetContainerLogs() will return 403. # # Redaction posture — redact_mount_paths and redact_container_env are DISABLED -# here because in the production tri-tool topology (sockguard → lookout → drydock) -# lookout forwards container inspect data to drydock whose update detection reads +# here because in the production tri-tool topology (sockguard → Portwing → drydock) +# Portwing forwards container inspect data to drydock whose update detection reads # HostConfig.Binds and Config.Env to recreate containers. If sockguard redacts # those fields to "", drydock faithfully forwards the placeholder into -# POST /containers/create and dockerd rejects with 400. Operators running lookout +# POST /containers/create and dockerd rejects with 400. Operators running Portwing # in standalone mode (not paired with drydock) can safely flip both to true: # # response: @@ -33,16 +33,16 @@ # logic reconstructs NetworkMode from the inspect spec. # # Exec: this preset denies all exec paths. To allow interactive exec sessions -# through lookout (e.g. for a terminal-over-websocket feature), use the -# lookout-with-exec.yaml preset instead. +# through Portwing (e.g. for a terminal-over-websocket feature), use the +# portwing-with-exec.yaml preset instead. # # Security tradeoff acknowledgment — log streaming: # GET /containers/{id}/logs is allowed below. sockguard requires # insecure_allow_read_exfiltration: true for this path because container logs # can contain environment-variable secrets or other sensitive output that -# should not be forwarded in all deployments. In the lookout topology the +# should not be forwarded in all deployments. In the Portwing topology the # agent is the sole consumer of the proxy socket and its own access controls -# gate who can reach the lookout HTTP API — this is an acceptable tradeoff. +# gate who can reach the Portwing HTTP API — this is an acceptable tradeoff. insecure_allow_read_exfiltration: true upstream: @@ -64,11 +64,11 @@ response: redact_container_env: false redact_network_topology: false -# Lookout needs container creation for its orchestration flows. Container-create +# Portwing needs container creation for its orchestration flows. Container-create # bodies are inspected by default; bind-mounted workloads are denied until their # host paths are allowlisted here. Image pulls are inspected too; this preset -# explicitly allows any registry so lookout can track arbitrary images while still -# denying fromSrc imports. The stock "runc" runtime is allowlisted because lookout +# explicitly allows any registry so Portwing can track arbitrary images while still +# denying fromSrc imports. The stock "runc" runtime is allowlisted because Portwing # (like drydock) recreates containers from inspect specs that carry an explicit # HostConfig.Runtime — without it every recreation is rejected at # POST /containers/create with 403 "runtime \"runc\" is not allowlisted". @@ -94,10 +94,10 @@ rules: action: allow # Container reads — list, inspect, stats, top, changes, and logs. - # /containers/*/logs is required by lookout's GetContainerLogs() call. + # /containers/*/logs is required by Portwing's GetContainerLogs() call. # /containers/*/archive, /containers/*/export, and /containers/*/attach # are intentionally omitted — those are bulk-data exfiltration paths that - # lookout does not use. insecure_allow_read_exfiltration: true (set above) + # Portwing does not use. insecure_allow_read_exfiltration: true (set above) # satisfies sockguard's startup validator for the logs path. - match: { method: GET, path: "/containers/json" } action: allow @@ -177,4 +177,4 @@ rules: # Deny everything else - match: { method: "*", path: "/**" } action: deny - reason: "not allowed by lookout preset" + reason: "not allowed by portwing preset" diff --git a/app/go.mod b/app/go.mod index 56f769c5..b7f8f484 100644 --- a/app/go.mod +++ b/app/go.mod @@ -9,7 +9,7 @@ require ( github.com/google/go-containerregistry v0.21.6 github.com/sigstore/protobuf-specs v0.5.1 github.com/sigstore/sigstore v1.10.8 - github.com/sigstore/sigstore-go v1.2.0 + github.com/sigstore/sigstore-go v1.2.1 github.com/spf13/cobra v1.10.2 github.com/spf13/viper v1.21.0 ) diff --git a/app/go.sum b/app/go.sum index a6047ac5..38d3ec91 100644 --- a/app/go.sum +++ b/app/go.sum @@ -291,8 +291,8 @@ github.com/sigstore/rekor-tiles/v2 v2.2.2-0.20260601073857-5d098a2b6443 h1:/CO8F github.com/sigstore/rekor-tiles/v2 v2.2.2-0.20260601073857-5d098a2b6443/go.mod h1:w1h8wF8vq9lHjmtRdwJiEaoVxhP+WHIMpj4M39pkzp0= github.com/sigstore/sigstore v1.10.8 h1:1Mgkxvkw4AXMfIP1DOjc6kw0GkUgA8pGVpveN/EfOq4= github.com/sigstore/sigstore v1.10.8/go.mod h1:f9+B/4iaYimvUkySyb2mvc73n3RLqNn24grHZM/ET8M= -github.com/sigstore/sigstore-go v1.2.0 h1:8k8sGMVUUWwZ/KA+s4Q66yEPEzcC1xZ8UsTgI46J9Fc= -github.com/sigstore/sigstore-go v1.2.0/go.mod h1:I8BqVwAb/SaQJ5pBu5IDFY+ksq8O/1/kCag8XUgrsko= +github.com/sigstore/sigstore-go v1.2.1 h1:YWP/rDbBaEBvtbkj6xtwsSj38ZCFEhTVVadNOXjVe3A= +github.com/sigstore/sigstore-go v1.2.1/go.mod h1:I8BqVwAb/SaQJ5pBu5IDFY+ksq8O/1/kCag8XUgrsko= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.8 h1:tofVQ+UWJgad/69I5zbqxdFCN5gpIn9tRQP7iBzIpBw= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.8/go.mod h1:73AfJE8H6w5KGCFPBu4x/OG+i1Yxgmh0L/FtV7prd88= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.8 h1:8Mt7J36GcUEmbiJaiFhz2tud5ZIgkfVVCe2H/WJCHmw= diff --git a/app/internal/banner/banner.go b/app/internal/banner/banner.go index 857d17b5..bae28e2b 100644 --- a/app/internal/banner/banner.go +++ b/app/internal/banner/banner.go @@ -2,44 +2,44 @@ package banner import ( + _ "embed" "fmt" "io" + "os" "runtime" "strings" + "unicode/utf8" "github.com/codeswhat/sockguard/internal/ui" "github.com/codeswhat/sockguard/internal/version" ) -const art = ` ... ... - .=+=.. .=+=.. - ..=--**.. ..=*--+.: - .:=-:=#*:.. .:*#+:--=.. - .:+--..+++=:..:..................=+++:.:-=:. - :.-=--...=+=:.-+***************=::-++:..:-=+.. - ..==--....:***++++++++++++####*+***=... ---+:. - ..==--..-+++++++++++++++++++***++++++=:.:--+:. - ..:+=::++++++++++++++++++++++++++++++++=.-=+.. - ....:++++%@%++#@%++++++++++@@%**#@%++++=.. .. - ..+++++*%@@@@@*+++++++++++%@@@@@*+++++-.: - :.:=+++++#@@@@#*++.++++=-++%@@@@#+++++==.. - ..-=++++%@@#*@%#:.:::::::.+%@**@@@*+++==:.. - ..:++++++++++::%@%..:**=:.-%@=.=+++++++++=... - ..=+==+=.:%@@%@@@.==.... .:=:-@@%@@@+..+===+:.. - ..:+===.*@@%:@*+@@:..:+...+...*@@:@*=@@@-:===+.. - ..====.#%%@@%:@==@@@*.. ...:%@@%:@=*@@@#%::===:.: - ...==-.#%-%%@@@@@%%%%%%=.*%%%%%@@@@@@%**%=.==-..: - ...:..+*#:.:-----::=*:::=*:::-----::.*%*..=-... - ..-====+#@*.#@@=:-:...::=:#@@@.=:#%*:....... - ..:+**%@#*===*+.:#%@@@@@@@@%=:::*%#:#@@@@%=.. - ..+%#*====+#@#===#@@@@@@@@@@@@=%%%@@%:+@@@@@@:. - ..*@@@@@@@%+==+%%+==%@%%%%%%%%%+*@@@@@@*.*%%%%:. - ..#@%%@@@@@@@@%===%@=-=+:........:%@@@@@@@=.....: - ..**...:*#%@@@@@@===%=.:**#***++=.#@@@@@@@@@=.. - ..**:.....=%%@@@@*-..-==========.*%@@@@@@@@@-.: - ...=#*:.. .-%%%%*.......:::... ..#%%%@@@@%%:.: - ...:*%#=:-%%-.. :...: ..:*#%%%#=... - ......... ... . .. +const art = ` ▓▓▒ + ▓██▓▒▒ + ▓▓▒▓▓ ▓█▓▓▓▓▓ + ██▓▓▓▓▓▓█▓▓▓▓▓▓ + ▓▓▓▒▒▓▒▓▓▓▓▓▓▒▓▒ + ▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓ + ▒▒▒▓▒░▒▒▒▒▒▒▒▓▓▓▓▓▓▓▒▒▒ + ▒▒▓▓▒▒▒▒▒▒░▒▒▓▓▓▓▓▓▓▓▓▓▒ + ▒▒▓▓▓▓▓▒░▒▒▒░▒▓▓▓▒▒▓▓▓▓▓▒ + ██▓█░ ░▒▓▓▒░▓▓▓░░▓▓▓▒▒▓▓▓▓▓▒ + ███▒ ░▓▓▒░░░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒ ▓▓▓▓ + ░░░░░░░ ░ ░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓██▓▓▓▓▒▒▒▒▒▒▒▒▒▒ ▓▒▓▓ + ░░░░░░░░░░░░▒▓▓▓▓▓▓▓▓▓▓▓▓█▓▓██▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▓▓▓▓▓ + ░░░░░░░░░░░░░▓▓▓▓▓▓▓▓▓██████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ + ░░░░░░░░░░░░▓▓▓▓▓████▒▓█▓▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒ + ░▒▒▒░░░░░▒▓███▒▓████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒ + ▓█▓▓█████▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▒ + ▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▒▒ + ░▒░▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒ + ░░░░░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒ + ░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒ + ▒▒░░░▒▓▓▓▓▓▒▒▓█▓▓▓▓▓▓▓▓▓▓▓▓▓█▓▓▓▒▒▓▒ + ▓▓▓▓▒▒▒▓▓▓▓▓▒▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▒▒▓▓ + ▒▓▓▓██▓▓▓▓▓▓▓▓▓███▓██▓██████▓▓▓▓▓▓▓▓ + ▓▓▓▓██▓▓▓▓▓▓▓▓▓ ██████▓▓▓▓▓▓▓▓ + ███▓▓▓▓▓▓▓▓▓ ██▓▓▓▓▓ ` // artMaxWidth is the widest character row of the banner, computed @@ -48,13 +48,29 @@ const art = ` ... ... var artMaxWidth = func() int { m := 0 for _, line := range strings.Split(strings.TrimRight(art, "\n"), "\n") { - if len(line) > m { - m = len(line) + // Count display columns (runes), not bytes — the art uses + // multi-byte block glyphs (░▒▓█), so len() would overcount ~3x + // and break the centering math. + if w := utf8.RuneCountInString(line); w > m { + m = w } } return m }() +// colorArt is a pre-rendered 24-bit (truecolor) half-block rendering of the +// sockguard logo, exactly colorArtWidth columns wide, generated from +// sockguard-logo.png by half-block (▀) truecolor sampling. It is shown only on +// truecolor terminals; everything else falls back to the monochrome `art` +// above. +// +//go:embed dog_color.ans +var colorArt string + +// colorArtWidth is the fixed display width (columns) of colorArt. Its rows +// carry ANSI escapes, so this is a known constant rather than a rune count. +const colorArtWidth = 50 + // Info is the runtime summary rendered beneath the ASCII art. type Info struct { Listen string @@ -72,9 +88,15 @@ func Render(w io.Writer, info Info) { access = "on" } p := ui.New(w) + cols := terminalCols(w) fmt.Fprintln(w) - fmt.Fprint(w, p.Cyan(centerArt(art, terminalCols(w)))) + if p.Enabled() && truecolor() { + // colorArt already carries per-cell ANSI; don't wrap it in Cyan. + fmt.Fprint(w, centerArt(colorArt, cols, colorArtWidth)) + } else { + fmt.Fprint(w, p.Cyan(centerArt(art, cols, artMaxWidth))) + } fmt.Fprintln(w) fmt.Fprintf(w, " %s %s %s\n", p.Bold("sockguard"), @@ -98,16 +120,28 @@ func shortCommit(c string) string { return c } +// truecolor reports whether the terminal advertises 24-bit color via +// COLORTERM. The colored banner emits 24-bit escapes, so without this we fall +// back to the monochrome art rather than send codes a 16/256-color terminal +// would mangle. +func truecolor() bool { + switch os.Getenv("COLORTERM") { + case "truecolor", "24bit": + return true + } + return false +} + // centerArt left-pads every row of the banner so the full block is // horizontally centered inside a terminal of `cols` columns. If cols // is 0 (no TTY) or narrower than the art itself, the art is returned // unchanged so piped output and narrow terminals fall back to the // original left-aligned rendering. -func centerArt(block string, cols int) string { - if cols <= artMaxWidth { +func centerArt(block string, cols, width int) string { + if cols <= width { return block } - pad := strings.Repeat(" ", (cols-artMaxWidth)/2) + pad := strings.Repeat(" ", (cols-width)/2) var b strings.Builder trimmed := strings.TrimRight(block, "\n") trailingNewlines := len(block) - len(trimmed) diff --git a/app/internal/banner/banner_test.go b/app/internal/banner/banner_test.go index 8d170f36..19824943 100644 --- a/app/internal/banner/banner_test.go +++ b/app/internal/banner/banner_test.go @@ -6,6 +6,7 @@ import ( "strings" "syscall" "testing" + "unicode/utf8" ) func TestRenderContainsRuntimeInfo(t *testing.T) { @@ -77,20 +78,16 @@ func TestCenterArtPreservesTrailingNewline(t *testing.T) { } } -// centerArtBlock wraps centerArt with a controlled artMaxWidth so the -// tests don't depend on the real banner art's exact dimensions. +// centerArtBlock wraps centerArt with a width measured from the test input so +// the tests don't depend on the real banner art's exact dimensions. func centerArtBlock(in string, cols int) string { - // Save-restore the package-level max width so the test stays - // isolated from the real banner. - old := artMaxWidth - artMaxWidth = 0 + width := 0 for _, line := range strings.Split(strings.TrimRight(in, "\n"), "\n") { - if len(line) > artMaxWidth { - artMaxWidth = len(line) + if w := utf8.RuneCountInString(line); w > width { + width = w } } - defer func() { artMaxWidth = old }() - return centerArt(in, cols) + return centerArt(in, cols, width) } func TestTerminalColsNonFileWriterReturnsZero(t *testing.T) { diff --git a/app/internal/banner/dog_color.ans b/app/internal/banner/dog_color.ans new file mode 100644 index 00000000..64997453 --- /dev/null +++ b/app/internal/banner/dog_color.ans @@ -0,0 +1,22 @@ +                  ▄▄▄                              +            ▄    ▄▀▀▀▀▄                            +           ▀▀▀▀▄ ▀▀▀▀▀▀▄                           +           ▀▀▀▀▀▀▀▀▀▀▀▀▀▄                          +        ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                          +      ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                        +     ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                       +  ▄▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                       + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄                ▄▄   +  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄▄▄▄▄▄▄▄▄      ▄▀▀▄  +  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄▀▀▀▀  +  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀   +   ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄   +     ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀   +           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀  +            ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀  +             ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀  +              ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀  +               ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀   +               ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀   +               ▀▀▀▀▀▀▀▀▀▀▀▀▀       ▀▀▀▀▀▀▀▀▀▀▀▀▀   +               ▀▀▀▀▀▀▀▀▀▀▀▀▀        ▀▀▀▀▀▀▀▀▀▀▀    diff --git a/docs/content/docs/presets.mdx b/docs/content/docs/presets.mdx index ec572ddb..93f25314 100644 --- a/docs/content/docs/presets.mdx +++ b/docs/content/docs/presets.mdx @@ -1,6 +1,6 @@ --- title: Presets -description: Ready-made sockguard configs for drydock, drydock with self-update, lookout, lookout with exec, Traefik, Portainer, Watchtower, Homepage, Homarr, Diun, Autoheal, GitHub Actions and GitLab runners, the CIS Docker Benchmark, and read-only dashboards. +description: Ready-made sockguard configs for drydock, drydock with self-update, Portwing, Portwing with exec, Traefik, Portainer, Watchtower, Homepage, Homarr, Diun, Autoheal, GitHub Actions and GitLab runners, the CIS Docker Benchmark, and read-only dashboards. --- Sockguard ships with ready-made config presets for common Docker consumers. All presets are bundled in the container image at `/etc/sockguard/`. @@ -48,11 +48,11 @@ Without this preset (using drydock.yaml), the self-update still completes — th old container is renamed, the new one starts — but the finalize callback exec is denied and drydock logs the failure. Use this preset to get a clean finalize. -## Lookout (`lookout.yaml`) +## Portwing (`portwing.yaml`) -Optimized for the [lookout](https://github.com/CodesWhat/lookout) Docker agent. +Optimized for the [Portwing](https://github.com/CodesWhat/portwing) Docker agent. -**Use for:** lookout in the tri-tool topology (sockguard → lookout → drydock), or +**Use for:** Portwing in the tri-tool topology (sockguard → Portwing → drydock), or any remote Docker agent that needs lifecycle control, image pull, and event streaming. ```yaml @@ -62,7 +62,7 @@ any remote Docker agent that needs lifecycle control, image pull, and event stre # Allows: network read, volume read, distribution, Swarm service reads # Denies: exec, build, swarm writes, secrets, plugins, raw archive/export/attach streams # insecure_allow_read_exfiltration=true — required because GET /containers/*/logs is allowed -# (lookout's GetContainerLogs()); container logs can carry secrets. Drop the logs rule and this +# (Portwing's GetContainerLogs()); container logs can carry secrets. Drop the logs rule and this # flag to harden. /containers/*/archive, /export, /attach stay denied (bulk-exfil paths). # Response redactions disabled (redact_mount_paths=false, redact_container_env=false, # redact_network_topology=false) — required for drydock passthrough topology so @@ -70,16 +70,16 @@ any remote Docker agent that needs lifecycle control, image pull, and event stre # Standalone operators not paired with drydock can re-enable all three redactions ``` -## Lookout with Exec (`lookout-with-exec.yaml`) +## Portwing with Exec (`portwing-with-exec.yaml`) -Extends the lookout preset with exec support for interactive terminal access through -the lookout agent, e.g. terminal-over-websocket or drydock-driven exec in edge mode. +Extends the Portwing preset with exec support for interactive terminal access through +the Portwing agent, e.g. terminal-over-websocket or drydock-driven exec in edge mode. -**Use for:** lookout deployments where exec sessions are needed (interactive terminals, +**Use for:** Portwing deployments where exec sessions are needed (interactive terminals, drydock edge mode exec calls). ```yaml -# Extends lookout.yaml with: +# Extends portwing.yaml with: # Allows: POST /containers/{id}/exec, POST /exec/{id}/start, # POST /exec/{id}/resize, GET /exec/{id}/json # Exec body inspection: allow_privileged=false, allow_root_user=true @@ -87,8 +87,8 @@ drydock edge mode exec calls). # non-root or command-pinned deployments) # insecure_allow_body_blind_writes=true — interactive exec can't be pinned to a fixed argv, # so the body-blind-write guard is bypassed; the allow_privileged/allow_root_user layer still -# applies. insecure_allow_read_exfiltration=true is inherited from lookout.yaml for the -# GET /containers/*/logs rule (see the Lookout section above). +# applies. insecure_allow_read_exfiltration=true is inherited from portwing.yaml for the +# GET /containers/*/logs rule (see the Portwing section above). ``` ## Traefik (`traefik.yaml`) diff --git a/docs/package.json b/docs/package.json index 57a00d75..9c91cb47 100644 --- a/docs/package.json +++ b/docs/package.json @@ -18,13 +18,13 @@ "react-dom": "^19.2.7" }, "devDependencies": { - "@tailwindcss/postcss": "4.3.0", + "@tailwindcss/postcss": "4.3.1", "@types/mdx": "2.0.14", "@types/node": "^25.9.2", "@types/react": "^19.2.17", "@types/react-dom": "19.2.3", "postcss": "^8.5.15", - "tailwindcss": "4.3.0", + "tailwindcss": "4.3.1", "typescript": "^6.0.3" }, "overrides": { diff --git a/docs/public/sockguard-logo.png b/docs/public/sockguard-logo.png index 4809ae6d..bcb49169 100644 Binary files a/docs/public/sockguard-logo.png and b/docs/public/sockguard-logo.png differ diff --git a/examples/compose/lookout/README.md b/examples/compose/lookout/README.md deleted file mode 100644 index c3c7907b..00000000 --- a/examples/compose/lookout/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Sockguard + lookout - -**Who this is for:** Teams running [lookout](https://github.com/CodesWhat/lookout) as a remote Docker agent and wanting to eliminate the raw Docker socket mount from the lookout container. - -**What's exposed:** A unix socket shared via a named volume. Lookout connects to `/var/run/sockguard/sockguard.sock` instead of `/var/run/docker.sock`. Port 4000 is the lookout API. - -## Security tradeoffs - -| Control | Status | -|---|---| -| sockguard: `read_only`, `cap_drop: ALL`, `no-new-privileges` | Enabled | -| No raw socket in lookout container | Yes — named volume unix socket | -| Exec denied | Yes | -| Build denied | Yes | -| Log streaming allowed; raw archive/export/attach denied | `insecure_allow_read_exfiltration: true` (required for lookout's `GetContainerLogs()`; `/containers/*/archive`, `/export`, `/attach` stay denied) | -| Image pulls | All registries allowed (lookout tracks arbitrary images) | -| Bind mounts on container create | Denied unless you add paths to `allowed_bind_mounts` | -| Response redaction (env, mounts, network topology) | Disabled — required for drydock passthrough topology | - -## Redaction note - -The lookout preset disables `redact_mount_paths`, `redact_container_env`, and `redact_network_topology` because in the tri-tool topology (sockguard → lookout → drydock) lookout forwards container inspect data to drydock, which uses it to recreate containers during updates. If sockguard redacts those fields, drydock cannot reconstruct the original container spec. - -If you run lookout in standalone mode without drydock, re-enable redactions by editing `sockguard.yaml`: - -```yaml -response: - redact_mount_paths: true - redact_container_env: true - redact_network_topology: true -``` - -## Usage - -```bash -docker compose up -d -# lookout API: http://localhost:4000 -``` - -To allowlist bind mounts for containers lookout recreates, add host paths to `sockguard.yaml` under `request_body.container_create.allowed_bind_mounts`. - -To enable exec sessions (interactive terminal access), switch to `app/configs/lookout-with-exec.yaml`. diff --git a/examples/compose/portwing/README.md b/examples/compose/portwing/README.md new file mode 100644 index 00000000..11fd2899 --- /dev/null +++ b/examples/compose/portwing/README.md @@ -0,0 +1,42 @@ +# Sockguard + Portwing + +**Who this is for:** Teams running [Portwing](https://github.com/CodesWhat/portwing) as a remote Docker agent and wanting to eliminate the raw Docker socket mount from the Portwing container. + +**What's exposed:** A unix socket shared via a named volume. Portwing connects to `/var/run/sockguard/sockguard.sock` instead of `/var/run/docker.sock`. Port 4000 is the Portwing API. + +## Security tradeoffs + +| Control | Status | +|---|---| +| sockguard: `read_only`, `cap_drop: ALL`, `no-new-privileges` | Enabled | +| No raw socket in Portwing container | Yes — named volume unix socket | +| Exec denied | Yes | +| Build denied | Yes | +| Log streaming allowed; raw archive/export/attach denied | `insecure_allow_read_exfiltration: true` (required for Portwing's `GetContainerLogs()`; `/containers/*/archive`, `/export`, `/attach` stay denied) | +| Image pulls | All registries allowed (Portwing tracks arbitrary images) | +| Bind mounts on container create | Denied unless you add paths to `allowed_bind_mounts` | +| Response redaction (env, mounts, network topology) | Disabled — required for drydock passthrough topology | + +## Redaction note + +The Portwing preset disables `redact_mount_paths`, `redact_container_env`, and `redact_network_topology` because in the tri-tool topology (sockguard → Portwing → drydock) Portwing forwards container inspect data to drydock, which uses it to recreate containers during updates. If sockguard redacts those fields, drydock cannot reconstruct the original container spec. + +If you run Portwing in standalone mode without drydock, re-enable redactions by editing `sockguard.yaml`: + +```yaml +response: + redact_mount_paths: true + redact_container_env: true + redact_network_topology: true +``` + +## Usage + +```bash +docker compose up -d +# Portwing API: http://localhost:4000 +``` + +To allowlist bind mounts for containers Portwing recreates, add host paths to `sockguard.yaml` under `request_body.container_create.allowed_bind_mounts`. + +To enable exec sessions (interactive terminal access), switch to `app/configs/portwing-with-exec.yaml`. diff --git a/examples/compose/lookout/docker-compose.yml b/examples/compose/portwing/docker-compose.yml similarity index 70% rename from examples/compose/lookout/docker-compose.yml rename to examples/compose/portwing/docker-compose.yml index 1808796e..71572cc2 100644 --- a/examples/compose/lookout/docker-compose.yml +++ b/examples/compose/portwing/docker-compose.yml @@ -1,14 +1,14 @@ -# examples/compose/lookout/docker-compose.yml +# examples/compose/portwing/docker-compose.yml # -# Sockguard + lookout — unix-socket mode, lookout preset. +# Sockguard + Portwing — unix-socket mode, portwing preset. # Sockguard writes a filtered unix socket into a shared named volume; -# lookout reads that socket rather than mounting /var/run/docker.sock. +# Portwing reads that socket rather than mounting /var/run/docker.sock. # -# lookout needs: container list/inspect/stats, lifecycle (start/stop/ +# Portwing needs: container list/inspect/stats, lifecycle (start/stop/ # restart/kill/rename/update/create/remove), image pull/inspect/remove, # /events, narrow network/volume/distribution reads, and Swarm service reads. -# The lookout preset covers all of these. Log streaming (GET /containers/*/logs) -# is allowed because lookout's GetContainerLogs() API needs it, and +# The portwing preset covers all of these. Log streaming (GET /containers/*/logs) +# is allowed because Portwing's GetContainerLogs() API needs it, and # insecure_allow_read_exfiltration: true acknowledges that tradeoff; exec, build, # secrets, and raw archive/export/attach streams stay denied. @@ -28,8 +28,8 @@ services: environment: - SOCKGUARD_LISTEN_SOCKET=/var/run/sockguard/sockguard.sock - lookout: - image: codeswhat/lookout:latest + portwing: + image: codeswhat/portwing:latest restart: unless-stopped depends_on: - sockguard diff --git a/examples/compose/lookout/sockguard.yaml b/examples/compose/portwing/sockguard.yaml similarity index 89% rename from examples/compose/lookout/sockguard.yaml rename to examples/compose/portwing/sockguard.yaml index 4733f13c..59d701d7 100644 --- a/examples/compose/lookout/sockguard.yaml +++ b/examples/compose/portwing/sockguard.yaml @@ -1,10 +1,10 @@ -# Sockguard config for lookout — mirrors the shipped lookout preset. -# Copy of app/configs/lookout.yaml; embedded here so the compose stack +# Sockguard config for Portwing — mirrors the shipped portwing preset. +# Copy of app/configs/portwing.yaml; embedded here so the compose stack # is self-contained. Update both files together if you change rules. # -# Log streaming: GET /containers/{id}/logs is required by lookout's +# Log streaming: GET /containers/{id}/logs is required by Portwing's # GetContainerLogs() API. insecure_allow_read_exfiltration: true acknowledges -# that container logs can contain secrets; see app/configs/lookout.yaml for +# that container logs can contain secrets; see app/configs/portwing.yaml for # the full security-tradeoff rationale. upstream: @@ -109,4 +109,4 @@ rules: - match: { method: "*", path: "/**" } action: deny - reason: "not allowed by lookout preset" + reason: "not allowed by portwing preset" diff --git a/package-lock.json b/package-lock.json index 1c076cbe..7452e60f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,13 +32,13 @@ "react-dom": "^19.2.7" }, "devDependencies": { - "@tailwindcss/postcss": "4.3.0", + "@tailwindcss/postcss": "4.3.1", "@types/mdx": "2.0.14", "@types/node": "^25.9.2", "@types/react": "^19.2.17", "@types/react-dom": "19.2.3", "postcss": "^8.5.15", - "tailwindcss": "4.3.0", + "tailwindcss": "4.3.1", "typescript": "^6.0.3" } }, @@ -55,9 +55,9 @@ } }, "node_modules/@biomejs/biome": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.16.tgz", - "integrity": "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.0.tgz", + "integrity": "sha512-4kURkd9hAPrdDM3C9n82ycYgx8hvQcW6MjKTEejruj8rK0N8P3OPpdy8BvI8kt3KWY4ycF5XtDOrktetEfhfuw==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -71,20 +71,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.4.16", - "@biomejs/cli-darwin-x64": "2.4.16", - "@biomejs/cli-linux-arm64": "2.4.16", - "@biomejs/cli-linux-arm64-musl": "2.4.16", - "@biomejs/cli-linux-x64": "2.4.16", - "@biomejs/cli-linux-x64-musl": "2.4.16", - "@biomejs/cli-win32-arm64": "2.4.16", - "@biomejs/cli-win32-x64": "2.4.16" + "@biomejs/cli-darwin-arm64": "2.5.0", + "@biomejs/cli-darwin-x64": "2.5.0", + "@biomejs/cli-linux-arm64": "2.5.0", + "@biomejs/cli-linux-arm64-musl": "2.5.0", + "@biomejs/cli-linux-x64": "2.5.0", + "@biomejs/cli-linux-x64-musl": "2.5.0", + "@biomejs/cli-win32-arm64": "2.5.0", + "@biomejs/cli-win32-x64": "2.5.0" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.16.tgz", - "integrity": "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-Mn3Fwi3SA5fgmfCPqmzpWF2DLZnms3BVAhM088nTnGrTZmHS3wwIjcoZPqpXeNgd3DrrLH6xp8vTLIBuJoZiXw==", "cpu": [ "arm64" ], @@ -99,9 +99,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.16.tgz", - "integrity": "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.0.tgz", + "integrity": "sha512-rg3VPL5P8mYro6pqlXYXuJWph21slVp3SZtAqWSrkZs40d2gTzYmHF8E/X1iTID25btmNKltNDJ926sqVBp7DQ==", "cpu": [ "x64" ], @@ -116,9 +116,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.16.tgz", - "integrity": "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.0.tgz", + "integrity": "sha512-tl+LW8fdD96/xdeWtWwc82LIOc5CoY7N2AsogLTp5R4ECErYt+8Jl/N68ezN9vzSiqPTxw6vjcihoLPYKZHrlw==", "cpu": [ "arm64" ], @@ -136,9 +136,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.16.tgz", - "integrity": "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-vQdM4oSGaf7ZNeGO9w5+Y8SBtyser9M6znxYbm7Ec8wInxJu1WiKxFYZW5Auj2d80bcVvefuGGRxoFOE0eee8g==", "cpu": [ "arm64" ], @@ -156,9 +156,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.16.tgz", - "integrity": "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.0.tgz", + "integrity": "sha512-zpEGf4RQbFEh8Vt7OmavLyyOzRbtcE9osCqrS1kfvt8jDvxwhKXLSf7n0ebr/ov0RJ9ssP+lhs6C8a9WwFvrQA==", "cpu": [ "x64" ], @@ -176,9 +176,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.16.tgz", - "integrity": "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-+9hIcMngJ+yGUahXqZuZ8CoWKJE9SAZsFsM3QDvXpNsLbXZ9lqVzgBhOk/jTSYkOA0GLP9eu3teukqpLUojHMg==", "cpu": [ "x64" ], @@ -196,9 +196,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.16.tgz", - "integrity": "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.0.tgz", + "integrity": "sha512-jB0wAvTLI4itx5VidqVUejPQFhRUxiZ9l9FvZ26D5fl6t3qme+ZB4PD3bTSeL1vZ8NI2Rx/zj6H9zcESuGHKGw==", "cpu": [ "arm64" ], @@ -213,9 +213,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "2.4.16", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.16.tgz", - "integrity": "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.0.tgz", + "integrity": "sha512-VT/lF+GId+67j8aDfLkxdxNoVApsPSTbyAtB3jJq0IWTrY77WXfbPfpngxq0bA6JCEv/7k8C9qWjDRKRznDlyw==", "cpu": [ "x64" ], @@ -261,9 +261,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -277,9 +277,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -293,9 +293,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -309,9 +309,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -325,9 +325,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -341,9 +341,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -357,9 +357,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -373,9 +373,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -389,9 +389,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -405,9 +405,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -421,9 +421,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -437,9 +437,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -453,9 +453,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -469,9 +469,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -485,9 +485,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -501,9 +501,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -517,9 +517,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -533,9 +533,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -549,9 +549,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -565,9 +565,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -581,9 +581,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -597,9 +597,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -613,9 +613,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -629,9 +629,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -645,9 +645,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -661,9 +661,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -715,9 +715,9 @@ "license": "MIT" }, "node_modules/@fuma-translate/react": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@fuma-translate/react/-/react-0.0.3.tgz", - "integrity": "sha512-EGaUcCyXM2p1HMV6D/NM1kZjIwCMitO+lmDni7b/J0St8IAZ5cUddhtqPqYyMtFj6Og721B5dXSIN6IDq8wf/g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@fuma-translate/react/-/react-1.0.2.tgz", + "integrity": "sha512-uOiOtBx3nRXR8Nu1GzBf1tApgF1FErDBTHxRIAQeyQdyOoZbrNRN6H4kDCWObY4qyGeGbHydG0DHzgeUgFDMIw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -2201,19 +2201,19 @@ "license": "MIT" }, "node_modules/@radix-ui/react-accordion": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.13.tgz", - "integrity": "sha512-xITxBB2p5m5tAe7M0F95kb4uAh7jSIKGlExMEm93HlW+XxZHV2eXFbPWLktd4JhRiwcnXNbO7iekcrbZy6ZCvA==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.14.tgz", + "integrity": "sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collapsible": "1.1.13", - "@radix-ui/react-collection": "1.1.9", + "@radix-ui/react-collapsible": "1.1.14", + "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { @@ -2232,12 +2232,12 @@ } }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.9.tgz", - "integrity": "sha512-yqHW5WQ/cTpU/un7dqqIKNy2iRU8BC0JB78PEzTfCCYvZu1U6W9KwObAniMk9nhSfyotKPQTYaUD/HB0f5muig==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.10.tgz", + "integrity": "sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.5" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -2255,9 +2255,9 @@ } }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.13.tgz", - "integrity": "sha512-F0s8+p2XNpfc3k02zBfB0jPWbkHVG162+p7BdUMyJ2308QMqZ+oaclX+FAzKFovgL5OqRU+Rvy6f/vbdlJVaqA==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.14.tgz", + "integrity": "sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", @@ -2265,7 +2265,7 @@ "@radix-ui/react-context": "1.1.4", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, @@ -2285,15 +2285,15 @@ } }, "node_modules/@radix-ui/react-collection": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.9.tgz", - "integrity": "sha512-zuSVi7ziP7uQRqc+yGxsKJfNkdyHv3ZKDaHe0gzg4dRgws96TPKWIiz84tVHP4GEcEl8bC0mdt17NkcxaJHmaQ==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.10.tgz", + "integrity": "sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-primitive": "2.1.5", - "@radix-ui/react-slot": "1.2.5" + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -2341,22 +2341,22 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.16.tgz", - "integrity": "sha512-l9ok83YBclEZhbjgzt76Hw733e6cvRKPNgO6GJ/IETlufXG9p+fRu2wlvpImQvR6xdJ8h7J8J2DBvsPEiEsKMw==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.17.tgz", + "integrity": "sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.12", + "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.9", + "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-portal": "1.1.11", + "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.5", - "@radix-ui/react-slot": "1.2.5", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" @@ -2392,14 +2392,14 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.12.tgz", - "integrity": "sha512-MhoruH6xEzsbvOmo4TNgMfmtvRGyDZw4MDSdf4ybMHfezjqwzv6hyd4lsMzBp8K9Sn6sGzCF62x1I7BYUECXOg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.13.tgz", + "integrity": "sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-escape-keydown": "1.1.2" }, @@ -2434,13 +2434,13 @@ } }, "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.9.tgz", - "integrity": "sha512-9Se8t+Zry+1rEOL7Y6l/4ANYU/TOtAtf8O2fKdwLltcaMcm6kOqYGbzO4tMFQ0bvzO920pRAoHpFZ4W85S3keQ==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.10.tgz", + "integrity": "sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { @@ -2477,25 +2477,25 @@ } }, "node_modules/@radix-ui/react-navigation-menu": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.15.tgz", - "integrity": "sha512-/fS8hKCcRt4DwCGa5QIB3juRXmfYSOk4a2AEe/BDIyy7Hm+eje2Y13oUx5zejl+wFt1owrM7E8NWlbaEl5EGpg==", + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.16.tgz", + "integrity": "sha512-nJ0SkrSQgudyYhMiYeHA1ayLVuduEJCFLan1RZZN7c9kqzzCFLaU9kuy81uNtqzweM9YaQPgWzxi9MwQ9jZ04g==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collection": "1.1.9", + "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.12", + "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", - "@radix-ui/react-visually-hidden": "1.2.5" + "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", @@ -2513,23 +2513,23 @@ } }, "node_modules/@radix-ui/react-popover": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.16.tgz", - "integrity": "sha512-8brVpAU5Uq7Bh0c8EFc4ZTf2JJTYn0o+1L+CUJB3UYIOkTjKGMgoHvduylrahdmNlr3DfH0rFq2DrbNZXgaspw==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.17.tgz", + "integrity": "sha512-/YSAOdJ7YJvdn7bn5sdSx2egW+SKY+u7O5RyAVs94Ymrg2fg5QTSFPMRkzvhGyFuE4/qsmPBdrwYoZMZh/4f+g==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-dismissable-layer": "1.1.12", + "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-focus-guards": "1.1.4", - "@radix-ui/react-focus-scope": "1.1.9", + "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-popper": "1.3.0", - "@radix-ui/react-portal": "1.1.11", + "@radix-ui/react-popper": "1.3.1", + "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.5", - "@radix-ui/react-slot": "1.2.5", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" @@ -2550,16 +2550,16 @@ } }, "node_modules/@radix-ui/react-popper": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.0.tgz", - "integrity": "sha512-9PB589e1aWZbrlFUHdz6WiPCL+xLZHQFX7oibqG/6Q0SwOkxDyQX9W/cyPa+sAPPKuC8cpLCpRczE5a/1DiwVQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.1.tgz", + "integrity": "sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.9", + "@radix-ui/react-arrow": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-rect": "1.1.2", @@ -2582,12 +2582,12 @@ } }, "node_modules/@radix-ui/react-portal": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.11.tgz", - "integrity": "sha512-UEytdjgEh2tJGgD/gZK4FUx6t1rNIlM3U0DENhSrG7I75FGm1DnaDuVUWF1pWAWUwGmn1sCJ1VGHn8LhN1aTOw==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.12.tgz", + "integrity": "sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { @@ -2629,12 +2629,12 @@ } }, "node_modules/@radix-ui/react-primitive": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.5.tgz", - "integrity": "sha512-zifXeB8Y88qCYx8PLZ5oQb32KwZub+s925mMoZsBBq9KUQqWKkREubTfs6ASjRPPBe7Jt9O8OHH89+95VG+grA==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz", + "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.5" + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -2652,18 +2652,18 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.12.tgz", - "integrity": "sha512-FvgPt1bRmg8Xt2QpF7NUZW3dE0ZQHGm41dAdgT2J2GJPoIXz+9Em3NobAxf4fupcxhgHu03E5CRiU2MWvObXyg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.13.tgz", + "integrity": "sha512-9gkwneI0guf8JDmrFxPjJF6Ozzgioyw+/lonYNCwefS9ZHA05er0BVHiXr+LbWGHxUfczvMY6G1oiZZi1VzjRw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", - "@radix-ui/react-collection": "1.1.9", + "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3" }, @@ -2683,9 +2683,9 @@ } }, "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.11.tgz", - "integrity": "sha512-DS39ziOgea75U/TrXKU2/oKp0be2jrDHnzFLvahg/0iNAT1Zq16e4Uw0WXwyXvsK+mG3BRyMb7A3NRZMDuEXtQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.12.tgz", + "integrity": "sha512-xuafVzQiTCLsyEjakowTdG3OgTXsmO7IdCiO77otIa+z44xoLNs9Do5eg7POFumIOCjtG6djfm6RKUKpUa/csA==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.2", @@ -2694,7 +2694,7 @@ "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.5", + "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2" }, @@ -2714,9 +2714,9 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.5.tgz", - "integrity": "sha512-rCMO3QsIVKv5JTY5CVbo2MvO77SpEqqYc8AvRE7OWqRDOIqAKjsp+DrmnY9uc8NPdxB5E2z47HTYGeE2+NTptg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" @@ -2732,9 +2732,9 @@ } }, "node_modules/@radix-ui/react-tabs": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.14.tgz", - "integrity": "sha512-D5jwp9JNuwDeCw3CYD2Fz+sSHo0droQjC8u75dJHe4aWr5q6yBiXZU+hurXnKudRgEpUkD5TsI6bjHPo5ThUxA==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.15.tgz", + "integrity": "sha512-kxc9gI6/HfcU4nfMMVS3AmQK414kbU1IE6UCJmMmxjhO3cRPXOyYnmvyKD+ODt7q56nRq9l7Wovi6uaGwKgMlg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.4", @@ -2742,8 +2742,8 @@ "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", - "@radix-ui/react-primitive": "2.1.5", - "@radix-ui/react-roving-focus": "1.1.12", + "@radix-ui/react-primitive": "2.1.6", + "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { @@ -2898,12 +2898,12 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.5.tgz", - "integrity": "sha512-tPcHNI3FajdDBFpl/Ez1m2WL0ufJqBKyHxMDBvKitopamK36WwBGOMicuMEZKkM5Wce41QxUyv6BsiqfrWBiGg==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.6.tgz", + "integrity": "sha512-jCE0WljWifTI4niIMCll06kGpsJTAPiZVU9H4WR1N6qW7At9ystHbN7dDB+we2xH535roFHj7qKS+RGj0FMDWQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.5" + "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", @@ -3042,47 +3042,47 @@ } }, "node_modules/@tailwindcss/node": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz", - "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.21.0", - "jiti": "^2.6.1", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.3.0" + "tailwindcss": "4.3.1" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz", - "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", "license": "MIT", "engines": { "node": ">= 20" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.0", - "@tailwindcss/oxide-darwin-arm64": "4.3.0", - "@tailwindcss/oxide-darwin-x64": "4.3.0", - "@tailwindcss/oxide-freebsd-x64": "4.3.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", - "@tailwindcss/oxide-linux-x64-musl": "4.3.0", - "@tailwindcss/oxide-wasm32-wasi": "4.3.0", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz", - "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", "cpu": [ "arm64" ], @@ -3096,9 +3096,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz", - "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", "cpu": [ "arm64" ], @@ -3112,9 +3112,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz", - "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", "cpu": [ "x64" ], @@ -3128,9 +3128,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz", - "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", "cpu": [ "x64" ], @@ -3144,9 +3144,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz", - "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", "cpu": [ "arm" ], @@ -3160,9 +3160,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz", - "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", "cpu": [ "arm64" ], @@ -3179,9 +3179,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz", - "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", "cpu": [ "arm64" ], @@ -3198,9 +3198,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz", - "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", "cpu": [ "x64" ], @@ -3217,9 +3217,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz", - "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", "cpu": [ "x64" ], @@ -3236,9 +3236,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz", - "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -3257,7 +3257,7 @@ "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", - "@tybys/wasm-util": "^0.10.1", + "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "engines": { @@ -3265,9 +3265,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz", - "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", "cpu": [ "arm64" ], @@ -3281,9 +3281,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz", - "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", "cpu": [ "x64" ], @@ -3297,16 +3297,16 @@ } }, "node_modules/@tailwindcss/postcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.0.tgz", - "integrity": "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.1.tgz", + "integrity": "sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==", "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.3.0", - "@tailwindcss/oxide": "4.3.0", - "postcss": "^8.5.10", - "tailwindcss": "4.3.0" + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "postcss": "8.5.15", + "tailwindcss": "4.3.1" } }, "node_modules/@turbo/darwin-64": { @@ -3542,9 +3542,9 @@ } }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -3600,9 +3600,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.35", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.35.tgz", - "integrity": "sha512-honAfLBde0HAFLdNyBEfuuENkF6zR+ozxqxa/2zJKHBe1qzLqyTSeRKpdPEHAP03rlDGyQOPnCSxnVpVqQo9Mg==", + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -3828,9 +3828,9 @@ "link": true }, "node_modules/enhanced-resolve": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz", - "integrity": "sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ==", + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -3885,9 +3885,9 @@ } }, "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -3897,32 +3897,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escape-string-regexp": { @@ -4117,12 +4117,11 @@ } }, "node_modules/fumadocs-core": { - "version": "16.10.0", - "resolved": "https://registry.npmjs.org/fumadocs-core/-/fumadocs-core-16.10.0.tgz", - "integrity": "sha512-DYAYVh83RCglrJ9eBjXJ0xCMv7yhiUfj3RVHlj2QRv4UuUPhtKkA4K1Tu49qvG1MjZQdTuP8B2A0WLiFijXDgg==", + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/fumadocs-core/-/fumadocs-core-16.10.3.tgz", + "integrity": "sha512-xXhqz/fqbN7pLlshJb/B5L+vzMJOmWxoPj7+KMRTa/4A669hKeeCBPpRAiooMqjblWqIRSxLiO02/ds8ltvUPQ==", "license": "MIT", "dependencies": { - "@fuma-translate/react": "^0.0.3", "@orama/orama": "^3.1.18", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", @@ -4283,23 +4282,23 @@ } }, "node_modules/fumadocs-ui": { - "version": "16.10.0", - "resolved": "https://registry.npmjs.org/fumadocs-ui/-/fumadocs-ui-16.10.0.tgz", - "integrity": "sha512-pSqtHX4rxYoALY7j6k32oK3rWmDESkaeUqUJxFiIkl7tCh4NXkkFAPURQSSzPYgy6NWC5qu6ellrbw9LnjWIQg==", + "version": "16.10.3", + "resolved": "https://registry.npmjs.org/fumadocs-ui/-/fumadocs-ui-16.10.3.tgz", + "integrity": "sha512-0aSLdQ73EWoCmYcQYr2uNHlSB/s2fD+NMugtdZF3vC4lqs0MfyOtwnZPyYAskUnXNs6HECly/Hu6oY5JqmlkHg==", "license": "MIT", "dependencies": { - "@fuma-translate/react": "^0.0.3", + "@fuma-translate/react": "^1.0.2", "@fumadocs/tailwind": "0.0.5", - "@radix-ui/react-accordion": "^1.2.12", - "@radix-ui/react-collapsible": "^1.1.12", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-direction": "^1.1.1", - "@radix-ui/react-navigation-menu": "^1.2.14", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-presence": "^1.1.5", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-accordion": "^1.2.13", + "@radix-ui/react-collapsible": "^1.1.13", + "@radix-ui/react-dialog": "^1.1.16", + "@radix-ui/react-direction": "^1.1.2", + "@radix-ui/react-navigation-menu": "^1.2.15", + "@radix-ui/react-popover": "^1.1.16", + "@radix-ui/react-presence": "^1.1.6", + "@radix-ui/react-scroll-area": "^1.2.11", + "@radix-ui/react-slot": "^1.2.5", + "@radix-ui/react-tabs": "^1.1.14", "class-variance-authority": "^0.7.1", "lucide-react": "^1.17.0", "motion": "^12.40.0", @@ -4315,7 +4314,7 @@ "@takumi-rs/image-response": "*", "@types/mdx": "*", "@types/react": "*", - "fumadocs-core": "16.10.0", + "fumadocs-core": "16.10.3", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0" @@ -5131,9 +5130,9 @@ } }, "node_modules/lucide-react": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.17.0.tgz", - "integrity": "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.18.0.tgz", + "integrity": "sha512-LZDb7H/0YfM+RJncD0hDQRCAu+vSGODqpe35TuVI8EuXaRjkczbsx7p8dY4J87F/MUSj6bpYqeI8nw8qXaAdmA==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -7023,9 +7022,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz", - "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", "license": "MIT" }, "node_modules/tapable": { diff --git a/sockguard-logo.png b/sockguard-logo.png index 4809ae6d..bcb49169 100644 Binary files a/sockguard-logo.png and b/sockguard-logo.png differ diff --git a/website/public/apple-touch-icon.png b/website/public/apple-touch-icon.png index 70176f2f..4bc0228c 100644 Binary files a/website/public/apple-touch-icon.png and b/website/public/apple-touch-icon.png differ diff --git a/website/public/favicon-96x96.png b/website/public/favicon-96x96.png index e2f054d3..a7f3f4f0 100644 Binary files a/website/public/favicon-96x96.png and b/website/public/favicon-96x96.png differ diff --git a/website/public/favicon.ico b/website/public/favicon.ico index b918bbe1..d271da58 100644 Binary files a/website/public/favicon.ico and b/website/public/favicon.ico differ diff --git a/website/public/favicon.svg b/website/public/favicon.svg index 35359153..df9d5898 100644 --- a/website/public/favicon.svg +++ b/website/public/favicon.svg @@ -1,3 +1 @@ -RealFaviconGeneratorhttps://realfavicongenerator.net \ No newline at end of file + \ No newline at end of file diff --git a/website/public/sockguard-logo.png b/website/public/sockguard-logo.png index 4809ae6d..bcb49169 100644 Binary files a/website/public/sockguard-logo.png and b/website/public/sockguard-logo.png differ diff --git a/website/public/web-app-manifest-192x192.png b/website/public/web-app-manifest-192x192.png index d7be5756..ac23265f 100644 Binary files a/website/public/web-app-manifest-192x192.png and b/website/public/web-app-manifest-192x192.png differ diff --git a/website/public/web-app-manifest-512x512.png b/website/public/web-app-manifest-512x512.png index ccdb5db9..25efee65 100644 Binary files a/website/public/web-app-manifest-512x512.png and b/website/public/web-app-manifest-512x512.png differ diff --git a/website/src/app/layout.tsx b/website/src/app/layout.tsx index 14b71304..0ddce406 100644 --- a/website/src/app/layout.tsx +++ b/website/src/app/layout.tsx @@ -42,12 +42,12 @@ export default function RootLayout({ children }: { children: React.ReactNode }) return ( - - - - + + + + - + {children}