Skip to content

fix: log streaming for Capgo Builder (public)#1510

Merged
riderx merged 9 commits intomainfrom
builder-fix-logs
Feb 2, 2026
Merged

fix: log streaming for Capgo Builder (public)#1510
riderx merged 9 commits intomainfrom
builder-fix-logs

Conversation

@WcaleNieWolny
Copy link
Copy Markdown
Contributor

@WcaleNieWolny WcaleNieWolny commented Jan 27, 2026

Summary

This PR introduces a new field called logs_url and logs_token to the /build/start endpoint. This is then used by the CLI to connect to the capgo builder worker directly skipping the proxy

Motivation

Martin asked me to improve and fix the native build, so I am doing just that

Business impact

Low - removing the proxy cuts costs of operating the native build + it makes the log streaming more reliable

Summary by CodeRabbit

  • New Features

    • Build start responses can optionally include a time-limited logs_url and logs_token to enable direct SSE streaming of build logs.
  • Bug Fixes

    • The proxy-based build logs endpoint now shows a deprecation notice directing users to the direct SSE streaming approach.
  • Chores

    • Added backend support for generating signed log-streaming tokens.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 27, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds optional HS256 JWT generation (4h) for direct SSE build log streaming, emits a deprecation notice for the logs proxy stream, updates an encrypted-file mapping, and adds the jose dependency. start build responses may include logs_url and logs_token when configured.

Changes

Cohort / File(s) Summary
Secret mapping update
\.gitsecret/paths/mapping.cfg
Updated hash mapping for encrypted internal/cloudflare/.env.prod.
Log streaming proxy notice
supabase/functions/_backend/public/build/logs.ts
Modified initial cloudlog message to include a deprecation note "(deprecated proxy - use direct SSE)"; added a deprecation comment above the log emission.
Build start: token generation & response
supabase/functions/_backend/public/build/start.ts
Added generateLogStreamToken(jobId, userId, appId, jwtSecret) to emit HS256 JWT (4h expiry); on successful build start, conditionally generates logs_token and logs_url when JWT_SECRET (and PUBLIC_URL) are present; logs generation success/failure without failing the request; BuilderStartResponse augmented to include optional logs_url and logs_token.
Dependency and runtime config
package.json, supabase/functions/deno.json
Added dependency "jose": "^6.1.3" in package.json and npm:jose@^6.1.3 entry in deno.json (plus minor JSON formatting tweak).

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant BuildStart as Build Start Function
  participant JWTGen as JWT Generator
  participant CloudLog
  participant DirectSSE as Direct Log Stream (SSE)

  Client->>BuildStart: POST /build/start
  BuildStart->>BuildStart: create job (jobId)
  BuildStart->>JWTGen: generateLogStreamToken(jobId, userId, appId, JWT_SECRET)
  alt JWT secret present & token created
    JWTGen-->>BuildStart: logs_token
    BuildStart->>CloudLog: emit "Build logs stream request (deprecated proxy - use direct SSE)"
    BuildStart-->>Client: 200 { ..., logs_url, logs_token }
  else JWT secret missing or token error
    JWTGen-->>BuildStart: error / skipped
    BuildStart->>CloudLog: emit skip/error log
    BuildStart-->>Client: 200 { ... } (no logs fields)
  end
  Note over Client,DirectSSE: Client may use logs_url + logs_token to connect directly to SSE log stream
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I twitch my whiskers for a logging song,
Four hours of hops encoded safe and strong,
The old proxy nods and lets me pass,
I bound to SSE on a carrot-path,
A tiny JWT tucked in my paws all along.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description covers the Summary and Motivation sections well, but is missing required sections: Test plan (how to verify the endpoint returns logs_url/logs_token), Screenshots (not applicable here), and the Checklist section (linting, tests, documentation status). Add a 'Test plan' section describing how to verify the /build/start endpoint now returns logs_url and logs_token. Complete the 'Checklist' by confirming linting passed and whether documentation updates are needed.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: log streaming for Capgo Builder (public)' directly reflects the main change: improving log streaming for the native builder by adding logs_url and logs_token fields to enable direct SSE streaming instead of proxy-based streaming.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch builder-fix-logs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@supabase/functions/_backend/public/build/start.ts`:
- Around line 17-79: The generateLogStreamToken function currently accepts any
jwtSecret length—add a minimum-strength validation at the start of
generateLogStreamToken (e.g., require a minimum number of characters/entropy for
jwtSecret) and throw/return an error if it fails, referencing jwtSecret in the
check; alternatively replace the manual JWT creation with a standard library
(e.g., jose) to sign the token securely (update import/use to create an HS256
token with the provided jwtSecret and keep the same payload fields job_id,
user_id, app_id, iat, exp).
🧹 Nitpick comments (1)
supabase/functions/_backend/public/build/start.ts (1)

