-
Notifications
You must be signed in to change notification settings - Fork 1
fix: reload runtime factory after login #95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| from __future__ import annotations | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import asyncio | ||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||
|
|
@@ -160,12 +161,19 @@ async def _config(): | |||||||||||||||||||||||||
| from uipath.dev.server.ws.handler import router as ws_router | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| if auth_enabled: | ||||||||||||||||||||||||||
| from uipath.dev.server.auth import restore_session | ||||||||||||||||||||||||||
| from uipath.dev.server.auth import get_auth_state, restore_session | ||||||||||||||||||||||||||
| from uipath.dev.server.routes.auth import router as auth_router | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| app.include_router(auth_router, prefix="/api") | ||||||||||||||||||||||||||
| restore_session() | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Reload the runtime factory when authentication completes so the | ||||||||||||||||||||||||||
| # newly-written credentials are picked up by subsequent runs. | ||||||||||||||||||||||||||
| def _on_authenticated() -> None: | ||||||||||||||||||||||||||
| asyncio.ensure_future(server.reload_factory()) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+173
to
+174
|
||||||||||||||||||||||||||
| asyncio.ensure_future(server.reload_factory()) | |
| task = asyncio.create_task(server.reload_factory()) | |
| def _log_reload_result(t: asyncio.Task) -> None: | |
| try: | |
| t.result() | |
| except Exception: | |
| logger.exception( | |
| "Error while reloading runtime factory after authentication" | |
| ) | |
| task.add_done_callback(_log_reload_result) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -109,6 +109,8 @@ class AuthState: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _last_tenant: str | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _last_org: dict[str, str] = field(default_factory=dict) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _last_environment: str | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Callback invoked after successful authentication | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _on_authenticated: Any | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+112
to
+113
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # internal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _code_verifier: str | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _state: str | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -990,6 +992,25 @@ def select_tenant(tenant_name: str) -> dict[str, Any]: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return {"status": "authenticated", "uipath_url": auth.uipath_url} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _update_env_file(env_contents: dict[str, str]) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Merge *env_contents* into the CWD ``.env`` file. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| New keys take priority; existing keys not in *env_contents* are preserved. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mirrors ``uipath._utils._auth.update_env_file``. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env_path = Path.cwd() / ".env" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if env_path.exists(): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(env_path) as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for line in f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if "=" in line: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key, value = line.strip().split("=", 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if key not in env_contents: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env_contents[key] = value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lines = [f"{key}={value}\n" for key, value in env_contents.items()] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(env_path, "w") as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| f.writelines(lines) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1002
to
+1013
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if env_path.exists(): | |
| with open(env_path) as f: | |
| for line in f: | |
| if "=" in line: | |
| key, value = line.strip().split("=", 1) | |
| if key not in env_contents: | |
| env_contents[key] = value | |
| lines = [f"{key}={value}\n" for key, value in env_contents.items()] | |
| with open(env_path, "w") as f: | |
| f.writelines(lines) | |
| # Read existing .env lines (if any) so we can update in place | |
| existing_lines: list[str] = [] | |
| if env_path.exists(): | |
| with open(env_path, encoding="utf-8") as f: | |
| existing_lines = f.readlines() | |
| # Work on a copy so we can track which keys still need to be appended | |
| pending: dict[str, str] = dict(env_contents) | |
| if existing_lines: | |
| new_lines: list[str] = [] | |
| for line in existing_lines: | |
| stripped = line.lstrip() | |
| # Preserve comments and non-assignment lines verbatim | |
| if stripped.startswith("#") or "=" not in stripped: | |
| new_lines.append(line) | |
| continue | |
| key_part, _sep, _rest = stripped.partition("=") | |
| key = key_part.strip() | |
| # If parsing yields an empty or commented key, keep the line as-is | |
| if not key or key.startswith("#"): | |
| new_lines.append(line) | |
| continue | |
| # Update existing keys with new values when provided | |
| if key in pending: | |
| new_lines.append(f"{key}={pending.pop(key)}\n") | |
| else: | |
| new_lines.append(line) | |
| # Append any remaining new keys at the end | |
| if pending: | |
| if new_lines and not new_lines[-1].endswith("\n"): | |
| new_lines[-1] = new_lines[-1] + "\n" | |
| for key, value in pending.items(): | |
| new_lines.append(f"{key}={value}\n") | |
| lines_to_write = new_lines | |
| else: | |
| # No existing .env: just write the provided contents | |
| lines_to_write = [f"{key}={value}\n" for key, value in pending.items()] | |
| with open(env_path, "w", encoding="utf-8") as f: | |
| f.writelines(lines_to_write) |
Copilot
AI
Mar 1, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling auth._on_authenticated() directly means any exception in the callback (or a failure to schedule its async work) will bubble out of _finalize_tenant and fail the login/tenant selection request. Consider wrapping the callback invocation in a try/except with logging, and if the callback schedules async work, make sure task exceptions are captured/logged as well.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
server.reload_factory()can dispose/recreate the runtime while runs are active, but this callback path does not apply the same “no active runs” guard used by the/reloadendpoint. Consider reusing the same active-run check here (or deferring reload until idle) to avoid disrupting in-flight runs if a user authenticates mid-execution.