Skip to content

Route Antigravity AWF target through Gemini provider key#34839

Merged
pelikhan merged 8 commits into
mainfrom
copilot/antigravity-update-config-generation
May 26, 2026
Merged

Route Antigravity AWF target through Gemini provider key#34839
pelikhan merged 8 commits into
mainfrom
copilot/antigravity-update-config-generation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 26, 2026

Smoke Antigravity failed because generated AWF config used apiProxy.targets.antigravity, which the current firewall schema/runtime rejects. Antigravity now runs via the new harness but still depends on Gemini provider routing, so config generation must emit a supported provider target.

  • Config generation update

    • BuildAWFConfigJSON now maps Antigravity target resolution to apiProxy.targets.gemini instead of emitting apiProxy.targets.antigravity.
    • Precedence is explicit: when Antigravity target is present, it is used for the Gemini provider target.
    • Override logging was tightened for cases where both Gemini and Antigravity base URLs are configured.
  • Contract/documentation alignment in code

    • Updated AWF target-key comments to reflect supported keys and clarify that the Gemini key is also used for Antigravity routing.
  • Coverage additions

    • Added targeted tests for:
      • default Antigravity target mapping (generativelanguage.googleapis.com) through targets.gemini
      • custom ANTIGRAVITY_API_BASE_URL mapping through targets.gemini
      • absence of unsupported targets.antigravity
if antigravityTarget := GetAntigravityAPITarget(config.WorkflowData, config.EngineName); antigravityTarget != "" {
    targets["gemini"] = &AWFAPITargetConfig{Host: antigravityTarget}
} else if geminiTarget := GetGeminiAPITarget(config.WorkflowData, config.EngineName); geminiTarget != "" {
    targets["gemini"] = &AWFAPITargetConfig{Host: geminiTarget}
}

Copilot AI and others added 3 commits May 26, 2026 02:18
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot recompile

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 26, 2026

@copilot recompile

Done in 36e20fd — I recompiled and committed the regenerated lock workflow output.

Copilot AI requested a review from pelikhan May 26, 2026 02:40
@pelikhan
Copy link
Copy Markdown
Collaborator

Copilot AI and others added 2 commits May 26, 2026 02:58
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 26, 2026

@copilot invalid arguments see https://github.com/github/gh-aw/actions/runs/26429242977/job/77798928425#step:31:1

Fixed in 13f69a2 (plus follow-up clarification in a015dfd). The Antigravity invocation now uses supported agy args (--dangerously-skip-permissions) and no longer emits unsupported --yolo --skip-trust --output-format flags in smoke-antigravity.lock.yml.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review antigravity docs to configure keys to avoid authentication issue as in https://github.com/github/gh-aw/actions/runs/26429852770/job/77800686815#step:31:1

Copilot AI and others added 2 commits May 26, 2026 03:34
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 26, 2026

@copilot review antigravity docs to configure keys to avoid authentication issue as in https://github.com/github/gh-aw/actions/runs/26429852770/job/77800686815#step:31:1

Addressed in 4aeed01 (with follow-up safety fix in 875ea78).

Execute Antigravity CLI now exports GEMINI_API_KEY from the effective ANTIGRAVITY_API_KEY, so the Gemini provider proxy gets a key and Antigravity no longer falls back to interactive OAuth auth prompts. I also regenerated smoke-antigravity.lock.yml so the workflow includes the new key mapping and excludes GEMINI_API_KEY from sandbox env exposure.

@pelikhan pelikhan marked this pull request as ready for review May 26, 2026 04:01
Copilot AI review requested due to automatic review settings May 26, 2026 04:01
@pelikhan pelikhan merged commit 88fa3ba into main May 26, 2026
47 of 57 checks passed
@pelikhan pelikhan deleted the copilot/antigravity-update-config-generation branch May 26, 2026 04:02
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #34839 does not have the 'implementation' label and has only 78 new lines of code in business logic directories (below the 100-line threshold).

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

