Skip to content

fix(cloud-agent-next): refresh generic git credentials#3919

Open
eshurakov wants to merge 1 commit into
mainfrom
colorful-jackfruit
Open

fix(cloud-agent-next): refresh generic git credentials#3919
eshurakov wants to merge 1 commit into
mainfrom
colorful-jackfruit

Conversation

@eshurakov

Copy link
Copy Markdown
Contributor

Summary

Why

Generic Git repositories such as App Builder use short-lived credentials that can rotate between follow-up messages. sendMessageV2 accepted the refreshed gitToken but discarded it, so the Durable Object and workspace could keep using an expired credential and fail later clones or Git operations. Refreshing the credential at durable message admission gives queued work a consistent token without changing the server-managed GitHub and GitLab credential paths.

What was done

  • Adapt non-empty legacy V2 gitToken values into a transient generic repository credential update while continuing to ignore caller-provided GitHub credentials.
  • Apply generic Git credential changes after message validation and capacity checks but before queued work becomes visible, with durable message ordering that prevents stale retries from restoring older credentials.
  • Keep credentials out of immutable message intents, pending rows, events, callbacks, and logs; temporary non-secret admission markers are removed after queue persistence.
  • Use the refreshed credential for cold clones and rewrite origin for warm direct and wrapper-bootstrap workspaces.
  • Shell-quote direct workspace paths and authenticated remote URLs before invoking Git.

High-level architecture

sequenceDiagram
  participant Client as App Builder / legacy client
  participant API as sendMessageV2
  participant DO as CloudAgentSession DO
  participant Store as Durable Object storage
  participant Runtime as Workspace runtime

  Client->>API: Follow-up message + fresh gitToken
  API->>DO: Submitted turn + transient credential update
  DO->>DO: Validate turn, model, and queue capacity
  alt Generic Git repository
    DO->>Store: Update repository metadata, message pointer, and temporary marker
  end
  DO->>Store: Persist message intent and admission state without credential
  DO->>Store: Remove temporary credential marker
  DO-->>API: Admission acknowledgement
  API-->>Client: Queued or sent result

  rect rgb(245, 245, 245)
    Note over DO,Runtime: When queued work prepares its workspace
    DO->>Runtime: Prepare execution from current session metadata
    alt Cold workspace
      Runtime->>Runtime: Clone with current credential
    else Warm workspace
      Runtime->>Runtime: Refresh origin with current credential
    end
  end
Loading

Architecture decision

Decision: Treat generic Git credential rotation as a transient, validated session-metadata mutation at durable message admission rather than as part of the immutable queued message intent.

Context: Cloud Agent can resolve managed GitHub and GitLab credentials through the shared token service, but it cannot independently refresh credentials for arbitrary Git providers. Admission retries and existing drain alarms also require the metadata update to be ordered with queue visibility.

Rationale: The Durable Object already owns session metadata and queue coordination, so it can apply the latest generic credential before work is observable while keeping the secret out of message persistence and delivery contracts. A durable current-message pointer plus temporary non-secret markers preserves ordering across partial failures and retries.

Alternatives considered:

  • Continue ignoring caller credentials. This preserves a server-only policy but cannot support arbitrary providers and leaves short-lived generic credentials stale.
  • Persist the token in the queued message intent. This simplifies handoff but would spread a secret into immutable pending-message, replay, event, or callback surfaces.
  • Add an App Builder-specific refresh path. This would address one caller while duplicating provider policy outside the durable session boundary and leaving other generic Git clients exposed.

Consequences: Generic Git follow-ups can safely rotate credentials for both cold and warm workspaces, while GitHub and managed GitLab remain server-resolved. The trade-off is additional Durable Object admission bookkeeping and an intentionally narrow compatibility contract where only non-empty gitToken values affect generic Git repositories.

Verification

  • Manual verification was not performed; this path requires a live generic Git repository with rotating credentials, and no manual environment was exercised.

Visual Changes

N/A

Reviewer Notes

  • Focus review on credential ordering when metadata persistence succeeds but queue persistence is retried, especially stale message replays.
  • Generic Git is intentionally the only caller-managed path; GitHub and managed GitLab credential behavior is unchanged.
  • No UI or database migration is included.

@kilo-code-bot

kilo-code-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of commit 432852a (squashed replacement of 3523c6a) confirms all previously-verified properties hold and the new additions are correct.

Incremental changes reviewed
  • refreshRemote condition extended (session-service.ts:1595-1597, buildWrapperRepoSource): now triggers for git.type === 'git' as well as gitlabTokenManaged, so warm workspaces for generic git repos get origin rewritten with the freshly-rotated credential. The refreshGitRemoteToken warm path uses the identical condition — the two are in sync.
  • Wrapper bootstrap warm path (session-bootstrap.test.ts): new test confirms prepareWrapperBootstrapWorkspace calls remote set-url with the current credential when refreshRemote: true and .git exists.
  • Test renames: test names updated to reflect that the gitToken field is no longer merely "deprecated/ignored" but actively rotates generic credentials.
  • New integration tests: ordering guard, GitHub/GitLab credential isolation, mismatched-replay rejection, and warm-path refresh are all covered.

All previously-verified properties remain intact: shell injection fix, credential containment, marker-based idempotency, and atomic storage writes.

Files Reviewed (10 files)
  • services/cloud-agent-next/src/execution/types.ts
  • services/cloud-agent-next/src/persistence/CloudAgentSession.ts
  • services/cloud-agent-next/src/router/handlers/session-execution.ts
  • services/cloud-agent-next/src/router/schemas.ts
  • services/cloud-agent-next/src/session-service.ts
  • services/cloud-agent-next/src/session/queue-message.ts
  • services/cloud-agent-next/src/session/session-message-queue.ts
  • services/cloud-agent-next/src/workspace.ts
  • services/cloud-agent-next/src/kilo/utils.ts
  • services/cloud-agent-next/wrapper/src/session-bootstrap.test.ts

Reviewed by claude-4.6-sonnet-20260217 · 805,380 tokens

Review guidance: REVIEW.md from base branch main

@eshurakov eshurakov force-pushed the colorful-jackfruit branch from 3523c6a to 432852a Compare June 10, 2026 14:10
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