docs: agent handoff for ARM64 build & collab setup
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# Agent Handoff: ARM64 Docker Build & Collaboration Setup
|
||||
|
||||
## Overview
|
||||
|
||||
Gitea server at `gitea.forkless.com` (RPi 5, native ARM64) hosts the repo
|
||||
`forkless/excalidraw-mcp-sentinel`. An ARM64 Gitea Actions runner is registered
|
||||
on the Gitea server itself (labels: `arm64`, `ubuntu-latest`).
|
||||
|
||||
Local workspace: `/home/pe1085/development/excalidraw-mcp-sentinel`
|
||||
Remote: `https://gitea.forkless.com/forkless/excalidraw-mcp-sentinel`
|
||||
|
||||
---
|
||||
|
||||
## What Was Done
|
||||
|
||||
### 1. Gitea Actions Workflow
|
||||
`.gitea/workflows/docker.yml` — builds both Docker images on ARM64 runner:
|
||||
- `gitea.forkless.com/forkless/excalidraw-mcp-sentinel:latest`
|
||||
- `gitea.forkless.com/forkless/excalidraw-mcp-sentinel-canvas:latest`
|
||||
|
||||
Triggers on push to `main` (paths: Dockerfile, src/**, frontend/**, .gitea/**),
|
||||
PRs, and `workflow_dispatch`.
|
||||
|
||||
### 2. Alpine Base Images
|
||||
Both `Dockerfile` and `Dockerfile.canvas` changed from `node:20-slim` to
|
||||
`node:20-alpine`. Build tools via `apk add --no-cache python3 make g++`.
|
||||
|
||||
### 3. AMD64 Runner Removed
|
||||
There was a local x86_64 Gitea Actions runner (`wsl-runner`) on this machine
|
||||
that competed with the ARM64 runner. It was stopped and its `.runner` file
|
||||
deleted from `/home/pe1085/development/gitea-test/`. It had label
|
||||
`ubuntu-latest:docker://catthehacker/ubuntu:full-latest` — would build amd64
|
||||
images that don't run on ARM64.
|
||||
|
||||
### 4. Frontend WebSocket URL
|
||||
`frontend/src/App.tsx` line 438:
|
||||
```ts
|
||||
const wsUrl = 'wss://excalidraw.forkless.com'
|
||||
```
|
||||
Previously used `window.location.host` — hardcoded to the forkless domain now.
|
||||
|
||||
### 5. Reverse Proxy Config (NPM / OpenResty)
|
||||
The server at `excalidraw.forkless.com` runs behind Nginx Proxy Manager v2.15.1.
|
||||
Two settings fixed WebSocket connectivity:
|
||||
- **WebSockets Support** toggle enabled in NPM (or advanced config:
|
||||
`proxy_set_header Upgrade $http_upgrade;`)
|
||||
- **ALLOWED_ORIGINS** env var must include `https://excalidraw.forkless.com`
|
||||
|
||||
### 6. trust proxy
|
||||
`src/server.ts` line 43:
|
||||
```ts
|
||||
app.set('trust proxy', 1);
|
||||
```
|
||||
Required because NPM sets `X-Forwarded-For` headers and express-rate-limit
|
||||
throws an error without it.
|
||||
|
||||
### 7. Gitea Actions Secrets
|
||||
Create these in the Gitea repo settings → Actions → Secrets:
|
||||
- `GITEAUSER` = `forkless`
|
||||
- `GITEATOKEN` = Gitea personal access token (needs `write:repository` scope)
|
||||
|
||||
---
|
||||
|
||||
## What Still Needs Work
|
||||
|
||||
### 1. Collab URL Hardcoded in Excalidraw Bundle
|
||||
The Excalidraw npm library has `wss://oss-collab.excalidraw.com` hardcoded in
|
||||
its built JS. This is NOT configurable via component props — the `collabServerUrl`
|
||||
prop is not a documented/working prop in v0.18.x.
|
||||
|
||||
Two options:
|
||||
|
||||
**A) Build-time patch (currently reverted but script exists):**
|
||||
`scripts/patch-collab-url.mjs` replaces the URL in `dist/frontend/assets/`
|
||||
after Vite builds. Enable it by restoring:
|
||||
```json
|
||||
"build:frontend": "vite build && node scripts/patch-collab-url.mjs"
|
||||
```
|
||||
|
||||
**B) Keep default (current):** Let the Excalidraw library connect to the
|
||||
official collab server. Requires NPM/OpenResty to allow egress to
|
||||
`oss-collab.excalidraw.com`. Currently works after cache flush + trust proxy fix.
|
||||
|
||||
### 2. ALLOWED_ORIGINS Env Var
|
||||
The `verifyWsClient` in `src/security.ts` checks `Origin` header against
|
||||
`ALLOWED_ORIGINS`. Defaults to `http://localhost:3000` and `http://127.0.0.1:3000`.
|
||||
For production, set:
|
||||
```
|
||||
ALLOWED_ORIGINS=https://excalidraw.forkless.com
|
||||
```
|
||||
Otherwise WebSocket connections from the real domain are rejected.
|
||||
|
||||
### 3. Unused Props in App.tsx
|
||||
Line 1864-1867 of `frontend/src/App.tsx`:
|
||||
```tsx
|
||||
collabServerUrl="wss://excalidraw.forkless.com/socket.io"
|
||||
onCollabDialogOpen={() => {}}
|
||||
```
|
||||
These are likely ignored by the Excalidraw library (not documented props).
|
||||
Can be removed — the real collab URL is controlled by the build-time patch
|
||||
or the default in the npm bundle.
|
||||
|
||||
### 4. WebSocket Auth
|
||||
When `EXCALIDRAW_API_KEY` is set, the WS server sends `auth_required` on
|
||||
connect, waits for `hello` with the API key, and closes if not received.
|
||||
The frontend handles this in `connectWebSocket()` → `sendHello()`.
|
||||
This works but could be strengthened:
|
||||
- Add IP-based rate limiting for WS connections
|
||||
- Add `verifyWsClient` to reject missing origins (currently allows no-origin)
|
||||
|
||||
### 5. Docker Image Tags
|
||||
Currently only `:latest` and `:$sha` tags are pushed. For versioned releases,
|
||||
trigger on `v*` tags is in the workflow but untested.
|
||||
|
||||
---
|
||||
|
||||
## Credentials & Access
|
||||
|
||||
- **Gitea API token**: stored in `~/.profile` as `GITEA_TOKEN` (not `GITEATOKEN`)
|
||||
- **Git credentials**: stored via `git credential-store` for
|
||||
`gitea.forkless.com` — username `forkless`, password is the token
|
||||
- To use the token: `source ~/.profile` then `$GITEA_TOKEN`
|
||||
- Or via git: `TOKEN=$(git credential fill <<< $'protocol=https\nhost=gitea.forkless.com\npath=/forkless/excalidraw-mcp-sentinel.git\n' 2>/dev/null | grep "^password=" | cut -d= -f2)`
|
||||
|
||||
---
|
||||
|
||||
## Quick Commands
|
||||
|
||||
```bash
|
||||
# Check latest build
|
||||
TOKEN=$(git credential fill <<< $'protocol=https\nhost=gitea.forkless.com\npath=/forkless/excalidraw-mcp-sentinel.git\n' 2>/dev/null | grep "^password=" | cut -d= -f2) && curl -s -H "Authorization: token $TOKEN" "https://gitea.forkless.com/api/v1/repos/forkless/excalidraw-mcp-sentinel/actions/runs?limit=3" | python3 -c "import sys,json;d=json.load(sys.stdin);[print(f'Run {r[\"id\"]}: {r[\"status\"]:>10} {r.get(\"conclusion\",\"-\"):>10} {r[\"head_sha\"][:12]}') for r in d.get('workflow_runs',[])]"
|
||||
|
||||
# Check Docker image manifest
|
||||
docker manifest inspect gitea.forkless.com/forkless/excalidraw-mcp-sentinel:latest
|
||||
|
||||
# Git credential helper (broken 'tea' → fixed 'tea-cli')
|
||||
git config --global credential.https://gitea.forkless.com.helper '!tea-cli login helper'
|
||||
|
||||
# Push without credential helper issues
|
||||
git -c credential.https://gitea.forkless.com.helper='!tea-cli login helper' push origin main
|
||||
```
|
||||
Reference in New Issue
Block a user