From 2f7d62ba92be508cb2648af10c4a4e418bf60293 Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Sun, 14 Jun 2026 09:01:35 +0000 Subject: [PATCH] refactor(ci-setup): extract container-port/image/proxy-port constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The container-internal port (4747 ×5), the image reference (×3), and the Caddy proxy-port arithmetic (opts.port + 1 ×5) were duplicated across the generated artifacts, so the port contract could drift if one site was updated and others missed. Hoist CONTAINER_PORT and GITNEXUS_IMAGE constants and a caddyProxyPort() helper. Generated output is byte-identical (existing template tests pass unchanged). buildMcpSnippet's auth-conditional display port (opts.port+1 for token, opts.port for no-auth) is intentionally left as-is — it is not the Caddy proxy port. Co-Authored-By: Claude Opus 4.8 (1M context) --- gitnexus/src/cli/ci-setup/templates.ts | 35 +++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/gitnexus/src/cli/ci-setup/templates.ts b/gitnexus/src/cli/ci-setup/templates.ts index 24aa3e247..653b9fa6f 100644 --- a/gitnexus/src/cli/ci-setup/templates.ts +++ b/gitnexus/src/cli/ci-setup/templates.ts @@ -5,6 +5,17 @@ const COMMERCIAL_NOTICE = '# ⚠ COMMERCIAL USE: verify PolyForm-Noncommercial-1.0.0 license before deploying to client environments.'; const GENERATED_NOTICE = '# Generated by: gitnexus ci-setup'; +// The port gitnexus serve always binds inside the container/image (the host or +// proxy-facing port is derived from opts.port). Keep these in one place so the +// port contract can't drift across the generated artifacts. +const CONTAINER_PORT = 4747; +const GITNEXUS_IMAGE = 'ghcr.io/abhigyanpatwari/gitnexus:latest'; + +/** The Caddy reverse-proxy port (one above the gitnexus serve port). */ +function caddyProxyPort(opts: CiSetupOptions): number { + return opts.port + 1; +} + function buildGitHubActionsWorkflow(opts: CiSetupOptions): string { const onBlock = opts.branchStrategy === 'pr-scoped' @@ -135,7 +146,7 @@ ${GENERATED_NOTICE} services: gitnexus: - image: ghcr.io/abhigyanpatwari/gitnexus:latest + image: ${GITNEXUS_IMAGE} # No ports: — gitnexus is accessible only to the proxy on the internal network. volumes: - gitnexus-data:/data/gitnexus @@ -144,7 +155,7 @@ services: GITNEXUS_HOME: /data/gitnexus restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:4747/api/health"] + test: ["CMD", "curl", "-f", "http://localhost:${CONTAINER_PORT}/api/health"] interval: 30s timeout: 5s retries: 3 @@ -153,7 +164,7 @@ services: gitnexus-proxy: image: caddy:alpine ports: - - "\${GITNEXUS_PROXY_PORT:-${opts.port + 1}}:${opts.port + 1}" + - "\${GITNEXUS_PROXY_PORT:-${caddyProxyPort(opts)}}:${caddyProxyPort(opts)}" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro environment: @@ -178,9 +189,9 @@ ${GENERATED_NOTICE} services: gitnexus: - image: ghcr.io/abhigyanpatwari/gitnexus:latest + image: ${GITNEXUS_IMAGE} ports: - - "\${GITNEXUS_PORT:-${opts.port}}:4747" + - "\${GITNEXUS_PORT:-${opts.port}}:${CONTAINER_PORT}" volumes: - gitnexus-data:/data/gitnexus - \${WORKSPACE_DIR:-./workspace}:/workspace:ro @@ -188,7 +199,7 @@ services: GITNEXUS_HOME: /data/gitnexus restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:4747/api/health"] + test: ["CMD", "curl", "-f", "http://localhost:${CONTAINER_PORT}/api/health"] interval: 30s timeout: 5s retries: 3 @@ -204,12 +215,12 @@ function buildDockerCompose(opts: CiSetupOptions): string { } function buildCaddyfile(opts: CiSetupOptions): string { - const proxyPort = opts.port + 1; + const proxyPort = caddyProxyPort(opts); return `:${proxyPort} { @authorized header Authorization "Bearer {env.GITNEXUS_TOKEN}" handle @authorized { - reverse_proxy gitnexus:4747 + reverse_proxy gitnexus:${CONTAINER_PORT} } respond "Unauthorized" 401 @@ -284,8 +295,8 @@ az containerapp create \\ --name "\$APP_NAME" \\ --resource-group "\$RESOURCE_GROUP" \\ --environment "\$ENVIRONMENT" \\ - --image ghcr.io/abhigyanpatwari/gitnexus:latest \\ - --target-port 4747 \\ + --image ${GITNEXUS_IMAGE} \\ + --target-port ${CONTAINER_PORT} \\ --ingress internal \\ --env-vars "GITNEXUS_HOME=/data/gitnexus" \\ --volume-name gitnexus-data \\ @@ -361,7 +372,7 @@ Copy the MCP entry from \`.claude/gitnexus-mcp-snippet.json\` into \`~/.claude/s "mcpServers": { "gitnexus": { "type": "http", - "url": "http://:${opts.port + 1}/api/mcp", + "url": "http://:${caddyProxyPort(opts)}/api/mcp", "headers": { "Authorization": "Bearer YOUR_GITNEXUS_TOKEN" } @@ -420,7 +431,7 @@ execution flows, and blast-radius impact — without reading every file on every | Auth model | ${authLabel} | ${opts.auth === 'token' ? 'Prevents unauthorized access to indexed source code' : 'Deployment behind trusted network perimeter'} | | Branch index strategy | ${branchLabel} | ${opts.branchStrategy === 'pr-scoped' ? 'Keeps AI clients aware of in-progress work on open PRs' : 'Simpler; indexes only merged code'} | | Server port | ${opts.port} | Default \`gitnexus serve\` port | -${opts.auth === 'token' ? `| Proxy port | ${opts.port + 1} | Caddy listens here; gitnexus is internal-only |\n` : ''} +${opts.auth === 'token' ? `| Proxy port | ${caddyProxyPort(opts)} | Caddy listens here; gitnexus is internal-only |\n` : ''} --- ## Connecting your AI client