Skip to content

Structural auth guardrails so agents never trigger sign-in silently - #173

Open
TomProkop wants to merge 1 commit into
masterfrom
feat/agent-auth-guardrails
Open

Structural auth guardrails so agents never trigger sign-in silently#173
TomProkop wants to merge 1 commit into
masterfrom
feat/agent-auth-guardrails

Conversation

@TomProkop

Copy link
Copy Markdown
Member

Problem

AI coding agents driving txc CLI/MCP repeatedly get confused about Profile/Connection/Credential when a token expires or no credential exists, invent profiles/connections speculatively, or end up stuck on an unattended device-code prompt no one is watching, instead of stopping and asking the user to sign in interactively.

Approach

Grounded in real usage from the alm-lab checkpoint scripts, which show the golden pattern already used by humans/scripts: sign-in is always a deliberate action (--device-code passed explicitly, never relying on auto-fallback), and existing profiles/connections are always listed before creating new ones.

No agent-harness environment-variable detection is used anywhere — every fix is structural (change what the CLI does) or message/help-driven (steer whoever/whatever is calling), so it applies uniformly to humans, known agents, and unknown future agents alike.

Changes

Tier 1 — structural, safety-critical:

  • AuthLoginCliCommand: removed the silent browser-unavailable → device-code auto-fallback. Fails fast with a clear message instead of ever starting an unattended device-code flow.
  • DataverseAccessTokenService.AcquirePublicClientSilentAsync: removed the automatic interactive/device-code re-authentication attempted on MsalUiRequiredException during token refresh — the literal "token expires mid-session" case reported. Now always throws immediately with a manual-sign-in message.
  • HeadlessAuthRequiredException.BuildMessage: leads with the manual-human-sign-in rule before headless remedy details.
  • ConfigurationResolver / ProfileValidateCliCommand: extended "no profile" error messages with a list-before-create nudge (config profile list / config connection list).
  • Baked the Credential/Connection/Profile model, list-before-create, and manual-sign-in rules directly into --help text for AuthCliCommand, ProfileCliCommand, ConnectionCliCommand, ProfileCreateCliCommand.
  • CliSubprocessRunner: extracted BuildStartInfo so the MCP-forced TXC_NON_INTERACTIVE=1 contract has direct unit test coverage (new CliSubprocessRunnerTests) instead of relying only on indirect integration coverage.

Tier 2 — optional documentation reinforcement:

  • docs/profiles-and-authentication.md: added a "Sign-in is manual" callout for agent-adjacent workflows.
  • MCP troubleshooting-patterns.md skill: added auth-failure anti-patterns (don't self-sign-in, don't create profiles speculatively).
  • CopilotInstructionsManager: added a short Authentication section to the generated copilot-instructions.md.

Also verified (no change needed): the --url one-liner bootstrap path already calls IHeadlessDetector.EnsureKindAllowed(CredentialKind.InteractiveBrowser) before attempting interactive sign-in and is only reachable via an explicit human-supplied --url flag — consistent with the "manual, deliberate" principle.

Testing

  • dotnet build TALXIS.CLI.sln — 0 errors.
  • dotnet test — 701/701 passing (698 pre-existing + 3 new CliSubprocessRunnerTests).

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Fixes the recurring failure mode where an AI coding agent driving txc
CLI/MCP gets confused about Profile/Connection/Credential, invents new
profiles/connections speculatively, or ends up stuck on an unattended
device-code prompt when a token expires.

Grounded in real usage from the alm-lab checkpoint scripts, which show
the golden pattern: sign-in is always a deliberate human action
(--device-code passed explicitly, never relying on auto-fallback), and
existing profiles/connections are always listed before creating new
ones. No agent-harness environment-variable detection is used anywhere
— the fixes are purely structural and apply uniformly to any caller.

Tier 1 (structural, safety-critical):
- AuthLoginCliCommand: remove the silent browser-unavailable ->
  device-code auto-fallback. Now fails fast with a clear message
  instead of ever starting an unattended device-code flow.
- DataverseAccessTokenService.AcquirePublicClientSilentAsync: remove
  the automatic interactive/device-code re-authentication attempted on
  MsalUiRequiredException during token refresh (the exact "token
  expires mid-session" case reported) — now always throws immediately
  with a manual-sign-in message.
- HeadlessAuthRequiredException.BuildMessage: lead with the
  manual-human-sign-in rule before headless remedy details.
- ConfigurationResolver / ProfileValidateCliCommand: extend "no
  profile" error messages with a list-before-create nudge (config
  profile list / config connection list).
- Bake the Credential/Connection/Profile model, list-before-create, and
  manual-sign-in rules directly into --help text for AuthCliCommand,
  ProfileCliCommand, ConnectionCliCommand, ProfileCreateCliCommand.
- CliSubprocessRunner: extract BuildStartInfo so the MCP-forced
  TXC_NON_INTERACTIVE=1 contract has direct unit test coverage
  (CliSubprocessRunnerTests) instead of relying only on indirect
  integration coverage.

Tier 2 (optional documentation reinforcement):
- docs/profiles-and-authentication.md: add a "Sign-in is manual"
  callout for agent-adjacent workflows.
- MCP troubleshooting-patterns skill: add auth-failure anti-patterns
  (don't self-sign-in, don't create profiles speculatively).
- CopilotInstructionsManager: add a short Authentication section to
  the generated copilot-instructions.md.

Tests: 701/701 passing (698 pre-existing + 3 new CliSubprocessRunner
regression tests). Full solution builds with 0 errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Case-Validation

Development

Successfully merging this pull request may close these issues.

2 participants