Skip to content

fix(runner,rbac,cli,routes): credential auth reliability and SSE improvements#1231

Merged
markturansky merged 4 commits intoalphafrom
fix/credential-auth-reliability
Apr 7, 2026
Merged

fix(runner,rbac,cli,routes): credential auth reliability and SSE improvements#1231
markturansky merged 4 commits intoalphafrom
fix/credential-auth-reliability

Conversation

@markturansky
Copy link
Copy Markdown
Contributor

@markturansky markturansky commented Apr 7, 2026

Summary

  • runner: On 401 from credential fetch, refresh the CP token and retry once instead of aborting the turn — fixes intermittent turn failures when the cached BOT_TOKEN expires mid-session
  • rbac: Fix pathToAction() so GET /credentials/{id}/token resolves to action token (matching credential:token-reader role) rather than read — was causing systematic 401s for runner SAs
  • cli: Improve acpctl session send -f output with [thinking] reasoning blocks, [ToolName] → result tool call annotations, and proper streaming newline handling
  • routes: Add haproxy.router.openshift.io/timeout: 10m to all ambient-api-server OpenShift Routes to prevent 504 Gateway Timeouts on long-running SSE streams

Test plan

  • Send a message via acpctl session send -f and confirm [thinking] and tool call output appears
  • Verify credential fetches succeed on long-running sessions (no intermittent 401 turn aborts)
  • Confirm GET /credentials/{id}/token returns 200 for runner SA (RBAC fix)
  • Verify SSE streams survive beyond 30s without 504 after route annotation is applied

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Automatic token refresh with a single retry on authentication failures
    • Richer CLI streaming output with reasoning blocks, tool-call annotations, and improved text formatting
    • Optional support for alternate text-block types when collecting observability output
  • Bug Fixes

    • Authorization now recognizes special path-based operations for correct permission checks
  • Configuration

    • Added 10-minute timeout to API server routes

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 7, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4215e453-0cbe-420d-b6e6-894f2a86ebf2

📥 Commits

Reviewing files that changed from the base of the PR and between f998e54 and 029062d.

📒 Files selected for processing (1)
  • components/manifests/overlays/mpp-openshift/ambient-api-server-route.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/manifests/overlays/mpp-openshift/ambient-api-server-route.yaml

📝 Walkthrough

Walkthrough

Path-aware RBAC action derivation added; CLI streaming output enriched with reasoning and tool-call annotations; bot-token refresh-and-retry flow plus refresh_bot_token() implemented; HAProxy 10m timeout annotations added to OpenShift Route manifests.

Changes

Cohort / File(s) Summary
RBAC Authorization
components/ambient-api-server/pkg/rbac/middleware.go
Authorization now derives action with pathToAction(method, path) to detect v1 operations (token, start, stop, ignite, ignition) and map them to specific actions, falling back to method-based mapping.
CLI Streaming Output
components/ambient-cli/cmd/acpctl/session/send.go
Non-JSON streaming output expanded to handle multiple event types: buffers reasoning and emits [thinking], tracks inText state, emits tool-call markers and one-line previews; event struct extended with toolCallName and content.
Bot Token Refresh & Auth Retry
components/runners/ambient-runner/ambient_runner/platform/auth.py, components/runners/ambient-runner/ambient_runner/platform/utils.py
Added refresh_bot_token(); _fetch_credential() now retries once with a refreshed BOT_TOKEN on 401/403 via a _retry_with_fresh_bot_token() path, and surfaces combined error context on failure.
OpenShift Route HAProxy Timeouts
components/manifests/overlays/local-dev/ambient-api-server-route.yaml, components/manifests/overlays/mpp-openshift/ambient-api-server-route.yaml, components/manifests/overlays/production/ambient-api-server-route.yaml
Added metadata.annotations.haproxy.router.openshift.io/timeout: 10m to ambient-api-server (and grpc where present) Route resources across overlays; no other route specs changed.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant FetchCredential as _fetch_credential()
    participant RefreshUtil as refresh_bot_token()
    participant CPService as CP Token Service

    Caller->>FetchCredential: Request credentials
    FetchCredential->>CPService: Call backend with BOT_TOKEN
    alt 200 OK
        CPService-->>FetchCredential: 200 + credentials
        FetchCredential-->>Caller: Return credentials
    else 401/403
        CPService-->>FetchCredential: 401/403
        FetchCredential->>RefreshUtil: Refresh BOT_TOKEN
        RefreshUtil->>CPService: Request new token (if CP env present)
        CPService-->>RefreshUtil: New token or error
        RefreshUtil-->>FetchCredential: Provide refreshed BOT_TOKEN
        FetchCredential->>CPService: Retry call with refreshed BOT_TOKEN
        alt 200 OK
            CPService-->>FetchCredential: 200 + credentials
            FetchCredential-->>Caller: Return credentials
        else error
            CPService-->>FetchCredential: Error
            FetchCredential-->>Caller: Raise PermissionError (includes context)
        end
    end