PR Code Quality Reviewer completed the code quality review.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 26, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions github-actions Bot mentioned this pull request May 26, 2026
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

Updates AWF config generation and Antigravity workflow execution so Antigravity traffic routes through the supported apiProxy.targets.gemini provider key (avoiding the rejected targets.antigravity key), while also aligning secret/env handling for Gemini-proxy authentication.

Changes:

  • Map Antigravity API target resolution onto apiProxy.targets.gemini (with explicit precedence and override logging).
  • Update Antigravity engine execution to use the current non-interactive permissions flag and to alias GEMINI_API_KEY from ANTIGRAVITY_API_KEY for proxy auth (while excluding it from the sandbox env).
  • Add/adjust tests and locked smoke workflow output to validate the new routing and env behavior.
Show a summary per file
File Description
pkg/workflow/awf_config.go Routes Antigravity target selection through the gemini provider key and updates target-key documentation/comments.
pkg/workflow/awf_config_test.go Adds tests asserting Antigravity target mapping uses targets.gemini and does not emit targets.antigravity.
pkg/workflow/antigravity_engine.go Updates Antigravity CLI invocation flags; adds GEMINI_API_KEY aliasing and excludes it from sandbox env.
pkg/workflow/antigravity_engine_test.go Updates assertions for new Antigravity CLI flags and validates GEMINI_API_KEY alias/exclusion behavior.
.github/workflows/smoke-antigravity.lock.yml Regenerates locked workflow to reflect targets.gemini, new CLI args, and GEMINI_API_KEY env/exclusion.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 2

// Route the Antigravity-resolved API target through the "gemini" provider key
// to match AWF's supported target providers.
geminiTarget := GetGeminiAPITarget(config.WorkflowData, config.EngineName)
if geminiTarget != "" && geminiTarget != antigravityTarget {
Comment on lines +311 to +314
assert.Contains(t, jsonStr, `"gemini"`, "should include gemini target for antigravity engine")
assert.Contains(t, jsonStr, "generativelanguage.googleapis.com", "should include default Gemini API hostname")
assert.NotContains(t, jsonStr, `"antigravity"`, "should not include unsupported antigravity target key")
})
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 1.3M

}
// The Antigravity CLI and AWF's Gemini API proxy both rely on a Gemini provider key.
// Keep GEMINI_API_KEY aligned with the effective ANTIGRAVITY_API_KEY by default so the
// workflow can authenticate non-interactively without requiring users to duplicate secrets.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Silent empty-string assignment if ANTIGRAVITY_API_KEY is absent from env: env["GEMINI_API_KEY"] will be set to "" rather than being omitted, injecting a blank credential into the step environment.

💡 Suggested fix
    if v := env["ANTIGRAVITY_API_KEY"]; v != "" {
        env["GEMINI_API_KEY"] = v
    }
}

If ANTIGRAVITY_API_KEY is missing or empty (e.g., due to a misconfigured workflow or a future reordering of env population), the current code silently forwards an empty string as GEMINI_API_KEY. The proxy will then receive a blank API key and fail with a confusing auth error rather than a clear "key not set" diagnostic. An explicit non-empty guard prevents this silent path.

