diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 0000000..b3ed5b7 --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,91 @@ +# Self-hosted app-store packaging (Umbrel / CasaOS / TrueNAS) + +Thin, per-store manifests that wrap the repo's existing hub image (built from +the root [`Dockerfile`](../Dockerfile) — distroless, CGO-free) so a BearDrive +**hub** installs as a one-click app in the self-hosted app-store catalogs. +None of these change the core image. + +| Dir | Store | Upstream PR target | Status | +|---|---|---|---| +| [`umbrel/`](umbrel/) | Umbrel App Store | `getumbrel/umbrel-apps` | **DRAFT — blocked** (see below) | +| [`casaos/`](casaos/) | CasaOS App Store | `IceWhaleTech/CasaOS-AppStore` | **DRAFT — blocked** | +| [`truenas/`](truenas/) | TrueNAS community | `truenas/apps` | **DRAFT — blocked** | + +> `packaging/homebrew` is the existing sibling — the CLI distribution manifest. + +## ⚠️ Two blockers before any of these can be PR'd upstream + +These manifests are **NOT yet known-good**. Both stores' contributing guides +require a real-instance install test, and all three reference a published +container image that does not exist yet. + +1. **No published container image.** Every store installs by pulling a public, + versioned, multi-arch image by tag. The repo publishes **none** — CI + (`.github/workflows/{ci,bump-cloud,docs}.yml`) has no image-publish job, and + the only build path is `deploy/gcp-cloudrun.sh` → a **private** GCP Artifact + Registry for Cloud Run. The `image:` fields below point at a **placeholder** + `ghcr.io/runbear-io/beardrive:` that must first be built and pushed + (multi-arch `linux/amd64` + `linux/arm64` — Umbrel runs on Raspberry Pi). + Owner: **CTO/eng** (tracked as the child issue filed off BEA-49). + +2. **No real-instance test environment.** Each store's guide requires the app + be installed + reach its web UI on an actual instance of that platform + (Umbrel OS / CasaOS / TrueNAS SCALE) before the PR is accepted. Eng has + Docker (the underlying image is smoke-tested — see below) but **no + Umbrel/CasaOS/TrueNAS instances and no local VM tooling** + (qemu/vagrant/multipass absent; Docker Desktop on macOS can't practically + nest those OSes). Owner: **CEO** — needs cloud-VM budget/credentials or a + hosted test env. Untested PRs get rejected and burn reviewer goodwill, so + we hold rather than ship blind (per BEA-49's "Known risk" instruction). + +## What IS verified (Docker smoke test, not a store instance) + +The underlying hub image was built from the root `Dockerfile` and run locally +under Docker with the self-host config below; the web UI was confirmed +reachable. This validates the **runtime invocation and defaults** the manifests +encode — it does **not** substitute for the per-store real-instance test. + +## Install defaults chosen (for the listing copy — CMO) + +The hub is configured by flags **plus** a JSON config file. Critically, the +**admin email can only be set via the config file's `auth.admins`** — there is +no `--admins` flag — and the image is **distroless (no shell)**, so each +manifest uses a tiny `busybox` init container to render `/data/config.json` +from the user-supplied admin email into the shared data volume before the hub +starts. The core image is untouched. + +| Setting | Value | Notes | +|---|---|---| +| **Admin email** | user-supplied; placeholder `admin@example.com` | `auth.admins`. On a zero-account hub this email can self-sign-up first (invite-only afterward). | +| **Listen port (container)** | `8080` (`--addr :8080`) | Suggested host/web port `4173` (matches `docs/self-hosting.md`). | +| **Storage backend** | `file:///data/storage` | Local filesystem blob+journal store — the simplest self-host backend (no S3/GCS creds). | +| **Metadata DB** | sqlite at `/data/hub.db` | `database.driver = sqlite`. | +| **Users DB** | `/data/auth.json` | `auth.users_db`. | +| **Uploads** | enabled (`--upload`) | A hub must accept client uploads. | +| **Read analytics** | enabled (`reads.enabled`) | Powers the Insights dashboard. | +| **Device/home state** | `BDRIVE_HOME=/data/home` | Overrides the image default `/tmp/bdrive` (ephemeral) so identity persists. | +| **Persistent volume** | one dir mounted at `/data` | Holds `storage/`, `home/`, `hub.db`, `auth.json`, `config.json`. | + +Rendered config (only the parts flags can't set — flags supply remote/addr/upload): + +```json +{ + "auth": { "admins": ["admin@example.com"], "users_db": "/data/auth.json" }, + "reads": { "enabled": true }, + "database": { "driver": "sqlite", "dsn": "/data/hub.db" } +} +``` + +Launch command: `serve --remote file:///data/storage --addr :8080 --upload -c /data/config.json` + +## Remaining per-store work (needs a real instance) + +- **UID/permissions:** distroless runs as nonroot UID **65532**; the init + container `chown`s `/data` to match. Each platform mounts app-data with its + own owner (Umbrel commonly 1000) — must be verified live. +- **TrueNAS:** `truenas/apps` expects the full `ix-dev` chart scaffold + (`app.yaml` + `questions.yaml` + `templates/`); the draft here is the core, + and the complete scaffold should be generated + validated with their tooling + on a real TrueNAS SCALE box. +- **Health checks, port-conflict defaults, gallery assets** per each store's + lint/CI. diff --git a/packaging/casaos/docker-compose.yml b/packaging/casaos/docker-compose.yml new file mode 100644 index 0000000..7ab5aff --- /dev/null +++ b/packaging/casaos/docker-compose.yml @@ -0,0 +1,91 @@ +# BearDrive hub — CasaOS App Store manifest (DRAFT, see ../README.md). +# PR target: IceWhaleTech/CasaOS-AppStore. Guide requires it be "well tested on +# your own CasaOS first" — BLOCKED on a published image + a real CasaOS test. +name: beardrive +services: + config-init: + # Distroless has no shell; render config + fix ownership, then exit. + image: busybox:1.36 + restart: on-failure + volumes: + - type: bind + source: /DATA/AppData/beardrive + target: /data + command: + - sh + - -c + - | + set -e + mkdir -p /data/storage /data/home + if [ ! -f /data/config.json ]; then + cat > /data/config.json <- + Self-hosted BearDrive hub: sync any folder across your devices, + teammates, and AI agents with per-change provenance and read + analytics. Local filesystem storage + sqlite; clients connect with + `bdrive login`. Open source (AGPL-3.0). + port_map: "4173" + scheme: http + index: / + webui_port: 4173 + envs: + - container: ADMIN_EMAIL + description: + en_us: >- + Email that becomes the hub admin. On a brand-new hub this address + can self-sign-up first; the hub is invite-only afterward. + volumes: + - container: /data + description: + en_us: BearDrive data — file storage, sqlite metadata, and config. diff --git a/packaging/truenas/app.yaml b/packaging/truenas/app.yaml new file mode 100644 index 0000000..1677d80 --- /dev/null +++ b/packaging/truenas/app.yaml @@ -0,0 +1,35 @@ +# BearDrive hub — TrueNAS Apps metadata (DRAFT, see ../README.md). +# PR target: truenas/apps (community train). BLOCKED on a published image and a +# real TrueNAS SCALE install test. The full ix-dev chart scaffold +# (questions.yaml + templates/) must be generated + validated with TrueNAS +# tooling on a real SCALE instance; questions.yaml and templates/ here are the +# core, not the complete lint-passing scaffold. +name: beardrive +title: BearDrive +train: community +categories: + - cloud + - productivity +app_version: "0.1.0" +version: 0.0.1 +home: https://beardrive.ai +sources: + - https://github.com/runbear-io/beardrive + - https://docs.beardrive.ai +description: >- + Self-hosted BearDrive hub — Google Drive for AI agents. Sync any folder + across devices, teammates, and AI agents with per-change provenance and read + analytics. Local filesystem storage + sqlite; clients connect with + `bdrive login`. Open source (AGPL-3.0). +maintainers: + - name: Runbear + url: https://beardrive.ai + email: hello@runbear.io +run_as_context: + - description: BearDrive runs as the distroless nonroot user. + gid: 65532 + group_name: nonroot + uid: 65532 + user_name: nonroot +capabilities: [] +host_mounts: [] diff --git a/packaging/truenas/questions.yaml b/packaging/truenas/questions.yaml new file mode 100644 index 0000000..5c37d98 --- /dev/null +++ b/packaging/truenas/questions.yaml @@ -0,0 +1,58 @@ +# BearDrive hub — TrueNAS config questions (DRAFT core, see ../README.md). +# Minimal set; the full questions.yaml (resources, DNS, etc.) is generated by +# the ix-dev scaffold and must be validated on a real TrueNAS SCALE instance. +groups: + - name: BearDrive Configuration + description: Hub admin and web access. + - name: Storage Configuration + description: Where BearDrive keeps files, metadata, and config. +questions: + - variable: beardrive + label: "" + group: BearDrive Configuration + schema: + type: dict + attrs: + - variable: admin_email + label: Admin Email + description: >- + Email that becomes the hub admin. On a brand-new hub this address + can self-sign-up first; the hub is invite-only afterward. + schema: + type: string + required: true + default: admin@example.com + - variable: network + label: "" + group: BearDrive Configuration + schema: + type: dict + attrs: + - variable: web_port + label: Web Port + schema: + type: int + default: 4173 + required: true + - variable: storage + label: "" + group: Storage Configuration + schema: + type: dict + attrs: + - variable: data + label: BearDrive Data + description: File storage, sqlite metadata, and config (mounted at /data). + schema: + type: dict + attrs: + - variable: type + label: Type + schema: + type: string + default: ix_volume + enum: + - value: ix_volume + description: ixVolume (dataset created by TrueNAS) + - value: host_path + description: Host Path (existing dataset) diff --git a/packaging/truenas/templates/docker-compose.yaml b/packaging/truenas/templates/docker-compose.yaml new file mode 100644 index 0000000..7798d40 --- /dev/null +++ b/packaging/truenas/templates/docker-compose.yaml @@ -0,0 +1,55 @@ +# BearDrive hub — TrueNAS compose template (DRAFT, see ../../README.md). +# Shown resolved (concrete values) for readability; in the real ix-dev chart +# these become {{ .Values... }} template expressions bound to questions.yaml. +# BLOCKED on a published image + a real TrueNAS SCALE test. +services: + config-init: + # Distroless has no shell; render config + fix ownership, then exit. + image: busybox:1.36 + restart: on-failure + volumes: + - type: bind + source: /mnt/.ix-apps/app_mounts/beardrive/data # ix_volume in the real chart + target: /data + command: + - sh + - -c + - | + set -e + mkdir -p /data/storage /data/home + if [ ! -f /data/config.json ]; then + cat > /data/config.json < /data/config.json <- + BearDrive mounts any folder as a synced volume shared across your devices, + teammates, and AI agents. Every change is attributed to the human, agent, and + device that made it; any synced file can become a public page; and the + Dashboard shows what your agents actually read. This app runs your own + self-hosted hub (local filesystem storage + sqlite) — clients connect with + `bdrive login http://:`. Open source (AGPL-3.0). +developer: Runbear +website: https://beardrive.ai +dependencies: [] +repo: https://github.com/runbear-io/beardrive +support: https://github.com/runbear-io/beardrive/issues +port: 4173 +gallery: + - 1.jpg + - 2.jpg + - 3.jpg +path: "" +defaultUsername: "" +defaultPassword: "" +submitter: Runbear +submission: https://github.com/getumbrel/umbrel-apps/pull/REPLACE_AT_PR_TIME