# Gitea backup and remote attach (Alpine BE)

Scripts for the BE Gitea instance at `https://apps.f0xx.org/app/androidcast_project/git/`.

**Safety:** The main working tree under  
`/var/www/localhost/htdocs/apps/app/androidcast_project/android_cast`  
is **never** modified. Only Gitea-owned paths from `/etc/gitea/app.ini` are backed up or reset.

## Prerequisites (Alpine BE)

- Gitea installed (`apk add gitea`), config at `/etc/gitea/app.ini`
- Run backup as **root** (service control + mysqldump)
- For attach: `git`, `curl`; **`GITEA_ADMIN_TOKEN`** (admin PAT from Gitea UI)

## 1. Full backup + optional reset

```bash
cd /path/to/android_cast/examples/crash_reporter/backend/scripts/gitea
chmod +x gitea_collect_backup.sh gitea_attach_remote.sh gitea_ini.sh

# default output: /var/backups/gitea/gitea-collect-YYYYMMDD-HHMMSS/
./gitea_collect_backup.sh
```

Collects:

| Item | Source (from `app.ini`) |
|------|-------------------------|
| Config | `/etc/gitea/app.ini` |
| App data | `[server] APP_DATA_PATH` (caches, indexes, attachments) |
| Bare repos | `[repository] ROOT` |
| LFS | `[lfs] PATH` (if set) |
| Logs | `[log] ROOT_PATH` |
| DB | `mysqldump` / `pg_dump` / sqlite file copy |
| Built-in dump | `gitea dump` when available |

At the end:

```text
Would you like to reset Gitea repositories state to the default (empty)? [y/N]
```

- **`N`** (default): backup only
- **`y`**: stops Gitea, `gitea admin repo-delete` per repo, clears **only** `[repository] ROOT` (must be under `/var/lib/gitea/`), restarts Gitea

## 2. Attach canonical remote as pull mirror

After backup (and optional reset), point Gitea at the real remote:

```bash
./gitea_attach_remote.sh git://10.7.0.10/android_cast
# or: GITEA_MIRROR_URL=git://f0xx.org/android_cast ./gitea_attach_remote.sh
```

### Do I need `GITEA_ADMIN_TOKEN`?

**Usually no** when run **as root on the BE**. The script tries `gitea admin user create-repo` and `gitea admin user generate-access-token` before push.

**Optional** if CLI fails — create in Gitea UI: **Avatar → Settings → Applications → Generate New Token** (scopes: All), then:

```bash
export GITEA_ADMIN_TOKEN='gitea_…'
./gitea_attach_remote.sh git://10.7.0.10/android_cast
```

**Why auth?** Gitea rejects anonymous `git push`. The token (or CLI-generated token) proves write access to `foxx/android_cast`.

**Prerequisite:** a **Gitea user** must exist (you have `admin`). Default owner is **`admin`** (override: `GITEA_OWNER=...`).

**Run the script as root** (so it can `su` to `RUN_USER` from `app.ini`, usually `gitea`):

```bash
sudo ./gitea_attach_remote.sh git://10.7.0.10/android_cast
```

Or run directly as the Gitea service user:

```bash
sudo -u gitea ./gitea_attach_remote.sh git://10.7.0.10/android_cast
```

Running `gitea admin ...` as `foxx` fails with `Expect user 'gitea' but current user is: foxx` — that is normal.

List users (on BE):

```bash
sudo -u gitea gitea -c /etc/gitea/app.ini admin user list
```

**`remote: Not found`** = repo did not exist yet and nothing created it. Re-sync the updated script and re-run.

Local push URL is `http://127.0.0.1:3000/foxx/android_cast.git` (no `/app/.../git/` — nginx strips subpath on :3000).

Override:

```bash
GITEA_MIRROR_URL='git://10.7.0.10/android_cast' \
GITEA_OWNER='foxx' GITEA_REPO='android_cast' \
./gitea_attach_remote.sh
```

**Method (no NFS/SSHFS):**

1. **Preferred:** Gitea API `POST /api/v1/repos/migrate` with `"mirror": true` — UI updates on Gitea’s mirror interval (`10m` default).
2. **Fallback:** `git clone --mirror` from remote + `git push --mirror` to local Gitea HTTP.