215-250: Good graceful degradation pattern.

The try/catch around token generation with fallback to the proxy approach maintains backward compatibility. Structured logging follows the coding guidelines.

One minor concern: the hardcoded fallback 'https://api.capgo.app' for PUBLIC_URL could cause issues in development or staging environments where the direct logs endpoint would point to production instead of the current environment.

💡 Consider logging a warning when using the fallback URL
-    const publicUrl = getEnv(c, 'PUBLIC_URL') || 'https://api.capgo.app'
+    const publicUrl = getEnv(c, 'PUBLIC_URL')
+    if (!publicUrl) {
+      cloudlog({
+        requestId: c.get('requestId'),
+        message: 'PUBLIC_URL not configured, using default',
+        job_id: jobId,
+      })
+    }
+    const effectivePublicUrl = publicUrl || 'https://api.capgo.app'

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@supabase/functions/_backend/public/build/start.ts`:
- Line 4: Reorder the imports so external modules come before parent/relative
imports: move the "import { SignJWT } from 'npm:jose'" line above the import of
"../../utils/hono.ts" (and any other relative imports) in start.ts; ensure
external imports (e.g., SignJWT from 'npm:jose') are grouped at the top, then
parent/relative imports (e.g., utils/hono.ts), and run the linter/formatter to
confirm the import order is correct.
🧹 Nitpick comments (1)
supabase/functions/_backend/public/build/start.ts (1)

18-35: Consider adding minimum secret length validation.

The function accepts any non-empty jwtSecret value. For HS256, secrets shorter than 32 characters provide weak security. The caller only checks if (jwtSecret) at line 178, so short secrets like "abc" would still produce weak tokens.

🔒 Suggested validation
 async function generateLogStreamToken(
   jobId: string,
   userId: string,
   appId: string,
   jwtSecret: string,
 ): Promise<string> {
+  if (jwtSecret.length < 32) {
+    throw new Error('JWT_SECRET must be at least 32 characters for secure signing')
+  }
+
   const secret = new TextEncoder().encode(jwtSecret)

Add issuer, audience, and subject claims to the JWT token for better
security. Move user_id to the standard 'sub' claim.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for direct log streaming from the Capgo Builder worker by introducing optional logs_url and logs_token fields to the /build/start endpoint response. This enables the CLI to bypass the existing proxy-based log streaming endpoint and connect directly to the builder worker, reducing operational costs and improving reliability.

Changes:

  • Adds JWT token generation for time-limited (4h) direct log stream access
  • Returns optional logs_url and logs_token in /build/start response when JWT_SECRET is configured
  • Adds deprecation notice to existing proxy-based /build/logs endpoint
  • Adds jose npm package (v6.1.3) for JWT signing

Reviewed changes

Copilot reviewed 4 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
supabase/functions/_backend/public/build/start.ts Implements JWT token generation and adds logs_url/logs_token to response
supabase/functions/_backend/public/build/logs.ts Adds deprecation notice for proxy-based endpoint
package.json Adds jose library dependency
bun.lock Lock file update for jose package
internal/cloudflare/.env.prod.secret Encrypted production environment configuration
internal/cloudflare/.env.preprod.secret Encrypted pre-production environment configuration
internal/cloudflare/.env.local.secret Encrypted local environment configuration
internal/supabase/.env.local.secret Encrypted local Supabase environment configuration
internal/how-to-deploy.md.secret Encrypted deployment documentation
internal/forgr-key.jks.secret Encrypted Android signing key
internal/forgr-key.jks.base64.secret Encrypted base64-encoded Android signing key
internal/capgo-394818-68ad1517d330.json.secret Encrypted GCP service account credentials
internal/Certificates_p12.p12.secret Encrypted iOS certificates
internal/Certificates.p12.secret Encrypted iOS certificates
internal/CICD.mobileprovision.secret Encrypted iOS provisioning profile
internal/AuthKey_8P7Y3V99PJ.p8.secret Encrypted iOS auth key
.gitsecret/paths/mapping.cfg Updated hash for encrypted prod environment file

@riderx riderx closed this Jan 30, 2026
@WcaleNieWolny WcaleNieWolny reopened this Feb 1, 2026
@WcaleNieWolny
Copy link
Copy Markdown
Contributor Author

@riderx Please merge this PR. Its a good PR for rewriting the logs system :)

@riderx riderx merged commit 227088d into main Feb 2, 2026
7 of 8 checks passed
@riderx riderx deleted the builder-fix-logs branch February 2, 2026 05:10
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Feb 2, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
5.0% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants