23 apps (MetaCore, the library/network/client tiers and 13 MetaFeeder*) move out of the general-purpose Worph/AppStore into their own store so the MetaMesh family releases on its own cadence. - asset URLs repointed to cdn.jsdelivr.net/gh/Worph/MetaAppStore@main - store scaffolding added (category/recommend/featured lists, licence, contributing, gitattributes) - psd-source/meta-icons-v2 icon generator follows the apps MetaMCP stays in Worph/AppStore: it is third-party metatool-ai software, not part of MetaMesh.
65 lines
3.5 KiB
Markdown
65 lines
3.5 KiB
Markdown
# MetaShare — Rationale
|
|
|
|
## What deviation / exception is being requested
|
|
|
|
1. `metashare-app` runs `user: 0:0`.
|
|
2. It publishes host port `4001/tcp` (libp2p).
|
|
3. It mounts `/DATA/AppData/metacore/meta-core` — another app's AppData directory.
|
|
4. Six HTTP paths bypass the SSO gate and are proxied straight to the backend:
|
|
`/health`, `/api/peers*`, `/api/peer/*`, `/api/file/*`, `/api/search*` and
|
|
`/api/services`.
|
|
|
|
## Why it is necessary
|
|
|
|
1. MetaShare writes its service registration into `/meta-core/services/`, a directory
|
|
created and owned by MetaCore's root-running container.
|
|
2. libp2p is **not HTTP**. Caddy is an HTTP reverse proxy and cannot carry it, and remote
|
|
peers resolve this node's public multiaddr from the kad-DHT and dial it directly. Without
|
|
a published, inbound-reachable TCP port the node can only make outbound connections and
|
|
never serves bytes to the swarm. The app therefore carries the reserved
|
|
`needs-public-ip` tag so a user behind CGNAT or the mesh-router tunnel can see the
|
|
limitation before installing.
|
|
3. `/meta-core` is the shared leader-election and service-discovery directory. MetaCore is
|
|
a hard prerequisite of this app.
|
|
4. Those are the **federation surface**: remote MetaShare peers call them to enumerate
|
|
peers, resolve records, search, and fetch blocks. A remote peer is a machine client with
|
|
no cookie jar and no way to complete an interactive OIDC redirect, so gating them makes
|
|
the app unable to federate at all — which is its only function. Every other path,
|
|
including the whole dashboard, stays behind the gate.
|
|
|
|
## Security mitigations in place
|
|
|
|
- Public ingress terminates at the AppShield sidecar (`ghcr.io/yundera/appshield:2.0.9`),
|
|
which gates every path behind the PCS's Authelia SSO over OIDC. The backend carries no
|
|
Caddy labels and publishes no HTTP port to the host, so it is reachable only from the
|
|
`pcs` Docker network.
|
|
- Every service declares `cpu_shares`, and the memory-heavy ones a hard `mem_limit` with
|
|
`memswap_limit` equal to it (swap disabled, so the container is OOM-killed rather than
|
|
pushing the host into swap).
|
|
- Image tags are pinned; no `:latest` anywhere in the stack.
|
|
|
|
- The bypassed paths are read-only federation endpoints scoped to content the user has
|
|
explicitly shared. They expose no configuration, no dashboard and no write operation, and
|
|
they serve exactly what this node already publishes to the public swarm over libp2p — so
|
|
gating them would protect nothing that the DHT does not already carry.
|
|
- The published port speaks libp2p only. libp2p transport is authenticated and encrypted
|
|
(Noise) and peer identity is a public key, so an unauthenticated dial cannot read
|
|
anything the node has not chosen to publish to the swarm. The HTTP API stays on
|
|
`expose:` behind AppShield.
|
|
|
|
## Alternatives considered and rejected
|
|
|
|
- **Proxy libp2p through Caddy.** Not possible: Caddy fronts HTTP, and the DHT advertises a
|
|
raw TCP multiaddr.
|
|
- **Outbound-only / relayed transport.** Works for reachability but not for serving: a node
|
|
nobody can dial contributes no bytes, which is the app's entire function.
|
|
- **Run as `$PUID:$PGID`.** Fails writing into MetaCore's root-owned
|
|
`/meta-core/services/`.
|
|
|
|
## Data protection
|
|
|
|
MetaShare's own store lives under `/DATA/AppData/metashare/{config,data}/`, declared in
|
|
`x-compose-app.folders` and archived by Maison on uninstall. Only content the user has
|
|
explicitly shared is published to the swarm; nothing under `/DATA/Documents`,
|
|
`/DATA/Downloads` or `/DATA/Media` is mounted into this container at all.
|