Skip to content

[codex] Add Tailscale and Aperture integration support#122

Open
Telli wants to merge 4 commits into
mainfrom
codex/tailscale-aperture-integration
Open

[codex] Add Tailscale and Aperture integration support#122
Telli wants to merge 4 commits into
mainfrom
codex/tailscale-aperture-integration

Conversation

@Telli
Copy link
Copy Markdown
Contributor

@Telli Telli commented May 20, 2026

Summary

Adds first-class documentation for Tailscale deployment patterns and optional Aperture-by-Tailscale provider routing without changing the default OpenClaw.NET provider behavior or quickstart.

Changes

  • Add docs/deployment/TAILSCALE.md with Serve/Funnel guidance, Aperture positioning, security notes, identity-header caveats, SSH future direction, and troubleshooting.
  • Add discoverability links in README and docs navigation.
  • Treat Provider = "aperture" as an OpenAI-compatible upstream route with Aperture-friendly labels/status.
  • Add optional AuthMode and SendRequestMetadata configuration, including no-key tailnet-identity mode.
  • Add openclaw setup provider aperture helper.
  • Extend doctor/smoke checks for Aperture while keeping offline mode non-failing.
  • Add tests for provider behavior, no-key auth, metadata opt-in, doctor validation, failure isolation, and setup output.

Validation

  • dotnet test src/OpenClaw.Tests/OpenClaw.Tests.csproj --configuration Release --filter "FullyQualifiedName~LlmClientFactoryTests|FullyQualifiedName~ModelProfileSelectionTests|FullyQualifiedName~SetupCommandTests|FullyQualifiedName~DocsConsistencyTests|FullyQualifiedName~ConfigValidatorTests"
  • dotnet test OpenClaw.Net.slnx --configuration Release
  • dotnet build OpenClaw.Net.slnx --configuration Release --no-restore

Notes

Metadata propagation is disabled by default and only applies to explicitly enabled profiles. Invalid Aperture profiles remain isolated from unrelated valid providers.

Summary by CodeRabbit

  • New Features

    • Added Aperture (via Tailscale) as a supported LLM provider with selectable auth modes (bearer or tailnet-identity).
    • Per-profile opt-in request-metadata transmission for richer context.
    • New CLI provider setup flow and help examples for configuring Aperture and auth modes.
  • Documentation

    • New Tailscale & Aperture integration guide plus updated docs/navigation entries and troubleshooting notes.
  • Tests

    • Added tests covering Aperture auth modes, metadata behavior, profile handling, and setup command.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a0abf7e3-f419-4dad-b4f1-a5a068f5e562

📥 Commits

Reviewing files that changed from the base of the PR and between dee1a3d and 288e370.

📒 Files selected for processing (1)
  • src/OpenClaw.Tests/SetupCommandTests.cs

📝 Walkthrough

Walkthrough

Adds Aperture/Tailscale integration: new AuthMode and SendRequestMetadata fields flow through models, validation, CLI setup, gateway client/policy, profile registry, docs, and tests to support bearer vs tailnet-identity auth and optional request metadata injection.

Changes

Tailscale And Aperture Provider Integration

