diff --git a/README.md b/README.md index a44dff6..2cedd2e 100644 --- a/README.md +++ b/README.md @@ -2,64 +2,110 @@ Internal deployment platform for Backend/QA. Lets a developer deploy a feature branch into an isolated sandbox, with the API Gateway routing selected -services to the sandbox and the rest to OCP. See [REQUIREMENTS.md](REQUIREMENTS.md) -for the full spec. +services to the sandbox and the rest to OCP. See +[REQUIREMENTS.md](REQUIREMENTS.md) for the full spec. ## Layout ``` . -├── protocol/ # shared wire types (Event, DeployRequest) -├── control-plane/ # Go. HTTP API + WS hub + SQLite/.log persistence -├── agent-micro/ # Go. Runs on 172.18.136.92, deploys Go microservices -├── agent-gateway/ # Go. Runs on 172.18.139.186, deploys the API Gateway -├── dashboard/ # NextJS static export, served by nginx -└── nginx/ # reverse proxy + try_files for the dashboard +├── protocol/ # shared wire types (Event, DeployRequest) +├── control-plane/ # Go. HTTP API + WS hub + SQLite/.log persistence +├── agent-micro/ # Go. Runs on 172.18.136.92, deploys Go microservices +├── agent-gateway/ # Go. Runs on 172.18.139.186, deploys the API Gateway +├── dashboard/ # NextJS static export, served by nginx +├── nginx/ # reverse proxy + try_files for the dashboard +├── scripts/ # build, deploy, ssh wrappers, nginx patch +├── docker-compose.yml # all three services on alpine:latest +├── go.work # Go workspace — one build, four modules +└── bin/ # build output (gitignored) ``` -## End-to-end smoke (manual) +## Prerequisites -Prereqs: Go 1.22+, Node 18+, Docker on each agent VM, alpine:3.20 loaded -locally (`docker load -i alpine.tar`). +- Docker (for the build container) +- Node 18+ (for the dashboard) +- `sshpass` (for the deploy scripts: `brew install sshpass`) -1. Build everything: - ```bash - cd protocol && go build ./... - cd ../control-plane && go build -o bin/control-plane ./cmd/control-plane - cd ../agent-micro && go build -o bin/agent-micro ./cmd/agent-micro - cd ../agent-gateway && go build -o bin/agent-gateway ./cmd/agent-gateway - cd ../dashboard && npm install && npm run build - ``` +No Go install needed locally — `scripts/build.sh` cross-compiles inside +`golang:1.23-alpine`. -2. Start the control plane: - ```bash - ./control-plane/bin/control-plane -addr :8080 -data ./data - ``` +## Build -3. Start the micro agent on 172.18.136.92: - ```bash - SDP_CP_URL=ws://172.18.139.186:8080/ws/agent SDP_NODE_ID=micro \ - ./agent-micro/bin/agent-micro - ``` +```bash +./scripts/build.sh +``` -4. Start the gateway agent on 172.18.139.186: - ```bash - SDP_CP_URL=ws://172.18.139.186:8080/ws/agent SDP_NODE_ID=gateway \ - ./agent-gateway/bin/agent-gateway - ``` +Outputs: +- `bin/control-plane`, `bin/agent-micro`, `bin/agent-gateway` (Linux/amd64 ELF) +- `dashboard/out/` (NextJS static export) -5. Point nginx at the dashboard build (`dashboard/out/`) and the control - plane (`:8080`). See `nginx/nginx.conf`. +The script verifies each binary with `file` to catch a missing +`GOOS`/`GOARCH`. -6. Open `http:///`, sign in with any Bitbucket creds, pick - `account` → `feature/login-error`, click Deploy. Watch the stage - checkmarks and the log stream. +## Deploy -## Notes +```bash +./scripts/deploy.sh +``` -- Credentials are passed per-operation to the agent and never persisted - on the agent longer than the operation. -- The runtime model is `alpine:3.20` + bind-mounted repo + exec'd binary. - No Dockerfile build step on the agent. -- Logs persist to `/logs/.log`. SQLite holds progress - snapshots and final state. +This script: +1. SSHs to **172.18.136.92** (`administrator`) and pushes `bin/agent-micro` + to `~/SDP/bin/` +2. SSHs to **172.18.139.186** (`administrator`) and pushes + `bin/control-plane`, `bin/agent-gateway`, and `dashboard/out/` to + `~/SDP/` +3. Idempotently splices the SDP location block into + `/etc/nginx/sites-available/default` on 186 and reloads nginx + +Override the creds via `SDP_92_PASS` / `SDP_186_PASS` env vars. + +## Local dev (docker compose) + +For dev on a single host (e.g. a laptop with Docker): + +```bash +./scripts/build.sh +docker compose up -d +``` + +Three services come up on `alpine:latest`: +- `control-plane` → `:8080` +- `agent-micro` (connects to control plane, has docker socket + repos mounted) +- `agent-gateway` (same shape) + +## Architecture notes + +- **Pass-through creds.** Bitbucket credentials travel with each deploy + request from control plane to agent, are used once for `git fetch`/`checkout`/ + `pull`, and are never logged or persisted on the agent. +- **No Dockerfile build on the agent.** Each agent does `go build` on the + host, then `docker run alpine:3.20` with the host repo bind-mounted at + `/src` and the binary exec'd as the container command. +- **No internet on the VMs.** `alpine:3.20` is pre-loaded via + `docker load`. The dashboard is a static export, no runtime fetches. +- **Persistence.** Deployment progress goes to SQLite (`/sdp.db`). + Log lines go to append-only `/logs/.log`. SQLite + uses `modernc.org/sqlite` (pure Go, no cgo) so the control plane binary + stays statically linkable. +- **Realtime transport.** WebSocket end-to-end. Agents connect to + `/ws/agent` on the control plane; the dashboard subscribes to + `/ws/deployments/{id}`. + +## MVP stubs (intentional) + +These are marked with `ponytail:` comments in the code and will be +replaced before production: + +- `validateViaAgent` (login) — accepts any creds if an agent is + connected. Real impl does a `git ls-remote` probe frame. +- `handleListRepos` / `handleListBranches` — hardcoded fixtures. + Real impl forwards to the connected agent. +- `handleListDeployments` (GET) — returns `[]`. Real impl reads SQLite. +- WS auth on `/ws/deployments/*` — open. Real impl checks session token. + +## See also + +- [REQUIREMENTS.md](REQUIREMENTS.md) — full spec, infra, MVP success criteria +- [nginx/nginx.conf](nginx/nginx.conf) — reference nginx config +- [docker-compose.yml](docker-compose.yml) — three-service dev stack