Skip to content

Make login default to production, not stored env#205

Merged
alexkroman merged 1 commit into
mainfrom
claude/intelligent-bardeen-ezmdxa
Jun 17, 2026
Merged

Make login default to production, not stored env#205
alexkroman merged 1 commit into
mainfrom
claude/intelligent-bardeen-ezmdxa

Conversation

@alexkroman

Copy link
Copy Markdown
Collaborator

Summary

Change the assembly login command to always default to production, rather than inheriting the profile's previously-stored environment. This prevents a bare re-login from silently re-targeting a sandbox environment the profile happened to be bound to.

Changes

  • Login command behavior: Modified aai_cli/commands/login.py to explicitly resolve and set the active environment to production (or the explicitly-provided --env/--sandbox/AAI_ENV) before running the OAuth flow, rather than reading the profile's stored environment binding.

    • The browser OAuth + AMS flow reads environments.active(), so the process global is now set here to ensure the flow runs against the correct environment.
    • An explicit --env, --sandbox, or AAI_ENV still takes precedence and becomes the environment the profile is bound to.
  • Documentation: Updated aai_cli/skills/aai-cli/references/account.md to clarify that login defaults to production and explain the rationale (preventing silent re-targeting of sandboxes on re-login).

  • Test coverage: Added two new tests in tests/test_login.py:

    • test_login_defaults_to_production_ignoring_stored_sandbox_env: Verifies that a bare assembly login defaults to production even when the profile was previously bound to a sandbox.
    • test_login_explicit_sandbox_still_overrides_production_default: Verifies that an explicit --sandbox flag still overrides the production default.

Implementation Details

The key change is in the login command's body() function: instead of reading environments.active().name directly (which would inherit the profile's stored env), we now:

  1. Call environments.resolve(state.env, None) to get the environment object (respecting explicit flags/env vars, defaulting to None)
  2. Call environments.set_active(env_obj) to set the process global
  3. Read the name from the resolved environment object

This ensures the OAuth flow sees the correct active environment and the profile is bound to the intended target.

https://claude.ai/code/session_01JYvBVVNW1FdpLDxTdmUya3

Comment thread aai_cli/commands/login.py
# the profile to. The browser OAuth + AMS flow reads environments.active(), so
# re-set the process global here, not just the stored/reported name.
env_obj = environments.resolve(state.env, None)
environments.set_active(env_obj)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

environments.set_active(env_obj) mutates process-global active environment, risking cross-request/session state leakage; avoid or gate process-global mutation (e.g., use request-scoped context) or clearly document/serialize access.

Details

✨ AI Reasoning
​The new code resolves an environment and then calls environments.set_active(env_obj), which mutates a process-global active environment. Module-level or process-global state mutations in server/CLI contexts can cause state to persist across invocations, leaking user-specific context or causing race conditions. The previous behavior only read environments.active(), so this change worsens the global-state mutation risk by writing into it. This is introduced in the current diff where the set_active call was added.

🔧 How do I fix it?
Avoid storing request-specific data in module-level variables. Use request-scoped variables or explicitly mark shared caches as intentional.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@AikidoSec ignore: This is the established, intentional pattern in this codebase, not a leak. The active environment is a process-global set once per CLI invocation (main.py calls environments.set_active(...) at startup; see aai_cli/core/environments.py and the architecture note in AGENTS.md). assembly runs as a single-shot process per command — there is no shared server request scope to leak across. The test suite already guards against cross-test bleed via the autouse reset_active_environment fixture in tests/conftest.py. The browser OAuth + AMS flow reads environments.active(), so login must re-set it to the resolved environment for the flow to target the right hosts; a request-scoped rewrite would be a repo-wide refactor against the documented design.


Generated by Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Based on your feedback, we ignored this issue because of the following reason:

This is the established, intentional pattern in this codebase, not a leak. The active environment is a process-global set once per CLI invocation (main.py calls environments.set_active(...) at startup; see aai_cli/core/environments.py and the architecture note in AGENTS.md). assembly runs as a single-shot process per command — there is no shared server request scope to leak across. The test suite already guards against cross-test bleed via the autouse reset_active_environment fixture in tests/conftest.py. The browser OAuth + AMS flow reads environments.active(), so login must re-set it to the resolved environment for the flow to target the right hosts; a request-scoped rewrite would be a repo-wide refactor against the documented design.


Generated by Claude Code

…d env

A bare `assembly login` resolved its target environment via
`environments.active()`, which inherits the profile's previously-stored env.
So re-signing-in on a profile that was once bound to the sandbox silently
re-targeted the sandbox. Resolve login's environment ignoring the profile's
stored env so it defaults to production; an explicit --env/--sandbox (or
AAI_ENV) still selects the environment and becomes the one the profile binds
to. Re-set the active environment too, since the browser OAuth + AMS flow
reads environments.active().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYvBVVNW1FdpLDxTdmUya3
@alexkroman alexkroman force-pushed the claude/intelligent-bardeen-ezmdxa branch from 7037f59 to 2a3ed01 Compare June 17, 2026 00:36
@alexkroman alexkroman added this pull request to the merge queue Jun 17, 2026
Merged via the queue into main with commit 4b4644c Jun 17, 2026
19 checks passed
@alexkroman alexkroman deleted the claude/intelligent-bardeen-ezmdxa branch June 17, 2026 00:53
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