Layer / File(s) Summary
Data Models and Configuration Contracts
src/OpenClaw.Core/Models/GatewayConfig.cs, src/OpenClaw.Core/Models/ModelProfiles.cs
LlmProviderConfig, ModelProfileConfig, ModelProfile, and ModelProfileStatus now include AuthMode and SendRequestMetadata (and ProviderGateway in status) to carry auth-mode and metadata behavior.
Validation Framework and Credential Logic
src/OpenClaw.Core/Validation/ConfigValidator.cs, src/OpenClaw.Core/Validation/ModelDoctorEvaluator.cs, src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs
Registers aperture as a built-in provider; validates AuthMode as bearer or tailnet-identity (and provider support for tailnet-identity); makes endpoint and API-key requirements conditional on auth-mode (allowing tailnet-identity to bypass API keys for supported providers); and refactors capability inference.
CLI Setup Command for Aperture
src/OpenClaw.Cli/Program.cs, src/OpenClaw.Cli/SetupCommand.cs
Adds openclaw setup provider aperture flow with option parsing, NormalizeApertureAuthMode, ParseBooleanOption, ResolveConfiguredPath, config load/create, profile upsert, validation, directory resolution, saving, and env example generation; also updates help text examples.
Gateway Execution and OpenAI-Compatible Client Factory
src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs, src/OpenClaw.Gateway/GatewayLlmExecutionService.cs
Routes aperture through CreateOpenAiCompatibleClient; introduces OpenClawProviderRequestPolicy to optionally remove Authorization and inject metadata headers via an AsyncLocal scope; wraps clients with OpenClawProviderRequestMetadataChatClient when needed; injects request metadata into ChatOptions for standard and streaming execution.
Model Profile Registry and Capability Detection
src/OpenClaw.Gateway/Models/ConfiguredModelProfileRegistry.cs
Propagates AuthMode and SendRequestMetadata through profile defaults, conversion, status listing, capability detection (adding aperture to several support matrices), and validation (BaseUrl requirement for aperture and auth-mode-aware API-key checks); adds helpers for aperture detection and gateway resolution.
Deployment and User Documentation
README.md, docs/README.md, docs/SITE_MAP.md, docs/USER_GUIDE.md, docs/deployment/TAILSCALE.md
Adds docs/deployment/TAILSCALE.md with Tailscale Serve/Funnel patterns, Aperture examples, identity/header guidance, default metadata behavior, security notes, and troubleshooting; updates README, docs index, USER_GUIDE provider list, and SITE_MAP navigation (note: docs/README.md includes a duplicate deployment/TAILSCALE.md entry).
Integration and Unit Tests
src/OpenClaw.Tests/LlmClientFactoryTests.cs, src/OpenClaw.Tests/ModelProfileSelectionTests.cs, src/OpenClaw.Tests/SetupCommandTests.cs, src/OpenClaw.Tests/ConfigValidatorTests.cs
Adds tests verifying Aperture tailnet-identity suppresses Authorization header and that SendRequestMetadata forwards metadata headers; adds smoke-probe and validation tests for auth-mode behavior; setup command integration test for non-interactive tailnet-identity profile; and a minimal OpenAI-compatible test server helper.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐇 OpenClaw's Tailscale Journey

A gateway seeks the Tailscale glow,
Where Aperture routes the requests flow,
Auth modes dance—bearer and identity blend,
Metadata whispers from end to end.
Secure and private, the path now clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.01% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding Tailscale and Aperture integration support, which is the primary objective documented in the PR description.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/tailscale-aperture-integration

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

@Telli Telli marked this pull request as ready for review May 20, 2026 08:29
Copilot AI review requested due to automatic review settings May 20, 2026 08:29
Comment thread src/OpenClaw.Tests/SetupCommandTests.cs Fixed
Comment thread src/OpenClaw.Cli/SetupCommand.cs Fixed
Comment thread src/OpenClaw.Cli/SetupCommand.cs Fixed
Comment thread src/OpenClaw.Cli/SetupCommand.cs Fixed
Comment thread src/OpenClaw.Tests/SetupCommandTests.cs Fixed
Comment thread src/OpenClaw.Tests/SetupCommandTests.cs Fixed
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented May 20, 2026

🤖 Augment PR Summary

Summary: Adds optional Tailscale deployment documentation and first-class Aperture-by-Tailscale integration as an OpenAI-compatible upstream route, without changing the default OpenClaw.NET provider behavior.

Changes:

  • Documentation: adds docs/deployment/TAILSCALE.md and links it from the README and docs navigation.
  • Config: introduces AuthMode and SendRequestMetadata on both the root LLM config and per-model profiles.
  • Gateway: treats provider "aperture" as OpenAI-compatible and adds a request pipeline policy to support tailnet-identity (no bearer token) and optional metadata headers.
  • Execution: optionally attaches OpenClaw routing/session metadata to outbound requests (opt-in via SendRequestMetadata).
  • CLI: adds openclaw setup provider aperture helper to write/update an Aperture profile and env example file.
  • Validation/doctor/smoke: recognizes Aperture, validates auth mode, supports no-key tailnet-identity, and keeps invalid Aperture profiles isolated from other providers.
  • Tests: adds coverage for auth header removal, metadata opt-in, model doctor behavior, profile isolation, and setup output.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/OpenClaw.Cli/SetupCommand.cs Outdated
