1
0
Fork
You've already forked fogss
0
No description
  • Rust 70.1%
  • JavaScript 13%
  • Shell 9.2%
  • CSS 6.1%
  • Kotlin 1%
  • Other 0.5%
yann degat 1848be0f40
All checks were successful
Release / linux-bin (push) Successful in 22m59s
Release / oci (push) Successful in 2m15s
Release / apk (push) Successful in 45m17s
Release / publish (push) Successful in 31s
feat(android): bridge tracing→logcat + in-app log viewer on ERROR screen
Two fixes exposing daemon state to the user:
1. `src/jni_bridge.rs` — bridge `tracing` events to logcat.
 Default `tracing_subscriber::fmt()` writes to stdout, which is
 captured to /dev/null for non-system Android processes. That's
 why the daemon appeared silent after start (logcat showed only
 the JNI-side `log::info!` calls). New inline `AndroidLogWriter`
 routes each tracing event through `log::info!` → android_logger
 → logcat. Losing per-event level is acceptable for debugging;
 everything lands on the `fogss-trace` tag.
2. `MainActivity` — new "VIEW AGENT LOGS" button on the ERROR
 screen. Execs `logcat -d -v time -t 400 fogss:V fogss-tlspin:V
 fogss-trace:V AndroidRuntime:E *:S` and displays the result in a
 scrollable selectable TextView. COPY button for clipboard.
 Works on debug-signed APKs; release-signed APKs restrict
 own-log reads (will need an in-memory ring buffer).
Unblocks debugging the current "daemon didn't answer within 15 s"
failure — previously the daemon's tracing output was invisible.
2026年04月21日 11:24:57 +00:00
.forgejo/workflows fix(android-ci): use nix-patched aapt2 instead of AGP's Maven-downloaded one 2026年04月20日 18:45:44 +00:00
android feat(android): bridge tracing→logcat + in-app log viewer on ERROR screen 2026年04月21日 11:24:57 +00:00
docs feat(ci): publish linux binary + OCI image + APK on every main push 2026年04月19日 12:04:09 +00:00
scripts Initial public release 2026年04月19日 11:54:42 +00:00
src feat(android): bridge tracing→logcat + in-app log viewer on ERROR screen 2026年04月21日 11:24:57 +00:00
tests Initial public release 2026年04月19日 11:54:42 +00:00
web Initial public release 2026年04月19日 11:54:42 +00:00
.gitignore Initial public release 2026年04月19日 11:54:42 +00:00
AGENTS.md Initial public release 2026年04月19日 11:54:42 +00:00
build.rs Initial public release 2026年04月19日 11:54:42 +00:00
Cargo.lock Initial public release 2026年04月19日 11:54:42 +00:00
Cargo.toml Initial public release 2026年04月19日 11:54:42 +00:00
CLAUDE.md Initial public release 2026年04月19日 11:54:42 +00:00
devshell.nix fix(devshell): pin perl for openssl-src build.rs in hermetic CI containers 2026年04月20日 06:25:49 +00:00
down.sh Initial public release 2026年04月19日 11:54:42 +00:00
flake.lock Initial public release 2026年04月19日 11:54:42 +00:00
flake.nix Initial public release 2026年04月19日 11:54:42 +00:00
LICENSE Initial public release 2026年04月19日 11:54:42 +00:00
Makefile fix(android-ci): use nix-patched aapt2 instead of AGP's Maven-downloaded one 2026年04月20日 18:45:44 +00:00
README.md Initial public release 2026年04月19日 11:54:42 +00:00
up.sh Initial public release 2026年04月19日 11:54:42 +00:00

FOGSS — Friend-Only Git Synchronized Storage

Distributed, git-backed object store with an S3-compatible API and libp2p P2P replication between mutually-trusted peers. One Rust binary. Friend-only trust. Works offline.

  • S3 plane — stock aws s3 cp works. SigV4, per-store credentials.
  • Git plane — stock git clone/push/pull works over SSH. gitoxide, LFS for large blobs.
  • Replication — libp2p gossipsub + request-response, AEAD-encrypted per tribe. Only peers with mutual tribe peer add sync.
  • UI — web UI embedded in the binary on port 2204 (HTTPS).
  • App frontends on top of the store — each store has a kind; today a store can be a plain S3/Git bucket (generic) or a Vaultwarden-compatible password vault (bitwarden), served at https://<host>:2204/bw/<tribe>/<store> for stock Bitwarden clients (bw CLI, desktop, mobile). The pattern — pick a store kind, mount a protocol adapter over the same git-backed bytes — is how future frontends (contacts, notes, calendar, ...) will plug in.
  • Encrypted at rest — every bare git repo and every LFS blob is encrypted on disk with tribe-key-derived keys (Content-Preserving Encryption, CPE). Git OIDs stay SHA-1 of the plaintext; on-disk bytes are ciphertext. SQLCipher also protects agent.db and runtime.db. Nothing sensitive sits in plaintext on the filesystem.

Build

make release # native release build
make release-musl # static musl build (portable single binary)

The build runs npm install + npm run build in web/ and embeds web/dist/ into the binary. Set SKIP_WEB_BUILD=1 to skip.

Nix dev shell: nix develop (see devshell.nix).

First run

# Create identity + first tribe. Prompts for passphrase; prints 24-word
# recovery phrase — save it.
fogss agent init
# Start daemon. Prompts for passphrase.
fogss agent start

Default data directory:

OS Path
Linux ~/.local/share/fogss
macOS ~/Library/Application Support/fogss
Windows %APPDATA%\fogss

Override with fogss -d <path> ....

Default bind addresses (override with fogss agent start --<surface>-bind ...):

Surface Default address
Web UI (HTTPS) 127.0.0.1:2204
S3 (HTTPS+SigV4) 127.0.0.1:8080
Git SSH 127.0.0.1:2222
libp2p P2P :4001
Prometheus 0.0.0.0:9090

Install the TLS cert (browser / CLI / Node)

The HTTPS surfaces use a self-signed CA generated at agent init. Trust it in user-scope stores without sudo:

# Downloads the CA+leaf bundle from a running daemon and installs it
# into ~/.pki/nssdb (Chromium), ~/.mozilla/firefox/*, and writes
# ~/.config/fogss/{server.crt,ca.crt} for env-var use.
scripts/fogss-trust-cert.sh https://localhost:2204

After install:

  • Browsershttps://localhost:2204 works without warnings.
  • curl / gitexport CURL_CA_BUNDLE=~/.config/fogss/server.crt.
  • Nodeexport NODE_EXTRA_CA_CERTS=~/.config/fogss/ca.crt.
  • aws CLIexport AWS_CA_BUNDLE=~/.config/fogss/server.crt.

Tribes and stores

  • Tribe — trust group with a shared 32-byte symmetric key. All tribe data is encrypted with keys derived from it. Tribe ID = <slug>-<hash4>.
  • Store — named bucket inside a tribe, backed by a bare git repo. Each store has its own S3 credentials (derived from tribe_key + store_name) and a policy (expose_s3, expose_ssh, auto_replicate, kind).
  • Store kindgeneric (default, plain S3 bucket) or bitwarden (Vaultwarden-compatible vault; see Frontends below).

All tribe/store commands below talk to the daemon over IPC — run them in a second terminal while fogss agent start keeps running. The <hash4> part of a tribe ID is derived from (name, tribe_key) so copy the actual value from tribe list, don't hand-write it.

fogss tribe create family # derives tribe_id = family-<hash4>
fogss tribe list # prints e.g. "family-ab12 (key: ...)"
# Copy the tribe_id from the line above:
TRIBE=family-ab12
fogss tribe info "$TRIBE"
fogss store create photos --tribe "$TRIBE"
fogss store create vault --tribe "$TRIBE" --kind bitwarden
fogss store list
fogss store s3-credentials photos

S3 API

Endpoint shape is https://<host>:8080/<store>. The path segment is the store name (not a key prefix).

# Credentials are per store. `s3-credentials` prints both env-var
# exports and an ~/.aws/config/credentials snippet — the grep/sed
# below just lifts the env-var block for `eval`.
eval "$(fogss store s3-credentials photos | grep -E '^\s*export ' | sed 's/^[[:space:]]*//')"
export AWS_CA_BUNDLE=~/.config/fogss/server.crt
aws s3 cp hi.jpg s3://photos/hi.jpg --endpoint-url https://127.0.0.1:8080/photos
aws s3 ls s3://photos/ --endpoint-url https://127.0.0.1:8080/photos
aws s3 cp s3://photos/hi.jpg back.jpg --endpoint-url https://127.0.0.1:8080/photos

Per-store credentials are enforced: keys for store X cannot read store Y. Presigned URLs (query-string SigV4) and multipart upload work with stock aws s3 and the official SDKs.

Git / SSH

fogss agent ssh add-key "$(cat ~/.ssh/id_ed25519.pub)"
git clone ssh://git@localhost:2222/photos
cd photos
echo hi > note.txt && git add . && git commit -m 'note' && git push

LFS handles blobs ≥ 1 MiB. Install git-lfs on the client (apt install git-lfs && git lfs install). git lfs pull fetches content; pointers clone by default.

Two-device sync (P2P)

Trust is bidirectional — both devices must tribe peer add the other or nothing syncs.

agent init auto-creates a Default tribe on each device with a fresh random key — devices need to share a key to sync, so one device creates, the other joins.

# ── Device A — creates the tribe ────────────────────────────────
fogss agent init # creates identity + local Default tribe
fogss agent start # prompts passphrase (keep running)
# In another terminal:
fogss agent status # note peer_id_A
fogss tribe list # note the derived tribe_id, e.g. default-ab12
fogss tribe info default-ab12 # shows tribe_key (hex)
# ── Device B — joins A's tribe ──────────────────────────────────
fogss agent init
fogss agent start
# In another terminal:
fogss tribe join Default --tribe-key <tribe_key_from_A>
fogss tribe list # now shows A's tribe (default-ab12)
fogss agent status # note peer_id_B
fogss tribe add-peer default-ab12 <peer_id_A>
# ── Device A — closes the loop ──────────────────────────────────
fogss tribe add-peer default-ab12 <peer_id_B>

S3 PUT on A → S3 GET on B within seconds. Same for git push on A → git clone on B.

CLI surface

Top-level subcommands (see fogss --help for the full list):

  • fogss agent {init|start|stop|status|lock|unlock|recover|ssh add-key ...}
  • fogss tribe {create|join|list|info|status|add-peer|remove-peer|invite|accept|leave|...}
  • fogss store {create|list|info|delete|s3-credentials|policy|replicate|verify|events|branch ...}
  • fogss tls {init|status|client|list|revoke|export}
  • fogss peer {...} fogss conflict {...}
  • Data: fogss put <id> <file> -s <store>, fogss get, fogss list, fogss delete

Frontends

FOGSS stores bytes; frontends give those bytes a purpose. Pick a kind when you create a store; the matching HTTP surface turns on automatically.

Kind What it exposes Clients
generic S3 API (:8080/<store>) and Git SSH (:2222/<store>) aws CLI / SDKs, git
bitwarden Vaultwarden-compatible REST at :2204/bw/<tribe>/<store>/ bw CLI ≥ 202630, Bitwarden desktop/mobile

Create a vault-kind store and point a Bitwarden client at it:

fogss store create vault --tribe family-ab12 --kind bitwarden
bw config server https://localhost:2204/bw/family-ab12/vault
bw login --apikey # or full login flow once registration is done in-app
bw list items

The Bitwarden surface is behind the bitwarden Cargo feature (cargo build --features bitwarden / make release-musl-bitwarden). Default builds exclude it so the attack surface stays minimal.

More frontend kinds (CardDAV / CalDAV / notes / ...) use the same pattern: a store of that kind + a protocol adapter module under src/api/<kind>/.

Security model

  • Encryption at rest. Every bare git repo under <data_dir>/git-stores/ is wrapped by CPE — blobs, trees and commits are encrypted on disk with keys derived from the tribe key (see src/storage/git/encryption.rs and src/crypto/). LFS objects get the same treatment. A file-system-level leak (stolen disk, misconfigured backup) reveals ciphertext only. agent.db / runtime.db are SQLCipher.
  • Passphrase — Argon2id-derived key unlocks agent.db (SQLCipher). agent.db holds identity, BIP39 seed, trusted peers, SSH keys, and the runtime DB key. runtime.db (for audit/events/presence) is unlocked from there and stays open while agent.db is locked.
  • Auto-lock — session locks after 30 min idle. API calls then 401 until fogss agent unlock.
  • Recovery — 24-word BIP39 seed → device keypair via BIP32 (--device-index). Same seed on multiple devices; each gets a unique index.
  • Per-store credentials — derived deterministically from tribe_key + store_name. Compromising one store's creds does not leak another store's data.
  • Tribe crypto boundary — peers outside the tribe, or holding the wrong tribe_key, cannot decrypt replicated packs.

Running as a service / on a phone

See docs/DISTRIBUTION.md for the full plan (Linux systemd, .deb/.rpm, Android APK).

Android: the APK build pipeline is already wired — nix develop pulls cargo-ndk + NDK 27 + JDK 17 + gradle, and:

make android-debug # arm64 debug APK → android/app/build/outputs/apk/debug/
make android # all-ABI release APK (unsigned)

The Rust daemon is compiled as libfogss.so (see the android feature in Cargo.toml) and loaded by a minimal Kotlin shell in android/ that hosts the embedded web UI in a WebView pointed at https://127.0.0.1:2204. JNI start(passphrase) calls the same commands::start::run entry the Linux fogss agent start CLI uses, on a dedicated thread with a current-thread tokio runtime (see android/SKILL.md). Still pending: BiometricPrompt + Keystore passphrase unlock, cert pinning against filesDir/fogss/tls/ca.crt, release-signing config — tracked in docs/DISTRIBUTION.md.

Tests

make test # rust-test + shell-test
make rust-test # curated integration binaries
make shell-test TEST=single-node
cd web && npm test # Playwright (uses system chromium via FOGSS_CHROME)

See tests/TEST_SUITE_USAGE.md and tests/WRITING_TESTS.md before adding tests — many Rust integration binaries are curated in the Makefile and some require the QEMU VM bed in vm-work/.

Architecture

See docs/ARCHITECTURE.md for the current layering (five concurrent surfaces, the Node coordinator, two-DB SQLCipher split, libp2p transport, etc.).

License

GPLv3.