Loading
🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title follows Conventional Commits format (fix type with multiple scopes) and accurately summarizes the core changes: credential auth retry logic, RBAC path-based action routing, CLI streaming improvements, and OpenShift route timeouts.
Performance And Algorithmic Complexity ✅ Passed PR contains no algorithmic complexity regressions or performance anti-patterns. RBAC uses IN clauses, auth retry is bounded to 1 attempt, streaming buffers reset properly.
Security And Secret Handling ✅ Passed Security analysis finds no violations across all blocking criteria: token handling avoids plaintext logging, authorization checks enforced at middleware level, SQL queries use parameterized statements, sensitive data never logged, no new Kubernetes Secrets introduced, credential refresh maintains proper user context.
Kubernetes Resource Safety ✅ Passed PR modifies only Route manifests with timeout annotations and application code; no child resources, container specs, RBAC policies, or security contexts created or modified.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/credential-auth-reliability
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/credential-auth-reliability

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

…ovements

- runner: retry credential fetch with fresh CP token on 401 instead of
  aborting the turn; adds refresh_bot_token() to utils.py and wires it
  into _fetch_credential() for both the direct BOT_TOKEN and caller-token
  fallback paths
- rbac: fix pathToAction() so GET /credentials/{id}/token resolves to
  action "token" (matching credential:token-reader role) instead of "read"
- cli: improve acpctl session send -f output with reasoning accumulation
  ([thinking] blocks), tool call annotations ([ToolName] → result), and
  proper newline handling for streamed text
