Files
Worph 39f82e1f96 Import the MetaMesh app family from Worph/AppStore
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.
2026-09-13 16:18:29 +00:00

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.