if geminiTarget := GetGeminiAPITarget(config.WorkflowData, config.EngineName); geminiTarget != "" {
targets["gemini"] = &AWFAPITargetConfig{Host: geminiTarget}
// Route the Antigravity-resolved API target through the "gemini" provider key
// to match AWF's supported target providers.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

User's GEMINI_API_BASE_URL is silently dropped when ANTIGRAVITY_API_BASE_URL is also set: the conflict is logged only via awfConfigLog.Printf (a debug-only logger), so the operator never sees the warning unless DEBUG= is configured.

💡 Suggested fix

Surface the conflict as a visible warning using the console formatter, or return an error requiring the user to resolve the ambiguity explicitly:

if geminiTarget != "" && geminiTarget != antigravityTarget {
    // Surface to stderr, not just debug log
    fmt.Fprintf(os.Stderr, "warning: ANTIGRAVITY_API_BASE_URL overrides GEMINI_API_BASE_URL for the gemini proxy target; unset one to resolve ambiguity\n")
}

A user who has configured both ANTIGRAVITY_API_BASE_URL and GEMINI_API_BASE_URL will silently route all Gemini traffic through the Antigravity endpoint with no indication their Gemini config was discarded. This is a misconfiguration that should be surfaced loudly, not buried in debug output.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnose and /tdd — approving with two non-blocking suggestions.

📋 Key Themes & Highlights

Key Themes

  • Root cause fix is correct: remapping targets.antigravitytargets.gemini directly addresses the schema rejection; the approach is clean and explicit.
  • CLI flag migration is clean: replacing --yolo/--skip-trust/--output-format stream-json with --dangerously-skip-permissions aligns with the new Antigravity CLI API; tests assert both the presence and the absence of old flags.
  • Two minor gaps worth a follow-up:
    1. The dual-URL ambiguity path (GEMINI_API_BASE_URL + ANTIGRAVITY_API_BASE_URL both set) has a warning log but no regression test — see inline comment.
    2. Silent empty-string propagation of GEMINI_API_KEY when ANTIGRAVITY_API_KEY is absent could produce opaque 401s — see inline comment.

Positive Highlights

  • ✅ Three focused new tests covering default target, custom ANTIGRAVITY_API_BASE_URL, and explicit absence of the unsupported antigravity key
  • GEMINI_API_KEY correctly added to both ExcludeEnvVarNames (hidden from agent) and allowedSecrets (passed through FilterEnvForSecrets) — dual-listing is intentional and the comment explains why
  • ✅ Precedence logic (antigravity beats gemini) is explicit with an if/else-if rather than two independent ifs
  • ✅ Lock file regenerated end-to-end, making the fix observable in CI

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 1.5M

assert.NotContains(t, jsonStr, `"antigravity"`, "should not include unsupported antigravity target key")
})