return 2;
}

var filteredArgs = args.Where(arg => !string.Equals(arg, provider, StringComparison.Ordinal)).ToArray();
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 20, 2026

Choose a reason for hiding this comment

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

src/OpenClaw.Cli/SetupCommand.cs:519: filteredArgs removes the provider token using StringComparison.Ordinal, so openclaw setup provider Aperture ... (different casing) can leave the positional arg in place and make CliArgs.Parse treat it as an unexpected argument.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

}, embeddingModel!),
"gemini" or "google" => CreateGeminiEmbeddingClient(config, embeddingModel!),
"openai-compatible" or "groq" or "together" or "lmstudio" =>
"openai-compatible" or "aperture" or "groq" or "together" or "lmstudio" =>
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 20, 2026

Choose a reason for hiding this comment

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

src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs:185-191: the embeddings path for "aperture"/"openai-compatible" doesn’t carry AuthMode/SendRequestMetadata, so tailnet-identity profiles may still require an API key (and metadata behavior may differ) for embeddings even though chat supports no-key mode.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

if (string.IsNullOrWhiteSpace(apiKey))
{
if (!IsTailnetIdentityAuth(llm.AuthMode))
throw new InvalidOperationException("MODEL_PROVIDER_KEY must be set for the OpenAI-compatible provider.");
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 20, 2026

Choose a reason for hiding this comment

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

src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs:260: when Provider="aperture" is missing an API key in bearer mode, the thrown message says “OpenAI-compatible provider”, which may mislead users who are following the Aperture docs/env var naming.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Copy link
Copy Markdown

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

Adds optional first-class Tailscale deployment documentation plus an Aperture-by-Tailscale provider alias/path, including new configuration knobs (AuthMode, SendRequestMetadata), CLI setup assistance, and expanded validation/doctor/smoke behavior—without changing default provider behavior unless explicitly configured.

Changes:

  • Document Tailscale Serve/Funnel deployment patterns and Aperture positioning, with security/trust-boundary notes.
  • Introduce Provider = "aperture" as an OpenAI-compatible upstream route, including AuthMode=tailnet-identity (no bearer token) and opt-in request metadata headers.
  • Add openclaw setup provider aperture flow plus updated validation/doctor/smoke checks and tests.

Reviewed changes

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

Show a summary per file
File Description
src/OpenClaw.Tests/SetupCommandTests.cs Adds coverage for setup provider aperture writing a tailnet-identity profile and env example behavior.
src/OpenClaw.Tests/ModelProfileSelectionTests.cs Adds tests for doctor behavior (no-key tailnet identity) and failure isolation for broken Aperture profiles.
src/OpenClaw.Tests/LlmClientFactoryTests.cs Adds integration-style tests for Authorization stripping and metadata header propagation.
src/OpenClaw.Gateway/Models/ConfiguredModelProfileRegistry.cs Extends profile status/config resolution to include Aperture labeling + auth/metadata fields and validation tweaks.
src/OpenClaw.Gateway/GatewayLlmExecutionService.cs Injects opt-in request metadata into outgoing ChatOptions for compatible providers.
src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs Adds OpenAI-compatible client wrapper/policy to strip auth for tailnet-identity and to apply metadata headers.
src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs Allows smoke probe configuration for Aperture and tailnet-identity “no key” mode.
src/OpenClaw.Core/Validation/ModelDoctorEvaluator.cs Updates doctor validation/capabilities to recognize Aperture and tailnet-identity credential rules.
src/OpenClaw.Core/Validation/ConfigValidator.cs Adds aperture provider id and validates AuthMode values at root/profile level.
src/OpenClaw.Core/Models/ModelProfiles.cs Adds AuthMode / SendRequestMetadata to profile config, model profile, and status DTOs.
src/OpenClaw.Core/Models/GatewayConfig.cs Adds root Llm.AuthMode / Llm.SendRequestMetadata configuration.
src/OpenClaw.Cli/SetupCommand.cs Implements openclaw setup provider aperture including tailnet-identity + metadata opt-in flags.
src/OpenClaw.Cli/Program.cs Adds CLI help examples for the new setup flow.
README.md Adds discoverability section + docs link for Tailscale/Aperture.
docs/USER_GUIDE.md Documents Aperture provider usage and setup helper invocation.
docs/SITE_MAP.md Adds nav entry for the new deployment doc.
docs/README.md Adds doc index links for Tailscale/Aperture guidance.
docs/deployment/TAILSCALE.md New deployment guide for Tailscale Serve/Funnel and Aperture routing patterns.
Comments suppressed due to low confidence (1)

src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs:192

  • Tailnet-identity mode is supported for chat requests, but CreateEmbeddingGenerator routes aperture/openai-compatible embeddings through CreateOpenAiEmbeddingClient, which always requires an API key and will throw at runtime (e.g., when SQLite vector memory is enabled). Either extend the tailnet-identity behavior to embeddings too (same policy + placeholder credential) or fail fast with a clearer validation/error when embeddings are requested under AuthMode=tailnet-identity.
    public static IEmbeddingGenerator<string, Embedding<float>>? CreateEmbeddingGenerator(
        LlmProviderConfig config, string? embeddingModel)
    {
        if (string.IsNullOrWhiteSpace(embeddingModel))
            return null;

        return config.Provider.ToLowerInvariant() switch
        {
            "openai" or "azure-openai" => CreateOpenAiEmbeddingClient(config, embeddingModel!),
            "ollama" => new OllamaEmbeddingGenerator(new LlmProviderConfig
            {
                ApiKey = config.ApiKey,
                Endpoint = OllamaEndpointNormalizer.NormalizeBaseUrl(config.Endpoint),
                Model = config.Model
            }, embeddingModel!),
            "gemini" or "google" => CreateGeminiEmbeddingClient(config, embeddingModel!),
            "openai-compatible" or "aperture" or "groq" or "together" or "lmstudio" =>
                CreateOpenAiEmbeddingClient(new LlmProviderConfig
                {
                    ApiKey = config.ApiKey,
                    Model = config.Model,
                    Endpoint = config.Endpoint
                }, embeddingModel!),
            "anthropic-vertex" or "amazon-bedrock" => null,

Comment thread src/OpenClaw.Cli/SetupCommand.cs Outdated
return 2;
}

var filteredArgs = args.Where(arg => !string.Equals(arg, provider, StringComparison.Ordinal)).ToArray();
Comment thread src/OpenClaw.Cli/SetupCommand.cs Outdated
var provider = args.FirstOrDefault(arg => !arg.StartsWith("--", StringComparison.Ordinal));
if (!string.Equals(provider, "aperture", StringComparison.OrdinalIgnoreCase))
{
error.WriteLine("Usage: openclaw setup provider aperture [--config <path>] [--endpoint <url>] [--model <route>] [--auth-mode <bearer|tailnet-identity>] [--env-var <name>] [--send-request-metadata <true|false>]");
Comment on lines +256 to +263
var apiKey = llm.ApiKey;
if (string.IsNullOrWhiteSpace(apiKey))
{
if (!IsTailnetIdentityAuth(llm.AuthMode))
throw new InvalidOperationException("MODEL_PROVIDER_KEY must be set for the OpenAI-compatible provider.");

apiKey = "openclaw-tailnet-identity";
}
Comment on lines +177 to +180
await app.StartAsync();
var address = app.Urls.FirstOrDefault()
?? app.Services.GetRequiredService<IServerAddressesFeature>().Addresses.First();
return new OpenAiCompatibleTestServer(app, address.TrimEnd('/'), headers);
Copy link
Copy Markdown

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs (1)

185-191: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tailnet-identity config is inconsistent for embeddings (no-key mode breaks at runtime).

Chat supports AuthMode=tailnet-identity without API key, but the embedding path still requires ApiKey and doesn’t carry AuthMode. This creates a runtime-only failure for otherwise valid aperture profile configs.

Suggested fail-fast diff (until keyless embeddings are implemented)
@@
             "openai-compatible" or "aperture" or "groq" or "together" or "lmstudio" =>
-                CreateOpenAiEmbeddingClient(new LlmProviderConfig
+                CreateOpenAiEmbeddingClient(new LlmProviderConfig
                 {
                     ApiKey = config.ApiKey,
+                    AuthMode = config.AuthMode,
                     Model = config.Model,
                     Endpoint = config.Endpoint
                 }, embeddingModel!),
@@
     private static IEmbeddingGenerator<string, Embedding<float>> CreateOpenAiEmbeddingClient(
         LlmProviderConfig config, string embeddingModel)
     {
+        if (IsTailnetIdentityAuth(config.AuthMode))
+            throw new InvalidOperationException("Embeddings do not support AuthMode=tailnet-identity yet. Configure an API key or disable embeddings for this profile.");
+
         var transport = CreateTransportOptions(config.Endpoint);
         var client = new OpenAI.OpenAIClient(
             new ApiKeyCredential(config.ApiKey ?? throw new InvalidOperationException("API key required for embeddings.")),
             CreateOpenAiClientOptions(transport));

As per coding guidelines, "Preserve existing configuration behavior unless intentionally changing it."

Also applies to: 231-237

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs` around lines 185 - 191,
The embedding client creation path (CreateOpenAiEmbeddingClient with
LlmProviderConfig and embeddingModel) does not propagate AuthMode and still
assumes ApiKey, causing runtime failures for `AuthMode=tailnet-identity` no-key
configs; update the embedding branch to carry through the provider AuthMode from
the incoming config (add AuthMode to the LlmProviderConfig passed into
CreateOpenAiEmbeddingClient) and add a fail-fast check: if AuthMode is not
key-based (e.g., "tailnet-identity") and no ApiKey is present, throw or return a
clear configuration error until keyless embeddings are implemented (apply the
same fix to the other embedding branch around the 231-237 area).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/SITE_MAP.md`:
- Line 32: The SITE_MAP.md Primary Navigation row for "Integrations | Tailscale
And Aperture" was added but the Sidebar Grouping list was not updated; open the
Sidebar Grouping section and add the entry "Tailscale And Aperture" under the
"Integrations" group (matching the label and link format used elsewhere, e.g.,
the existing Integrations items) so the Sidebar Grouping and Primary Navigation
remain consistent.

In `@src/OpenClaw.Cli/SetupCommand.cs`:
- Around line 639-641: The code is creating a directory from
config.Tooling.WorkspaceRoot without resolving config refs (e.g.,
env:OPENCLAW_WORKSPACE); instead resolve that value first and only call
Directory.CreateDirectory on the resolved path. Locate the creation logic around
Directory.CreateDirectory and replace the direct use of
config.Tooling.WorkspaceRoot with the resolved string (using the existing config
resolution utility or method you have in the project), check for null/empty
after resolution, and then call Directory.CreateDirectory on the resolved path
to avoid creating literal "env:..." folders or invalid paths.
- Around line 643-653: The code saves the merged Gateway config immediately
using GatewayConfigFile.SaveAsync without validating it first; call
ConfigValidator.Validate(config) (or the appropriate async/validation helper
used in the project) and handle/propagate any validation errors before calling
GatewayConfigFile.SaveAsync so malformed provider or tooling settings are not
persisted; locate the save call in SetupCommand.cs (the block using
GatewayConfigFile.SaveAsync and subsequent File.WriteAllTextAsync for
envExamplePath) and insert the validation step, aborting the save/write if
validation fails and surfacing the validation errors to the caller/user.

In `@src/OpenClaw.Core/Validation/ConfigValidator.cs`:
- Around line 70-72: ConfigValidator currently skips provider-specific checks
when Models.Profiles is empty; you must validate the implicit default profile
derived from OpenClaw:Llm so bad configs like Llm.Provider="aperture" fail fast.
Update ConfigValidator.Validate (or the surrounding logic where
IsValidProviderAuthMode and ValidatePromptCaching are called) to detect when
Models.Profiles is empty and materialize/validate the implicit profile using the
same validation paths (e.g., run the provider auth checks used by
IsValidProviderAuthMode, provider-specific credential/endpoint checks, and call
ValidatePromptCaching with the implicit profile's Provider and PromptCaching
values). Reuse existing symbols (IsValidProviderAuthMode, ValidatePromptCaching,
Models.Profiles, config.Llm.Provider, config.Llm.PromptCaching) rather than
duplicating logic so the implicit profile fails with the same errors as an
explicit profile.

In `@src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs`:
- Around line 151-152: The OpenAI-style request builder is unconditionally
adding an Authorization header from config.ApiKey, causing tailnet-identity
probes to use the wrong auth; modify BuildOpenAiStyleRequest to accept a
suppressAuthorization (bool) parameter and, when true, skip adding the
"Authorization: Bearer ..." header even if config.ApiKey is present; update the
call sites in ProviderSmokeProbe where you build requests for
"openai"/"openai-compatible"/"aperture"/etc. (the switch branch that calls
BuildOpenAiStyleRequest and the similar block around lines 268-280) to pass
suppressAuthorization=true when HasRequiredCredentials/your probe-intent
indicates the probe should use tailnet-identity (or when provider ==
"tailnet-identity" / config indicates tailnet identity), leaving behavior
unchanged otherwise.

In `@src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs`:
- Around line 375-379: OpenClawProviderRequestPolicy.Apply currently copies
arbitrary metadata headers into message.Request.Headers via the loop over
headers and message.Request.Headers.Set; modify that loop to skip injection of
sensitive header names (e.g., "Authorization", "Cookie", "Proxy-Authorization",
"WWW-Authenticate" — perform a case-insensitive comparison) so these are never
re-added, ensure you trim names/values and only set when not in the blocked
list, and optionally centralize the blocked names into a small readonly HashSet
used by the Apply method to make the rule obvious and maintainable.

---

Outside diff comments:
In `@src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs`:
- Around line 185-191: The embedding client creation path
(CreateOpenAiEmbeddingClient with LlmProviderConfig and embeddingModel) does not
propagate AuthMode and still assumes ApiKey, causing runtime failures for
`AuthMode=tailnet-identity` no-key configs; update the embedding branch to carry
through the provider AuthMode from the incoming config (add AuthMode to the
LlmProviderConfig passed into CreateOpenAiEmbeddingClient) and add a fail-fast
check: if AuthMode is not key-based (e.g., "tailnet-identity") and no ApiKey is
present, throw or return a clear configuration error until keyless embeddings
are implemented (apply the same fix to the other embedding branch around the
231-237 area).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bdd37f63-1042-471f-a62a-050c69053da9

📥 Commits

Reviewing files that changed from the base of the PR and between 3fffdd8 and f012050.

📒 Files selected for processing (18)
  • README.md
  • docs/README.md
  • docs/SITE_MAP.md
  • docs/USER_GUIDE.md
  • docs/deployment/TAILSCALE.md
  • src/OpenClaw.Cli/Program.cs
  • src/OpenClaw.Cli/SetupCommand.cs
  • src/OpenClaw.Core/Models/GatewayConfig.cs
  • src/OpenClaw.Core/Models/ModelProfiles.cs
  • src/OpenClaw.Core/Validation/ConfigValidator.cs
  • src/OpenClaw.Core/Validation/ModelDoctorEvaluator.cs
  • src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs
  • src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs
  • src/OpenClaw.Gateway/GatewayLlmExecutionService.cs
  • src/OpenClaw.Gateway/Models/ConfiguredModelProfileRegistry.cs
  • src/OpenClaw.Tests/LlmClientFactoryTests.cs
  • src/OpenClaw.Tests/ModelProfileSelectionTests.cs
  • src/OpenClaw.Tests/SetupCommandTests.cs

Comment thread docs/SITE_MAP.md
Comment thread src/OpenClaw.Cli/SetupCommand.cs Outdated
Comment thread src/OpenClaw.Cli/SetupCommand.cs
Comment thread src/OpenClaw.Core/Validation/ConfigValidator.cs
Comment thread src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs Outdated
Comment thread src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs
Comment thread src/OpenClaw.Tests/SetupCommandTests.cs Fixed
Copy link
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/OpenClaw.Cli/SetupCommand.cs`:
- Line 519: The current filtering (var filteredArgs = args.Where(arg =>
!string.Equals(arg, provider, StringComparison.OrdinalIgnoreCase)).ToArray();)
removes every argument matching provider (e.g., "aperture") including legitimate
option values; change it to remove only the single positional provider token
instead of all matching values by locating the first index of the provider token
in args (or the first token that is not an option/starts-with '-' if you need to
be stricter) and creating filteredArgs by skipping/removing only that single
element; update the expression where filteredArgs is defined (reference symbols:
filteredArgs, args, provider) to use an index-based removal (e.g., find index
via Array.IndexOf or manual loop, then build a new array without that one
element) so other option values are preserved.

In `@src/OpenClaw.Core/Validation/ConfigValidator.cs`:
- Around line 70-71: Update IsValidProviderAuthMode validation to be
provider-aware: when config.Llm.AuthMode equals "tailnet-identity" ensure
config.Llm.Provider is one of the providers that support tailnet identity (use
the same provider-checking logic used elsewhere or a centralized helper like
SupportsTailnetIdentity(providerName)); if not, add a validation error stating
that tailnet-identity is unsupported for that provider. Apply the same
provider-scoped check to the other occurrences referenced (around the logic at
the blocks corresponding to lines 632-633 and 893-900) so
AuthMode="tailnet-identity" fails-fast for unsupported providers.

In `@src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs`:
- Line 152: The current call in ProviderSmokeProbe to BuildOpenAiStyleRequest
passes suppressAuthorization based solely on
IsTailnetIdentityAuth(config.AuthMode), which suppresses Authorization for all
OpenAI-style providers; change it so suppression is applied only when the
provider actually supports tailnet-identity auth. In ProviderSmokeProbe (the
call site for BuildOpenAiStyleRequest), add a provider-capability check (e.g., a
new predicate like ProviderSupportsTailnetIdentity(provider) or an existing
provider.Type/Name check) and pass suppressAuthorization:
IsTailnetIdentityAuth(config.AuthMode) &&
ProviderSupportsTailnetIdentity(provider) (or equivalent), ensuring
BuildOpenAiStyleRequest is unchanged and only the argument value is constrained
to supported providers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ad3c46e3-dc94-4928-8d07-d80eb34cb542

📥 Commits

Reviewing files that changed from the base of the PR and between f012050 and 81ba141.

📒 Files selected for processing (8)
  • docs/SITE_MAP.md
  • src/OpenClaw.Cli/SetupCommand.cs
  • src/OpenClaw.Core/Validation/ConfigValidator.cs
  • src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs
  • src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs
  • src/OpenClaw.Tests/ConfigValidatorTests.cs
  • src/OpenClaw.Tests/LlmClientFactoryTests.cs
  • src/OpenClaw.Tests/SetupCommandTests.cs

Comment thread src/OpenClaw.Cli/SetupCommand.cs Outdated
Comment thread src/OpenClaw.Core/Validation/ConfigValidator.cs
Comment thread src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs Outdated
Comment thread src/OpenClaw.Tests/SetupCommandTests.cs Fixed
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
src/OpenClaw.Tests/SetupCommandTests.cs (1)

632-683: 💤 Low value

Consider using Path.Join for consistency with recent fixes.

The test correctly validates Aperture setup with tailnet-identity auth mode. However, lines 638 and 675 use Path.Combine, while earlier in this file (lines 30, 72) the code was updated to use Path.Join to avoid the "silent argument drop" behavior. For consistency and to prevent the same CodeQL warning, consider using Path.Join in this test as well.

Suggested consistency fix
-            var configPath = Path.Combine(root, "config", "openclaw.settings.json");
+            var configPath = Path.Join(root, "config", "openclaw.settings.json");

And at line 675:

-            var envExample = await File.ReadAllTextAsync(Path.Combine(root, "config", "openclaw.settings.env.example"));
+            var envExample = await File.ReadAllTextAsync(Path.Join(root, "config", "openclaw.settings.env.example"));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OpenClaw.Tests/SetupCommandTests.cs` around lines 632 - 683, The test
RunAsync_SetupProviderAperture_WritesTailnetIdentityProfile uses Path.Combine in
two places (when creating configPath and when reading the env example file)
which should be replaced with Path.Join to match the file's other fixes and
avoid silent-argument-drop warnings; update the configPath assignment and the
File.ReadAllTextAsync call that currently use Path.Combine(root, "config",
"openclaw.settings.json") and Path.Combine(root, "config",
"openclaw.settings.env.example") to use Path.Join(root, "config",
"openclaw.settings.json") and Path.Join(root, "config",
"openclaw.settings.env.example") respectively.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/OpenClaw.Tests/SetupCommandTests.cs`:
- Around line 632-683: The test
RunAsync_SetupProviderAperture_WritesTailnetIdentityProfile uses Path.Combine in
two places (when creating configPath and when reading the env example file)
which should be replaced with Path.Join to match the file's other fixes and
avoid silent-argument-drop warnings; update the configPath assignment and the
File.ReadAllTextAsync call that currently use Path.Combine(root, "config",
"openclaw.settings.json") and Path.Combine(root, "config",
"openclaw.settings.env.example") to use Path.Join(root, "config",
"openclaw.settings.json") and Path.Join(root, "config",
"openclaw.settings.env.example") respectively.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2948af21-99c0-4f88-bb41-efe743676918

📥 Commits

Reviewing files that changed from the base of the PR and between 81ba141 and 58d2757.

📒 Files selected for processing (7)
  • src/OpenClaw.Cli/SetupCommand.cs
  • src/OpenClaw.Core/Validation/ConfigValidator.cs
  • src/OpenClaw.Core/Validation/ProviderSmokeProbe.cs
  • src/OpenClaw.Gateway/Extensions/LlmClientFactory.cs
  • src/OpenClaw.Tests/ConfigValidatorTests.cs
  • src/OpenClaw.Tests/LlmClientFactoryTests.cs
  • src/OpenClaw.Tests/SetupCommandTests.cs

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
src/OpenClaw.Tests/SetupCommandTests.cs (1)

638-638: ⚡ Quick win

Use Path.Join for consistency with the pattern being applied in this PR.

Lines 30, 72, 402, and 675 in this file were changed from Path.Combine to Path.Join to address static analysis warnings. Line 638 follows the same pattern (constructing configPath for file I/O) but still uses Path.Combine.

♻️ Proposed fix
-            var configPath = Path.Combine(root, "config", "openclaw.settings.json");
+            var configPath = Path.Join(root, "config", "openclaw.settings.json");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OpenClaw.Tests/SetupCommandTests.cs` at line 638, Replace the use of
Path.Combine with Path.Join for constructing configPath in SetupCommandTests:
change the assignment to use Path.Join(root, "config", "openclaw.settings.json")
where the variable configPath is declared in the SetupCommandTests class/method
so it matches the other replacements (lines using Path.Join at 30, 72, 402,
675).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/OpenClaw.Tests/SetupCommandTests.cs`:
- Line 638: Replace the use of Path.Combine with Path.Join for constructing
configPath in SetupCommandTests: change the assignment to use Path.Join(root,
"config", "openclaw.settings.json") where the variable configPath is declared in
the SetupCommandTests class/method so it matches the other replacements (lines
using Path.Join at 30, 72, 402, 675).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1a966c74-ff98-4cb9-81ad-19210b4ec459

📥 Commits

Reviewing files that changed from the base of the PR and between 58d2757 and dee1a3d.

📒 Files selected for processing (1)
  • src/OpenClaw.Tests/SetupCommandTests.cs

@Telli Telli force-pushed the codex/tailscale-aperture-integration branch from dee1a3d to 288e370 Compare May 20, 2026 09:47
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.

2 participants