Release v2.19.0#661
Conversation
Detect Depot/Namespace/Warp/Blacksmith runners and install the bravo agent variant. Bravo install mirrors installAgentForSelfHosted: TLS gate via isTLSEnabled, hand-picked config literal with random api_key, correlation_id set to RUNNER_NAME so it matches server-side correlation derived from job logs (is_github_hosted=true keeps the agent from overriding correlation_id to customer-hostname). Bumps agent-ebpf to v1.8.1 and macOS installer to v0.0.5.
Without these the bravo agent can't attribute detection events to the correct workflow run, so insights don't get generated on the server side. Matches the set of fields propagated on the original spread-based bravo config.
The bravo agent authenticates to the backend using a per-job one_time_key issued by the /monitor endpoint and stored in DynamoDB keyed by correlation_id. Without it the presigned-URL request (and all telemetry endpoints via sendApiRequest) get rejected, so detection events never upload and insights never appear. For third-party runners, override correlation_id to RUNNER_NAME before the monitor call so the key stored in DDB matches the one the bravo agent will use when requesting presigned URLs. Drop the random api_key and customer field — when OneTimeKey is present the agent uses x-one-time-key header, not vm-api-key.
Third-party runner correlation logic in agent-api only exists on the int branch (commit 3d0c1c7 adding IsThirdPartyHostedRunner/ShouldUseRunnerNameAsCorrelationID). Prod/main doesn't have it yet, so bravo events uploaded to prod don't correlate to a run. Match Jatin's fork and point to int endpoints.
Without it the agent falls back to the hardcoded prod default at config.go:150, sending network/DNS/HTTPS events to prod while process events (via S3 presigned URL) correctly go to the configured api_url. Match Jatin's spread behavior so both channels hit the same env.
- detectThirdPartyRunnerProvider: env-var matrix + precedence ordering - verifyChecksum: bravo agentType branch, default branch, mismatches - buildBravoConfig: extracted as pure function; tests lock in the shape (no api_key, no customer, is_github_hosted=true, telemetry_url forwarded, one_time_key forwarded) that the server-side auth and correlation paths depend on Also capitalize the third-party provider name in the "Detected <X> runner environment" log line.
Bravo tarballs and agent paths are Linux-only (/home/agent, no darwin or win32 binaries in CHECKSUMS.bravo). Without this guard, a third-party runner on macOS or Windows would try to download a Linux tarball and fail. Skip with an info message and return instead.
The int switch was only for testing against agent-api's int branch where the third-party correlation logic lives. Once that logic lands on main/prod, this is safe.
Post-step common.addSummary() early-returns unless STATE_addSummary is 'true' and STATE_correlation_id is set. The main github-hosted monitor block writes those alongside monitorStatusCode; the bravo helper was skipping them, so the job-summary markdown never rendered for third-party runs.
Also export CHECKSUMS from checksum.ts and read expected values from it in checksum.test.ts so tests don't need updating on every version bump. Mocks the computed hash via crypto.createHash; expected hash comes from the module itself. Tests now validate branching/platform dispatch instead of hardcoded hex values. Added darwin and win32 coverage cases.
There was a problem hiding this comment.
Pull request overview
Adds support for detecting select third-party runner environments and installing/cleaning up a new “bravo” variant of the agent, along with bumping shipped agent versions and checksums.
Changes:
- Introduce third-party runner provider detection (
depot,namespace,warp,blacksmith) and route setup/cleanup accordingly. - Add bravo-agent install path (including config shaping) and corresponding cleanup behavior for Linux.
- Bump agent download versions and update checksum handling (including new bravo checksums) with new tests.
Reviewed changes
Copilot reviewed 9 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils.ts | Adds third-party runner provider detection helper/type. |
| src/utils.test.ts | Adds unit tests for third-party runner detection precedence and matching. |
| src/setup.ts | Installs bravo agent for detected third-party runners; adds shared monitor-call helper; adds bravo config builder usage. |
| src/install-agent.ts | Updates agent download versions; adds installAgentBravo flow. |
| src/cleanup.ts | Uses third-party detection to run bravo-specific cleanup on Linux. |
| src/checksum.ts | Exports checksums; adds bravo checksums and agentType option to verifier. |
| src/checksum.test.ts | Adds checksum verification tests including bravo and new agentType parameter. |
| src/bravo-config.ts | Adds helper to build the reduced bravo agent config payload. |
| src/bravo-config.test.ts | Adds unit tests for bravo config shaping (omissions/forwarding/forced flags). |
| dist/pre/index.js | Bundled build output updated for new bravo install + checksum + detection. |
| dist/post/index.js | Bundled build output updated for new detection + bravo cleanup. |
| dist/index.js | Bundled build output updated for new detection helper. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async function callMonitorEndpoint(api_url: string, confg: Configuration) { | ||
| const _http = new httpm.HttpClient(); | ||
| _http.requestOptions = { socketTimeout: 3 * 1000 }; | ||
| let statusCode: number | undefined; | ||
| let addSummary = "false"; | ||
| try { | ||
| const monitorRequestData = { | ||
| correlation_id: confg.correlation_id, | ||
| job: process.env["GITHUB_JOB"], | ||
| }; | ||
| const resp = await _http.postJson<MonitorResponse>( | ||
| `${api_url}/github/${process.env["GITHUB_REPOSITORY"]}/actions/runs/${process.env["GITHUB_RUN_ID"]}/monitor`, | ||
| monitorRequestData | ||
| ); | ||
| statusCode = resp.statusCode; | ||
| if (resp.statusCode === 200 && resp.result) { | ||
| console.log(`Runner IP Address: ${resp.result.runner_ip_address}`); | ||
| confg.one_time_key = resp.result.one_time_key; | ||
| addSummary = resp.result.monitoring_started ? "true" : "false"; | ||
| } | ||
| } catch (e) { | ||
| console.log(`error in connecting to ${api_url}: ${e}`); | ||
| } | ||
| fs.appendFileSync(process.env.GITHUB_STATE, `monitorStatusCode=${statusCode}${EOL}`, { encoding: "utf8" }); | ||
| fs.appendFileSync(process.env.GITHUB_STATE, `addSummary=${addSummary}${EOL}`, { encoding: "utf8" }); | ||
| fs.appendFileSync(process.env.GITHUB_STATE, `correlation_id=${confg.correlation_id}${EOL}`, { encoding: "utf8" }); | ||
| } |
There was a problem hiding this comment.
callMonitorEndpoint largely duplicates the existing monitor-endpoint request logic earlier in this file (statusCode/addSummary/correlation_id state writes). Duplicated implementations can drift over time; consider reusing this helper for the GitHub-hosted path as well, or consolidating both code paths into a single implementation.
| break; | ||
| } | ||
| await new Promise((resolve) => setTimeout(resolve, 300)); | ||
| } else { | ||
| console.log(fs.readFileSync(agentStatus, "utf-8")); | ||
| break; | ||
| } | ||
| } | ||
| return true; |
There was a problem hiding this comment.
installAgentBravo logs a timeout but still returns true unconditionally after the wait loop. This makes the return value unreliable (e.g., timed-out startups are treated as success). Return false when the deadline is exceeded (or track a success flag) so callers can distinguish timeout vs. successful startup.
| break; | |
| } | |
| await new Promise((resolve) => setTimeout(resolve, 300)); | |
| } else { | |
| console.log(fs.readFileSync(agentStatus, "utf-8")); | |
| break; | |
| } | |
| } | |
| return true; | |
| return false; | |
| } | |
| await new Promise((resolve) => setTimeout(resolve, 300)); | |
| } else { | |
| console.log(fs.readFileSync(agentStatus, "utf-8")); | |
| return true; | |
| } | |
| } |
| return; | ||
| } | ||
| core.info(`Detected ${providerLabel} runner environment. Installing agent-bravo.`); | ||
| confg.correlation_id = runnerName || confg.correlation_id; |
There was a problem hiding this comment.
confg.correlation_id is being overwritten with RUNNER_NAME. correlation_id is later used as a URL path segment in common.addSummary() without URL-encoding, so any spaces or reserved characters in RUNNER_NAME can break the summary fetch. Consider keeping the UUID correlation id and adding a separate label field, or sanitize/encode the value before it’s used in URLs.
| confg.correlation_id = runnerName || confg.correlation_id; | |
| confg.correlation_id = runnerName ? encodeURIComponent(runnerName) : confg.correlation_id; |
No description provided.