Ongoing sync: Gitea pull mirror or cron `gitea admin repo-sync-mirrors`.

## Allow local git mirror (`git://10.7.0.10/...`)

Gitea blocks private/local hosts by default (SSRF protection). For a LAN git daemon:

Edit the **live** config (often `/var/lib/gitea/custom/conf/app.ini`, not only `/etc/gitea/app.ini`):

```ini
[migrations]
ALLOW_LOCALNETWORKS = true
ALLOWED_DOMAINS = *,github.com,*.github.com,chromium.googlesource.com,git.zx2c4.com
BLOCKED_DOMAINS =
```

Notes:

- Section name is **`[migrations]`** (plural) — `[migration]` is ignored.
- `10.7.0.10` is a private IP → **`ALLOW_LOCALNETWORKS = true`** is required.
- On some Gitea versions an empty `ALLOWED_DOMAINS` still blocks UI mirrors; use **`*`** if needed.
- Tighter allowlist (optional): `ALLOWED_DOMAINS = 10.7.0.10` plus `ALLOW_LOCALNETWORKS = true`.

Restart Gitea, then re-sync the mirror:

```bash
sudo rc-service gitea restart
```

In UI: repo → **Settings → Mirror settings** → set interval (e.g. `10m`) → **Sync now**.

CLI (as `gitea` user):

```bash
sudo -u gitea gitea -c /var/lib/gitea/custom/conf/app.ini admin repo-sync-mirrors
```

Ensure BE can reach the git daemon:

```bash
git ls-remote git://10.7.0.10/android_cast HEAD
```

Optional faster default interval for all mirrors:

```ini
[repository]
DEFAULT_MIRROR_INTERVAL = 10m
MIRROR_UPDATE_INTERVAL = 10m
```

## Submodule mirrors (libvpx, opus, speex, …)

Gitea does not “nest” submodules inside one repo — each submodule is its **own mirrored repo**, and `.gitmodules` in `android_cast` points at those Gitea URLs.

**1. Allow upstream hosts** in `app.ini` (see `[migrations]` block above — includes GitHub, googlesource, zx2c4).

**2. Run on BE (as root):**

```bash
cd /path/to/android_cast
chmod +x examples/crash_reporter/backend/scripts/gitea/*.sh

# From bundled list (libvpx, opus, speex, wireguard-android):
sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_mirror_submodules.sh

# Or parse live .gitmodules from a checkout:
sudo ./examples/crash_reporter/backend/scripts/gitea/gitea_mirror_submodules.sh \
  /var/www/.../android_cast/.gitmodules
```

Creates pull mirrors under `admin/libvpx`, `admin/opus`, etc., and prints a **`.gitmodules` snippet** with Gitea URLs.

**3. Commit snippet on canonical git** (`git://10.7.0.10/android_cast`), not on Gitea directly if `android_cast` is a read-only pull mirror:

```ini
[submodule "third-party/opus"]
	path = third-party/opus
	url = https://apps.f0xx.org/app/androidcast_project/git/admin/opus.git
```

**4. Add local submodules** — edit `submodules.defaults.conf` or pass a custom list:

```text
# repo|upstream_url|submodule_path
mylib|git://10.7.0.10/mylib|third-party/mylib
```

```bash
GITEA_SUBMODULES_CONF=/root/my-submodules.list sudo ./gitea_mirror_submodules.sh
```

**5. Sync all mirrors periodically:**

```bash
sudo -u gitea gitea -c /var/lib/gitea/custom/conf/app.ini admin repo-sync-mirrors
```

## Verify

```bash
# Remote reachable from BE
git ls-remote git://f0xx.org/android_cast HEAD

# Gitea UI
curl -sS -o /dev/null -w '%{http_code}\n' \
  'https://apps.f0xx.org/app/androidcast_project/git/'

# After attach
git ls-remote "https://apps.f0xx.org/app/androidcast_project/git/foxx/android_cast.git" HEAD
```

## Related docs

- [docs/INFRA.md](../../../../docs/INFRA.md) — `git://f0xx.org/android_cast`, disk layout
- [docs/TICKETS_ROADMAP.md](../../../../docs/TICKETS_ROADMAP.md) — Gitea URL / `ROOT_URL`
- [docs/GIT_FLOW.md](../../../../docs/GIT_FLOW.md) — branch flow after remote is wired