- routes: add haproxy.router.openshift.io/timeout: 10m to all
  ambient-api-server Routes (production, mpp-openshift, local-dev) to
  prevent 504s on long-running SSE streams

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@markturansky markturansky force-pushed the fix/credential-auth-reliability branch from fe9a7ca to bf6be85 Compare April 7, 2026 01:37
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/ambient-cli/cmd/acpctl/session/send.go`:
- Around line 127-137: The SSE reader uses bufio.NewScanner which defaults to a
64KiB token limit causing bufio.ErrTooLong when TOOL_CALL_RESULT events have
large evt.Content; locate the bufio.NewScanner(...) instance (variable name
scanner) used in the session send flow and call scanner.Buffer(make([]byte,
1024*1024), 10*1024*1024) (or another appropriate larger max like 5–10MB)
immediately after creating the scanner to raise the token limit, and keep
existing evt.Content handling (the preview code around evt.Content) intact;
optionally ensure any bufio.ErrTooLong is handled/logged if you still want to
detect oversized tokens.

In `@components/manifests/overlays/mpp-openshift/ambient-api-server-route.yaml`:
- Around line 10-11: The grpc Route resource ambient-api-server-grpc is missing
the haproxy.router.openshift.io/timeout: 10m annotation applied to the other
Route; update the annotations block on the ambient-api-server-grpc Route (the
resource with name ambient-api-server-grpc and its annotations mapping) to
include haproxy.router.openshift.io/timeout: 10m so both routes receive the same
10m router timeout.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c3c0f4b2-2b50-43b9-8d08-edf1c0dd07fa

📥 Commits

Reviewing files that changed from the base of the PR and between bc58a6e and bf6be85.

📒 Files selected for processing (7)
  • components/ambient-api-server/pkg/rbac/middleware.go
  • components/ambient-cli/cmd/acpctl/session/send.go
  • components/manifests/overlays/local-dev/ambient-api-server-route.yaml
  • components/manifests/overlays/mpp-openshift/ambient-api-server-route.yaml
  • components/manifests/overlays/production/ambient-api-server-route.yaml
  • components/runners/ambient-runner/ambient_runner/platform/auth.py
  • components/runners/ambient-runner/ambient_runner/platform/utils.py

Comment on lines +127 to +137
if evt.Content != "" {
var content string
if err := json.Unmarshal([]byte(evt.Content), &content); err != nil {
content = evt.Content
}
lines := strings.SplitN(strings.TrimSpace(content), "\n", 4)
preview := strings.Join(lines, " | ")
if len(lines) >= 4 {
preview += " ..."
}
fmt.Fprintf(out, "→ %s\n", preview)
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.

⚠️ Potential issue | 🟠 Major

Raise the scanner limit before previewing tool results.

bufio.Scanner still caps each SSE line at 64 KiB. Now that TOOL_CALL_RESULT consumes full evt.Content, one large result can terminate acpctl session send -f with bufio.ErrTooLong.

Patch
 	out := cmd.OutOrStdout()
 	scanner := bufio.NewScanner(stream)
+	scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
 	var reasoningBuf strings.Builder
 	var inText bool

Expected: this file shows no scanner.Buffer call today; if emitters stream full tool-result payloads, the current scanner limit is enough to abort the stream.

#!/bin/bash
set -euo pipefail

sed -n '78,86p' components/ambient-cli/cmd/acpctl/session/send.go
printf '\n'
rg -n -C2 'scanner\.Buffer|bufio\.NewScanner' components/ambient-cli/cmd/acpctl/session/send.go
printf '\n'
rg -n -C2 'TOOL_CALL_RESULT|toolCallName|content' .
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/ambient-cli/cmd/acpctl/session/send.go` around lines 127 - 137,
The SSE reader uses bufio.NewScanner which defaults to a 64KiB token limit
causing bufio.ErrTooLong when TOOL_CALL_RESULT events have large evt.Content;
locate the bufio.NewScanner(...) instance (variable name scanner) used in the
session send flow and call scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)
(or another appropriate larger max like 5–10MB) immediately after creating the
scanner to raise the token limit, and keep existing evt.Content handling (the
preview code around evt.Content) intact; optionally ensure any bufio.ErrTooLong
is handled/logged if you still want to detect oversized tokens.

…rror message

The _retry_with_fresh_bot_token helper was hardcoding HTTP 401 in the
PermissionError message regardless of the actual response code. This broke
test_raises_permission_error_on_403_without_caller_token which expects
"authentication failed with HTTP 403".

