mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-02 07:12:41 +00:00
* feat(render): private-service topology, docs, and a CI check on render.yaml Rewrites the Blueprint around the topology Abhigyan called for: `serve` on a private service, the public web service reverse-proxying /api/* to it, and the generated token gating that edge. `gitnexus-server` becomes a `pserv`, so it has no public URL. `gitnexus-web` gets `GITNEXUS_UPSTREAM_URL` from `fromService … property: hostport`, `GITNEXUS_SERVE_AUTH_TOKEN` with `generateValue: true`, and `GITNEXUS_PROXY_TRUST_XFF: 1` for Render's load balancer. `autoDeploy: true` becomes `autoDeployTrigger: off` so a push cannot restart an indexing server mid-analyze. Four variables come out: - `GITNEXUS_PUBLIC_ORIGIN`: under the proxy the browser is same-origin with the web service and Origin is stripped, so it has no job — and since #2820 `assertServeAuthForPublicOrigin` refuses to start when it is set without serve-native auth. The old topology no longer boots. - `GITNEXUS_BACKEND_URL`: docker-server.mjs falls back to RENDER_EXTERNAL_URL, which is this service's own origin. - `AZURE_DEVOPS_URL` / `AZURE_DEVOPS_PAT`: per Abhigyan, "a stranger can POST /api/analyze an Azure URL, have the server spend the operator's credential, then read the private repo back through the ungated /api/file and /api/grep." The edge token closes the stranger path, but the knob still should not ship in a one-click prompt. Operators who want Azure DevOps set both in the dashboard, on a deploy they have already secured. README drops "with no API keys required" — it described missing authentication as a convenience, and the deploy now generates a token — and replaces it with the token-retrieval flow. It also corrects `plan` versus `sizeGB`: `plan` sets RAM, `sizeGB` only matters when the disk fills. Both the README and a new SECURITY.md section state plainly that the proxy strips Origin, so the CSRF guard does nothing for proxied traffic and the token is the only control — not a second layer behind the guard. SECURITY.md enumerates the routes a token holder reaches with no origin guard, and notes that `POST /api/mcp` has no `authToken` of its own as a pre-existing gap in `serve`. Nothing in CI parsed render.yaml, so the couplings the file documents were unenforced. `gitnexus/test/unit/render-blueprint.test.ts` asserts them: mountPath equals GITNEXUS_HOME, PORT matches Dockerfile.cli's CMD, the server stays a `pserv`, GITNEXUS_PUBLIC_ORIGIN appears in no YAML, the token is generated, no AZURE_DEVOPS_* key, and the schema pragma is intact. Each was confirmed to fail when its invariant is deliberately broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(readme): state what the Render deploy costs The Deploy to Render section described the topology and the token but not the bill. At the Blueprint's defaults it is ~$35/month: $25 for the server's `standard` instance, $7 for the web service's `starter`, $2.50 for the 10 GB disk. Neither service scales to zero, which matters more than the number — an idle deploy costs the same as a busy one. Also trims the section's em dashes and drops "access token" to "token" where the antecedent is one sentence away. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore: update readme --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
87 lines
3.9 KiB
YAML
87 lines
3.9 KiB
YAML
# yaml-language-server: $schema=https://render.com/schema/render.yaml.json
|
|
#
|
|
# One-click GitNexus deploy: a private API server, plus the public web UI that
|
|
# proxies /api/* to it over Render's private network.
|
|
#
|
|
# SECURITY: the web service's URL is discoverable (onrender.com names appear in
|
|
# CT logs). The generated GITNEXUS_SERVE_AUTH_TOKEN is the only access control —
|
|
# the proxy strips Origin, so the server's CSRF guard sees no proxied traffic,
|
|
# and rate limits bound cost, not access. Anyone holding the token can read
|
|
# every indexed repo. See SECURITY.md § Hosted Deploys on Render.
|
|
|
|
previews:
|
|
generation: 'off'
|
|
|
|
projects:
|
|
- name: gitnexus
|
|
environments:
|
|
- name: production
|
|
services:
|
|
# Private: no public URL. `serve` has no authentication of its own.
|
|
- type: pserv
|
|
name: gitnexus-server
|
|
runtime: docker
|
|
# Private networking needs one shared region.
|
|
region: oregon
|
|
# plan sets RAM: standard 2GB, pro 4GB. Indexing is memory-bound.
|
|
plan: standard
|
|
dockerfilePath: ./Dockerfile.cli
|
|
dockerContext: .
|
|
# No dockerCommand — the image's CMD already binds $PORT, and Render
|
|
# re-wraps dockerCommand in a shell, so `sh -c` exits 127.
|
|
# No healthCheckPath either: Render rejects one on a pserv. The
|
|
# proxy's connect-retry covers the restart window instead.
|
|
#
|
|
# Don't restart an indexing server on a push.
|
|
autoDeployTrigger: 'off'
|
|
# mountPath must equal GITNEXUS_HOME in Dockerfile.cli.
|
|
disk:
|
|
name: gitnexus-data
|
|
mountPath: /data/gitnexus
|
|
sizeGB: 10
|
|
envVars:
|
|
# Dockerfile.cli's CMD binds this.
|
|
- key: PORT
|
|
value: 4747
|
|
# One hop: gitnexus-web's proxy, which writes X-Forwarded-For
|
|
# itself. A count rather than the default ranges (loopback,
|
|
# linklocal, uniquelocal), which assume Render's private network
|
|
# is RFC1918. `true` is rejected outright.
|
|
- key: GITNEXUS_TRUST_PROXY
|
|
value: 1
|
|
# Deliberately unset: GITNEXUS_PUBLIC_ORIGIN, which has no job
|
|
# behind the proxy and makes `serve` refuse to start
|
|
# (assertServeAuthForPublicOrigin); AZURE_DEVOPS_URL /
|
|
# AZURE_DEVOPS_PAT, since /api/analyze would spend the PAT and
|
|
# /api/file could read the private repo back. Set the Azure pair
|
|
# in the dashboard if you want it.
|
|
|
|
# Public: the UI, plus a token-gated same-origin proxy to the server.
|
|
- type: web
|
|
name: gitnexus-web
|
|
runtime: docker
|
|
region: oregon
|
|
plan: starter
|
|
dockerfilePath: ./Dockerfile.web
|
|
dockerContext: .
|
|
healthCheckPath: /
|
|
autoDeployTrigger: 'off'
|
|
envVars:
|
|
# host:port, scheme-less; the proxy prefixes http://. Set without
|
|
# the token below, docker-server.mjs refuses to start.
|
|
- key: GITNEXUS_UPSTREAM_URL
|
|
fromService:
|
|
type: pserv
|
|
name: gitnexus-server
|
|
property: hostport
|
|
# Bearer token for every /api/* request. Copy it from this
|
|
# service's Environment tab into the UI's settings panel; rotate by
|
|
# editing it here and redeploying.
|
|
- key: GITNEXUS_SERVE_AUTH_TOKEN
|
|
generateValue: true
|
|
# Render's load balancer is the one hop in front and appends the
|
|
# real peer. The proxy ignores inbound XFF by default.
|
|
- key: GITNEXUS_PROXY_TRUST_XFF
|
|
value: 1
|
|
# Deliberately unset: GITNEXUS_BACKEND_URL. docker-server.mjs falls
|
|
# back to RENDER_EXTERNAL_URL, this service's own origin.
|