t.Run("no API targets section when no custom endpoints are configured", func(t *testing.T) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Missing test for the dual-URL ambiguity warning path — the new branch at awf_config.go:308 (both GEMINI_API_BASE_URL and ANTIGRAVITY_API_BASE_URL set) is not covered.

💡 Suggested test sketch
t.Run("antigravity overrides gemini when both base URLs are set", func(t *testing.T) {
    config := AWFCommandConfig{
        EngineName: "antigravity",
        WorkflowData: &WorkflowData{
            EngineConfig: &EngineConfig{
                ID: "antigravity",
                Env: map[string]string{
                    "ANTIGRAVITY_API_BASE_URL": "(antigravity.internal/redacted),
                    "GEMINI_API_BASE_URL":      "(gemini.internal/redacted),
                },
            },
            NetworkPermissions: &NetworkPermissions{
                Firewall: &FirewallConfig{Enabled: true},
            },
        },
    }
    jsonStr, err := BuildAWFConfigJSON(config)
    require.NoError(t, err)
    // Antigravity target wins; Gemini base URL is ignored
    assert.Contains(t, jsonStr, "antigravity.internal")
    assert.NotContains(t, jsonStr, "gemini.internal")
})

This path emits a log warning today but has no assertion ensuring the correct target wins.

// Keep GEMINI_API_KEY aligned with the effective ANTIGRAVITY_API_KEY by default so the
// workflow can authenticate non-interactively without requiring users to duplicate secrets.
if _, hasGeminiKey := env["GEMINI_API_KEY"]; !hasGeminiKey {
env["GEMINI_API_KEY"] = env["ANTIGRAVITY_API_KEY"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/diagnose] If ANTIGRAVITY_API_KEY is absent from env, this silently sets GEMINI_API_KEY to an empty string, which will pass the FilterEnvForSecrets check and appear in the step env as an empty value — a subtle auth failure that's hard to diagnose.

💡 Suggested guard
if apiKey, hasAPIKey := env["ANTIGRAVITY_API_KEY"]; hasAPIKey && apiKey != "" {
    env["GEMINI_API_KEY"] = apiKey
}

Or at minimum log a warning when propagation is skipped, so the misconfiguration surfaces early in the run log rather than as a 401 from the proxy.

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

🔶 Test Quality Score: 50/100 — Needs Improvement

Analyzed 2 new test sub-cases and ~5 modified assertion groups: both new tests are strong behavioral contracts, but neither covers an error path or edge/boundary case, and the test file grows at 3.75× the production code addition rate.

📊 Metrics & Test Classification (2 new tests + 5 modified assertion groups analyzed)
Metric Value
New/modified tests analyzed 2 new sub-cases + ~5 modified assertion groups
✅ Design tests (behavioral contracts) 2 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 0 (0%)
Duplicate test clusters 0
Test inflation detected ✅ YES — awf_config_test.go +45 lines vs awf_config.go +12 lines (3.75:1 ratio)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Issues Detected
"antigravity engine routes API target through gemini provider" pkg/workflow/awf_config_test.go:296 ✅ Design No error path; happy-path only
"antigravity custom base URL maps to gemini provider target" pkg/workflow/awf_config_test.go:316 ✅ Design No error path; custom URL is an edge case but not an error case
Modified assertions in "basic execution" pkg/workflow/antigravity_engine_test.go:141 ✅ Design GEMINI_API_KEY env var assertion added
Modified assertions in "environment variables" pkg/workflow/antigravity_engine_test.go:220 ✅ Design GEMINI_API_KEY alias assertion added
Modified assertions in "engine env overrides..." pkg/workflow/antigravity_engine_test.go:266 ✅ Design GEMINI_API_KEY tracking through override added
Modified assertions in "validates ANTIGRAVITY_API_KEY secret" pkg/workflow/antigravity_engine_test.go:287 ✅ Design Negative GEMINI_API_KEY assertions added
Modified assertions in "firewall enabled" pkg/workflow/antigravity_engine_test.go:333 ✅ Design --exclude-env GEMINI_API_KEY assertion added

Language Support

Tests analyzed:

  • 🟨 JavaScript (*.test.cjs, *.test.js): 0 tests
⚠️ Flagged Tests — Review Suggested (2 issue(s))

⚠️ "antigravity engine routes API target through gemini provider" (pkg/workflow/awf_config_test.go:296)

Classification: Design test
Issue: Happy-path only. Verifies the default Gemini target is emitted, but has no assertions for error conditions — e.g., what if NetworkPermissions is nil, or the firewall is disabled (should the gemini target still appear?).
What design invariant does this test enforce? The AWF config JSON for antigravity must route through the gemini provider key, not an unsupported antigravity target key.
What would break if deleted? A regression that emits the wrong target key would only be caught by the custom-URL test below.
Suggested improvement: Add a case with Firewall.Enabled: false to verify the target is omitted (or still present) when firewall is disabled.


⚠️ "antigravity custom base URL maps to gemini provider target" (pkg/workflow/awf_config_test.go:316)

Classification: Design test
Issue: Verifies the happy path for a valid custom ANTIGRAVITY_API_BASE_URL. No error case for a malformed URL (e.g., "not-a-url" or empty string).
What design invariant does this test enforce? A user-supplied ANTIGRAVITY_API_BASE_URL override must be reflected in the gemini proxy target host, not the default Gemini hostname.
Suggested improvement: Add one case with a malformed URL and assert on the error return or that the code falls back to the default hostname gracefully.

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%), and no coding-guideline violations were detected. Score of 50/100 reflects zero error/edge-case coverage in the two new test cases and a 3.75:1 test-inflation ratio — consider adding error-path coverage before merge.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Give false assurance: they pass even when the system is wrong

References: §26431514075

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 2.6M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 50/100. Test quality is acceptable — 0% of new tests are implementation tests (threshold: 30%). No coding-guideline violations detected. Note: neither of the two new test cases covers an error path; consider adding error/edge-case coverage to improve the score.

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