Now the original status code is passed through and the retry error message
reflects the actual HTTP code from both the initial and retry attempts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/runners/ambient-runner/ambient_runner/platform/auth.py`:
- Around line 204-214: The _retry_with_fresh_bot_token path can trigger
concurrent refreshes when populate_runtime_credentials fans out multiple
credential fetches; fix this by coalescing refreshes for refresh_bot_token so
only one in-flight refresh runs at a time and other callers await its result
(e.g., add a module-level in-progress future or an asyncio.Lock + cached result
inside the refresh logic used by _retry_with_fresh_bot_token and the shared
bot-token cache update in ambient_runner/platform/utils.py), ensure refresh
errors propagate to waiting callers and update the cache only once with the
fresh token.
- Around line 215-221: Ensure the URL is explicitly an http/https host and not a
hostless scheme: after parsing the URL (the parsed variable) and before creating
retry_req or adding headers (where _urllib_request.Request and retry_req are
used and Authorization/X-Runner-Current-User are added), enforce that
parsed.scheme is either "http" or "https" and that parsed.hostname is present;
if not, reject the request (raise/return an error) rather than proceeding or
relying solely on the hostname allowlist check.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f185722d-a2c9-4671-9a46-78f4d3f29fca

📥 Commits

Reviewing files that changed from the base of the PR and between bf6be85 and 8af45d4.

📒 Files selected for processing (1)
  • components/runners/ambient-runner/ambient_runner/platform/auth.py

Comment on lines +204 to +214
def _retry_with_fresh_bot_token(original_code: int):
logger.info(
f"{credential_type} got {original_code} with cached BOT_TOKEN — refreshing from CP endpoint and retrying"
)
try:
fresh_bot = refresh_bot_token()
except Exception as refresh_err:
logger.warning(f"{credential_type} CP token refresh failed: {refresh_err}")
raise PermissionError(
f"{credential_type} authentication failed with HTTP {original_code}"
) from refresh_err
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.

⚠️ Potential issue | 🟠 Major

Coalesce CP token refreshes across concurrent failures.

Line 209 can run once per failing provider fetch. populate_runtime_credentials() fans out four credential fetches concurrently (Lines 349-356), while ambient_runner/platform/utils.py:31-92 updates the shared bot-token cache without locking. One stale BOT_TOKEN can therefore trigger a refresh stampede and race the cache, so the intermittent auth failures this PR is fixing can still reproduce under load.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/runners/ambient-runner/ambient_runner/platform/auth.py` around
lines 204 - 214, The _retry_with_fresh_bot_token path can trigger concurrent
refreshes when populate_runtime_credentials fans out multiple credential
fetches; fix this by coalescing refreshes for refresh_bot_token so only one
in-flight refresh runs at a time and other callers await its result (e.g., add a
module-level in-progress future or an asyncio.Lock + cached result inside the
refresh logic used by _retry_with_fresh_bot_token and the shared bot-token cache
update in ambient_runner/platform/utils.py), ensure refresh errors propagate to
waiting callers and update the cache only once with the fresh token.

Comment on lines +215 to +221
retry_req = _urllib_request.Request(url, method="GET")
if fresh_bot:
retry_req.add_header("Authorization", f"Bearer {fresh_bot}")
if context.current_user_id:
retry_req.add_header("X-Runner-Current-User", context.current_user_id)
try:
with _urllib_request.urlopen(retry_req, timeout=10) as resp:
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Guard and retry callsites:\n'
sed -n '121,131p;215,221p' components/runners/ambient-runner/ambient_runner/platform/auth.py

printf '\nurlparse() behavior for representative BACKEND_API_URL values:\n'
python - <<'PY'
from urllib.parse import urlparse

samples = [
    "https://ambient-api-server.svc.cluster.local",
    "http://localhost:8080",
    "file:///tmp",
    "data:text/plain,hello",
]

for value in samples:
    p = urlparse(value)
    allowed = bool(p.hostname) and (
        p.hostname.endswith(".svc.cluster.local")
        or p.hostname.endswith(".svc")
        or p.hostname in {"localhost", "127.0.0.1"}
    )
    print(
        f"{value!r} -> scheme={p.scheme!r}, hostname={p.hostname!r}, "
        f"current_guard_rejects={bool(p.hostname and not allowed)}"
    )
PY

Repository: ambient-code/platform

Length of output: 1365


Guard hostless and non-HTTP(S) schemes in addition to hostname allowlist.

The current guard if parsed.hostname and not (allowlisted) fails for file:///tmp and data:text/... URIs—both return hostname=None and thus skip the rejection check. These bypass the cluster-only boundary and expose credentials via unintended schemes. Add checks for explicit scheme allowlist (http, https only) and reject any URL missing parsed.hostname.

🧰 Tools
🪛 Ruff (0.15.9)

[error] 215-215: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


[error] 221-221: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/runners/ambient-runner/ambient_runner/platform/auth.py` around
lines 215 - 221, Ensure the URL is explicitly an http/https host and not a
hostless scheme: after parsing the URL (the parsed variable) and before creating
retry_req or adding headers (where _urllib_request.Request and retry_req are
used and Authorization/X-Runner-Current-User are added), enforce that
parsed.scheme is either "http" or "https" and that parsed.hostname is present;
if not, reject the request (raise/return an error) rather than proceeding or
relying solely on the hostname allowlist check.

…_turn import

- auth.py: don't retry with fresh CP token when caller-token BOT_TOKEN
  fallback fails; preserve that path's original error message
- observability.py: guard claude_agent_sdk import in end_turn with try/except
  so Langfuse generation.update() is still called when the SDK is not installed

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/runners/ambient-runner/ambient_runner/platform/auth.py`:
- Around line 185-187: The code currently retries with a fresh BOT_TOKEN only
when the initial request used BOT_TOKEN; if the initial request used
context.caller_token and the fallback BOT_TOKEN then returns 401/403 the code
raises immediately instead of calling the same retry path. Update the exception
handling in the block that falls back from context.caller_token to BOT_TOKEN so
that when the fallback response error code (e.code) is 401 or 403 it calls
_retry_with_fresh_bot_token(e.code) instead of re-raising; keep existing
behavior for other error codes. Ensure you reference the context.caller_token
flow, the BOT_TOKEN fallback branch, the exception object e (e.code), and the
_retry_with_fresh_bot_token helper when making the change.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 492e8eec-c18b-4f66-9c5e-ae8555f3a7eb

📥 Commits

Reviewing files that changed from the base of the PR and between 8af45d4 and f998e54.

📒 Files selected for processing (2)
  • components/runners/ambient-runner/ambient_runner/observability.py
  • components/runners/ambient-runner/ambient_runner/platform/auth.py

Comment on lines 185 to +187
if e.code in (401, 403):
logger.warning(
f"{credential_type} credential fetch failed with HTTP {e.code}: {e}"
)
raise PermissionError(
f"{credential_type} authentication failed with HTTP {e.code}"
) from e
# BOT_TOKEN may have expired — refresh from CP endpoint and retry once.
return _retry_with_fresh_bot_token(e.code)
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.

⚠️ Potential issue | 🟠 Major

Handle 401/403 from the caller-token BOT_TOKEN fallback too.

This retry only runs when the first request was sent with BOT_TOKEN. If the first request used context.caller_token, Lines 177-184 raise as soon as the fallback BOT_TOKEN gets 401/403, so the fresh-token retry never happens and long-running sessions can still fail on an expired cached bot token.

Patch idea
                 try:
                     with _urllib_request.urlopen(fallback_req, timeout=10) as resp:
                         return resp.read().decode("utf-8", errors="replace")
+                except _urllib_request.HTTPError as fallback_err:
+                    if fallback_err.code in (401, 403):
+                        logger.warning(
+                            f"{credential_type} BOT_TOKEN fallback got {fallback_err.code}; refreshing from CP endpoint and retrying"
+                        )
+                        return _retry_with_fresh_bot_token(fallback_err.code)
+                    logger.warning(
+                        f"{credential_type} BOT_TOKEN fallback also failed: {fallback_err}"
+                    )
+                    raise PermissionError(
+                        f"{credential_type} authentication failed with HTTP {fallback_err.code}"
+                    ) from fallback_err
                 except Exception as fallback_err:
                     logger.warning(
                         f"{credential_type} BOT_TOKEN fallback also failed: {fallback_err}"
                     )
                     raise PermissionError(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/runners/ambient-runner/ambient_runner/platform/auth.py` around
lines 185 - 187, The code currently retries with a fresh BOT_TOKEN only when the
initial request used BOT_TOKEN; if the initial request used context.caller_token
and the fallback BOT_TOKEN then returns 401/403 the code raises immediately
instead of calling the same retry path. Update the exception handling in the
block that falls back from context.caller_token to BOT_TOKEN so that when the
fallback response error code (e.code) is 401 or 403 it calls
_retry_with_fresh_bot_token(e.code) instead of re-raising; keep existing
behavior for other error codes. Ensure you reference the context.caller_token
flow, the BOT_TOKEN fallback branch, the exception object e (e.code), and the
_retry_with_fresh_bot_token helper when making the change.

…route

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@ambient-code ambient-code Bot added this to the Review Queue milestone Apr 7, 2026
@markturansky markturansky merged commit 8578733 into alpha Apr 7, 2026
46 checks passed
@markturansky markturansky deleted the fix/credential-auth-reliability branch April 7, 2026 15: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.

1 participant