devops-bot-sdk 1.6.75__tar.gz → 1.6.76__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/PKG-INFO +1 -1
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/PKG-INFO +1 -1
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/SOURCES.txt +1 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/__init__.py +2 -2
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/service.py +121 -6
- devops_bot_sdk-1.6.76/tests/test_windows_panel_task.py +135 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_windows_task_paths.py +10 -1
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/README.md +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/dependency_links.txt +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/entry_points.txt +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/requires.txt +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/top_level.txt +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/pyproject.toml +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/classifier.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/collectors/common.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/collectors/linux_auditd.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/collectors/macos_eslogger.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/collectors/windows_eventlog.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/models.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/os_setup.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/recorder.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/redact.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/settings.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/shipper.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/activity/spool.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agentd.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/activity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/builder.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/chat.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/connectors.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/engines/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/engines/claude_code.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/engines/http.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/engines/mcp.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/engines/n8n.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/engines/shell.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/integrations.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/inventory.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/library/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/manifest.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/prompt_studio.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/prompt_template.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/prompt_vars.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/run_log.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/schedules.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/secrets.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/ticket_run.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/usage.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/agents/varstore.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/browser_profile.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/cli.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/client.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/collectors/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/collectors/files.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/collectors/process.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/collectors/screenshot.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/config.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/crucial.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/custom_agents.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/departments.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/design_verify/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/design_verify/assets.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/design_verify/bootstrap.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/design_verify/browser.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/design_verify/compare.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/design_verify/loop.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/estimator.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/exceptions.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/firewall.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/formats.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/git_ops.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/github_fetch.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/github_ingest.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/graph_recon.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/graphify.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/hooks/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/hooks/crucial_guard.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/intake.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ipc/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ipc/electron_bridge.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ipc/handlers.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/journal.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/local_exec.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/memory_guard.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/models/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/models/envelope.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/models/requests.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/models/responses.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/models/snapshots.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/phase_timer.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/plan_run.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/platform_compat.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/prd_progress.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/proof_readers.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/providers.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/py.typed +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/resume.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/router.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/run_auto.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/schedule_tickets.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/scheduler.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/self_report.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/self_report_local.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/sse.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/swagger.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/task_file.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/task_types.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/test.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/test_pipeline.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ticket_fields.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/tickets.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/tiers/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/tiers/mini_agent.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/__init__.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/api.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/dashboard.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/health.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/ip_allowlist.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/jobs.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/models.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/runner.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/security.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/server.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/session.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/setup_manager.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/agents.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/app.js +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/chat.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/custom-agents.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/default-agents.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/index.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/report.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/runs.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/schedules.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/setup.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/styles.css +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/static/tickets.html +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/ui/swagger.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/updater.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/url_access.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/vps_health.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/vps_identity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/sdk/write_hook.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/setup.cfg +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_claude_runs.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_collectors.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_core.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_live_tracking.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_macos.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_os_setup.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_activity_pipeline.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_activity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_activity_tracking.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_chat_features.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_crud_cli.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_listing.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_prompt_async.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_prompt_models.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_run_ticket.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_schedules.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agent_workspace_settings.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_agents_connectors_builder.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_allowed_tools_config.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_auto_agent_dispatch.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_browser_profile.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_cheap_tier.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_client_jira_projects.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_config_token_diagnostics.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_configure_token_owner.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_console_encoding.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_crash_recovery.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_departments.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_done_transition.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_epic_decompose_run.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_epic_inherited_agent_id.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_epic_session_isolation.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_estimator.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_fallback_cli.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_firewall_open_on_update.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_formats.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_git_action.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_github_fetch.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_github_ingest.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_graph_recon.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_graphify_build.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_graphify_hook_install.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_health.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_intake_job_outcome.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_intake_plan_review.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_journal.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_local_exec_provider.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_mcp_route_contract.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_memory_guard.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_phase_timer.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_plan_new_command.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_plan_run_activity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_pr_identity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_prd_artifact.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_project_path_resolution.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_proof_readers.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_providers.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_recon_session_isolation.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_resume.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_router.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_run_auto_agent_only.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_run_outputs.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_run_verdict_is_honest.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_schedule_api.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_schedule_outputs_and_plans.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_schedule_tickets.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_scheduler.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_scheduler_transient_retry.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_self_report.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_service_token_warning.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_stale_panel_restart.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_swagger_command.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_task_file_and_plan_run.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_task_file_format_doc.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_ticket_cli.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_ticket_fields.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_ticket_run_resolve_by_id.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_ticket_speed_fixes.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_tier_flag_parity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_ui_gate.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_ui_lifespan.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_update_timer.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_updater_extras.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_updater_pep668.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_updater_reports_the_truth.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_url_access.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_vps_health.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_vps_only_reporting.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_windows_loop_identity.py +0 -0
- {devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/tests/test_write_hook.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""AgentOS Desktop SDK — thin HTTPS/SSE client for the Electron app.
|
|
2
2
|
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.76
|
|
4
4
|
|
|
5
5
|
Public surface:
|
|
6
6
|
BackendClient.from_config() — create client from ~/.agentos/config.toml
|
|
@@ -34,7 +34,7 @@ Rules:
|
|
|
34
34
|
- All data egress through submit_webhook only
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
__version__ = "1.6.
|
|
37
|
+
__version__ = "1.6.76" # SINGLE SOURCE OF TRUTH — bump on every change; pyproject,
|
|
38
38
|
__author__ = "AgentOS" # sdk.client.SDK_VERSION and the UI server version all read this.
|
|
39
39
|
|
|
40
40
|
from sdk.client import BackendClient
|
|
@@ -410,20 +410,118 @@ def _uninstall_launchd() -> tuple[bool, str]:
|
|
|
410
410
|
|
|
411
411
|
# ── Windows (Scheduled Task) ────────────────────────────────────────────────
|
|
412
412
|
|
|
413
|
+
#: Written when Windows refused the logged-out (S4U) panel task, so ``ensure`` does
|
|
414
|
+
#: not rebuild the task on every update only to be refused again.
|
|
415
|
+
_S4U_REFUSED_MARKER = Path.home() / ".agentos" / "panel_task_s4u_refused"
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def _windows_account() -> str:
|
|
419
|
+
"""``DOMAIN\\user`` for the task principal — the user whose ~/.agentos holds the token."""
|
|
420
|
+
import getpass
|
|
421
|
+
|
|
422
|
+
user = os.environ.get("USERNAME") or getpass.getuser()
|
|
423
|
+
domain = os.environ.get("USERDOMAIN") or os.environ.get("COMPUTERNAME") or ""
|
|
424
|
+
return f"{domain}\\{user}" if domain else user
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def _panel_task_xml(exe: str, args: str, home: str, account: str) -> str:
|
|
428
|
+
"""Task Scheduler XML for the panel: runs whether or not anyone is signed in.
|
|
429
|
+
|
|
430
|
+
The old task was ``/SC ONLOGON`` with an interactive token, so the panel — and
|
|
431
|
+
with it the health ping, the activity collector and the shipper — stopped the
|
|
432
|
+
moment the user signed out of RDP. A VPS used all day then reported nothing
|
|
433
|
+
from sign-out until the next sign-in ("VPS not reporting since 8h ago").
|
|
434
|
+
|
|
435
|
+
* ``S4U`` logon: runs without a stored password, signed in or not. It has no
|
|
436
|
+
Windows network credentials, which the panel does not use (HTTPS only).
|
|
437
|
+
* Boot AND logon triggers: up after a reboot with nobody signed in, and started
|
|
438
|
+
again at sign-in if it was down.
|
|
439
|
+
* Restart on failure, no execution time limit (the default is 72 h).
|
|
440
|
+
* ``HighestAvailable``: the collector reads the Security log, which needs an
|
|
441
|
+
elevated token — same as the old ``/RL HIGHEST``.
|
|
442
|
+
"""
|
|
443
|
+
from xml.sax.saxutils import escape
|
|
444
|
+
|
|
445
|
+
who = escape(account)
|
|
446
|
+
return (
|
|
447
|
+
'<?xml version="1.0" encoding="UTF-16"?>\n'
|
|
448
|
+
'<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">\n'
|
|
449
|
+
" <RegistrationInfo><Description>AgentOS control panel (health, activity, "
|
|
450
|
+
"ticket runs)</Description></RegistrationInfo>\n"
|
|
451
|
+
" <Triggers>\n"
|
|
452
|
+
" <BootTrigger><Enabled>true</Enabled><Delay>PT1M</Delay></BootTrigger>\n"
|
|
453
|
+
f" <LogonTrigger><Enabled>true</Enabled><UserId>{who}</UserId></LogonTrigger>\n"
|
|
454
|
+
" </Triggers>\n"
|
|
455
|
+
f' <Principals><Principal id="Author"><UserId>{who}</UserId>'
|
|
456
|
+
"<LogonType>S4U</LogonType><RunLevel>HighestAvailable</RunLevel>"
|
|
457
|
+
"</Principal></Principals>\n"
|
|
458
|
+
" <Settings>\n"
|
|
459
|
+
" <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>\n"
|
|
460
|
+
" <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>\n"
|
|
461
|
+
" <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>\n"
|
|
462
|
+
" <StartWhenAvailable>true</StartWhenAvailable>\n"
|
|
463
|
+
" <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>\n"
|
|
464
|
+
" <RestartOnFailure><Interval>PT1M</Interval><Count>999</Count></RestartOnFailure>\n"
|
|
465
|
+
" </Settings>\n"
|
|
466
|
+
' <Actions Context="Author"><Exec>'
|
|
467
|
+
f"<Command>{escape(exe)}</Command><Arguments>{escape(args)}</Arguments>"
|
|
468
|
+
f"<WorkingDirectory>{escape(home)}</WorkingDirectory>"
|
|
469
|
+
"</Exec></Actions>\n"
|
|
470
|
+
"</Task>\n"
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _create_task_from_xml(task: str, xml: str) -> tuple[int, str]:
|
|
475
|
+
import tempfile
|
|
476
|
+
|
|
477
|
+
fd, path = tempfile.mkstemp(suffix=".xml")
|
|
478
|
+
try:
|
|
479
|
+
with os.fdopen(fd, "w", encoding="utf-16") as fh: # schtasks /XML wants UTF-16
|
|
480
|
+
fh.write(xml)
|
|
481
|
+
return _run(["schtasks", "/Create", "/TN", task, "/XML", path, "/F"])
|
|
482
|
+
except OSError as exc:
|
|
483
|
+
return 1, str(exc)
|
|
484
|
+
finally:
|
|
485
|
+
try:
|
|
486
|
+
os.unlink(path)
|
|
487
|
+
except OSError:
|
|
488
|
+
pass
|
|
489
|
+
|
|
490
|
+
|
|
413
491
|
def _install_schtask(host: str, port: int) -> tuple[bool, str]:
|
|
414
492
|
exe = _exe()
|
|
415
493
|
refusal = _require_absolute(exe, WIN_TASK)
|
|
416
494
|
if refusal:
|
|
417
495
|
return False, refusal
|
|
418
|
-
|
|
419
|
-
rc, out =
|
|
420
|
-
|
|
496
|
+
args = f"--host {host} --port {port} --no-browser"
|
|
497
|
+
rc, out = _create_task_from_xml(
|
|
498
|
+
WIN_TASK, _panel_task_xml(exe, args, str(Path.home()), _windows_account()))
|
|
499
|
+
if rc == 0:
|
|
500
|
+
try:
|
|
501
|
+
_S4U_REFUSED_MARKER.unlink()
|
|
502
|
+
except OSError:
|
|
503
|
+
pass
|
|
504
|
+
_run(["schtasks", "/Run", "/TN", WIN_TASK])
|
|
505
|
+
return True, (f"installed scheduled task '{WIN_TASK}' — runs whether or not anyone "
|
|
506
|
+
f"is signed in, restarts on failure, and is running now.")
|
|
507
|
+
|
|
508
|
+
# Windows refused it (e.g. a policy denying "Log on as a batch job"). Fall back to
|
|
509
|
+
# the at-logon task: worse — it stops at sign-out — but never worse than before.
|
|
510
|
+
try:
|
|
511
|
+
_S4U_REFUSED_MARKER.parent.mkdir(parents=True, exist_ok=True)
|
|
512
|
+
_S4U_REFUSED_MARKER.write_text(out[-2000:], encoding="utf-8")
|
|
513
|
+
except OSError:
|
|
514
|
+
pass
|
|
515
|
+
tr = f'"{exe}" {args}'
|
|
516
|
+
rc, out2 = _run(["schtasks", "/Create", "/TN", WIN_TASK, "/TR", tr,
|
|
517
|
+
"/SC", "ONLOGON", "/RL", "HIGHEST", "/F"])
|
|
421
518
|
if rc != 0:
|
|
422
|
-
return False, f"schtasks create failed:\n{out}"
|
|
519
|
+
return False, f"schtasks create failed:\n{out}\n{out2}"
|
|
423
520
|
_run(["schtasks", "/Run", "/TN", WIN_TASK])
|
|
424
521
|
return True, (f"installed scheduled task '{WIN_TASK}' — starts at logon and is "
|
|
425
|
-
f"running now
|
|
426
|
-
f"
|
|
522
|
+
f"running now. NOTE: Windows refused the run-while-signed-out task, so "
|
|
523
|
+
f"the panel STOPS when you sign out — disconnect from RDP instead of "
|
|
524
|
+
f"signing out. Reason: {out.strip()[-300:]}")
|
|
427
525
|
|
|
428
526
|
|
|
429
527
|
def _update_task_xml(exe: str, home: str) -> str:
|
|
@@ -527,6 +625,19 @@ def _schtask_points_nowhere(task: str) -> bool:
|
|
|
527
625
|
return cmd is not None and not (Path(cmd).is_absolute() and Path(cmd).is_file())
|
|
528
626
|
|
|
529
627
|
|
|
628
|
+
def _schtask_runs_signed_out(task: str) -> bool | None:
|
|
629
|
+
"""True when ``task`` keeps running after sign-out; ``None`` if it cannot be read."""
|
|
630
|
+
rc, out = _run(["schtasks", "/Query", "/TN", task, "/XML"])
|
|
631
|
+
if rc != 0:
|
|
632
|
+
return None
|
|
633
|
+
return bool(re.search(r"<LogonType>\s*(S4U|Password)\s*</LogonType>", out))
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
def _panel_task_needs_upgrade() -> bool:
|
|
637
|
+
"""An at-logon panel task (pre-1.6.76) that Windows has not already refused to replace."""
|
|
638
|
+
return _schtask_runs_signed_out(WIN_TASK) is False and not _S4U_REFUSED_MARKER.exists()
|
|
639
|
+
|
|
640
|
+
|
|
530
641
|
def _uninstall_schtask() -> tuple[bool, str]:
|
|
531
642
|
_run(["schtasks", "/Delete", "/TN", WIN_UPDATE_TASK, "/F"])
|
|
532
643
|
_run(["schtasks", "/End", "/TN", WIN_TASK])
|
|
@@ -855,6 +966,10 @@ def ensure(restart_running: bool = False) -> tuple[bool, str]:
|
|
|
855
966
|
rok, rmsg = refresh() # rebuilds the task with an absolute path
|
|
856
967
|
return rok, (_with_token_warning(f"panel task pointed at a missing program — "
|
|
857
968
|
f"rebuilt; {rmsg}") if rok else rmsg)
|
|
969
|
+
if IS_WINDOWS and _panel_task_needs_upgrade():
|
|
970
|
+
rok, rmsg = refresh() # at-logon task → runs while signed out
|
|
971
|
+
return rok, (_with_token_warning(f"panel task now runs while signed out; {rmsg}")
|
|
972
|
+
if rok else rmsg)
|
|
858
973
|
if _is_active():
|
|
859
974
|
stale = _restart_if_stale()
|
|
860
975
|
if stale is not None:
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""The Windows panel task keeps running after the user signs out.
|
|
2
|
+
|
|
3
|
+
The incident: the panel task was ``/SC ONLOGON`` with an interactive token, so
|
|
4
|
+
the panel — health ping, activity collector, shipper, ticket runs — stopped the
|
|
5
|
+
moment someone signed out of RDP. A VPS used all day showed "VPS not reporting
|
|
6
|
+
since 8h ago" on the dashboard from sign-out until the next sign-in, and the
|
|
7
|
+
existing task was never upgraded by an update.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
from sdk.ui import service
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def windows(monkeypatch, tmp_path):
|
|
20
|
+
exe = tmp_path / "R&D" / "Scripts" / "agentos-ui.exe"
|
|
21
|
+
exe.parent.mkdir(parents=True)
|
|
22
|
+
exe.write_text("")
|
|
23
|
+
monkeypatch.setattr(service, "IS_WINDOWS", True)
|
|
24
|
+
monkeypatch.setattr(service, "_exe", lambda: str(exe))
|
|
25
|
+
monkeypatch.setattr(service, "_S4U_REFUSED_MARKER", tmp_path / ".agentos" / "refused")
|
|
26
|
+
monkeypatch.setenv("USERDOMAIN", "WIN-PND3HEN88VE")
|
|
27
|
+
monkeypatch.setenv("USERNAME", "Administrator")
|
|
28
|
+
return exe
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _recorder(monkeypatch, *, xml_rc=0, xml_out=""):
|
|
32
|
+
calls, xmls = [], []
|
|
33
|
+
|
|
34
|
+
def run(argv):
|
|
35
|
+
calls.append(argv)
|
|
36
|
+
if "/XML" in argv and "/Create" in argv:
|
|
37
|
+
xmls.append(Path(argv[argv.index("/XML") + 1]).read_text(encoding="utf-16"))
|
|
38
|
+
return xml_rc, xml_out
|
|
39
|
+
return 0, ""
|
|
40
|
+
monkeypatch.setattr(service, "_run", run)
|
|
41
|
+
return calls, xmls
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestTheTaskDefinition:
|
|
45
|
+
def test_runs_signed_out_at_boot_and_logon_and_restarts(self, monkeypatch, windows):
|
|
46
|
+
_, xmls = _recorder(monkeypatch)
|
|
47
|
+
ok, msg = service._install_schtask("0.0.0.0", 8765)
|
|
48
|
+
assert ok is True and "signed in" in msg
|
|
49
|
+
xml = xmls[0]
|
|
50
|
+
assert "<LogonType>S4U</LogonType>" in xml
|
|
51
|
+
assert "<RunLevel>HighestAvailable</RunLevel>" in xml # reads the Security log
|
|
52
|
+
assert "<BootTrigger>" in xml and "<LogonTrigger>" in xml
|
|
53
|
+
assert "<UserId>WIN-PND3HEN88VE\\Administrator</UserId>" in xml
|
|
54
|
+
assert "<RestartOnFailure>" in xml
|
|
55
|
+
assert "<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>" in xml # default would be 72 h
|
|
56
|
+
assert "R&D" in xml # the path is escaped
|
|
57
|
+
|
|
58
|
+
def test_the_task_is_started_after_creation(self, monkeypatch, windows):
|
|
59
|
+
calls, _ = _recorder(monkeypatch)
|
|
60
|
+
service._install_schtask("0.0.0.0", 8765)
|
|
61
|
+
assert ["schtasks", "/Run", "/TN", service.WIN_TASK] in calls
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TestWhenWindowsRefusesIt:
|
|
65
|
+
def test_falls_back_to_the_at_logon_task_and_says_so(self, monkeypatch, windows):
|
|
66
|
+
calls, _ = _recorder(monkeypatch, xml_rc=1, xml_out="ERROR: Access is denied.")
|
|
67
|
+
ok, msg = service._install_schtask("0.0.0.0", 8765)
|
|
68
|
+
assert ok is True
|
|
69
|
+
fallback = calls[1]
|
|
70
|
+
assert fallback[fallback.index("/SC") + 1] == "ONLOGON"
|
|
71
|
+
assert "disconnect from RDP instead of signing out" in msg
|
|
72
|
+
assert service._S4U_REFUSED_MARKER.exists() # don't retry every update
|
|
73
|
+
|
|
74
|
+
def test_a_later_success_clears_the_refusal(self, monkeypatch, windows):
|
|
75
|
+
service._S4U_REFUSED_MARKER.parent.mkdir(parents=True)
|
|
76
|
+
service._S4U_REFUSED_MARKER.write_text("denied")
|
|
77
|
+
_recorder(monkeypatch)
|
|
78
|
+
service._install_schtask("0.0.0.0", 8765)
|
|
79
|
+
assert not service._S4U_REFUSED_MARKER.exists()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _query(monkeypatch, rc, logon_type):
|
|
83
|
+
xml = f"<Task><Principals><Principal><LogonType>{logon_type}</LogonType></Principal></Principals></Task>"
|
|
84
|
+
monkeypatch.setattr(service, "_run", lambda argv: (rc, xml))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class TestDetection:
|
|
88
|
+
@pytest.mark.parametrize("logon_type, expected", [
|
|
89
|
+
("InteractiveToken", False), ("S4U", True), ("Password", True)])
|
|
90
|
+
def test_reads_the_logon_type(self, monkeypatch, logon_type, expected):
|
|
91
|
+
_query(monkeypatch, 0, logon_type)
|
|
92
|
+
assert service._schtask_runs_signed_out(service.WIN_TASK) is expected
|
|
93
|
+
|
|
94
|
+
def test_an_unreadable_task_is_unknown_not_old(self, monkeypatch, windows):
|
|
95
|
+
_query(monkeypatch, 1, "InteractiveToken")
|
|
96
|
+
assert service._schtask_runs_signed_out(service.WIN_TASK) is None
|
|
97
|
+
assert service._panel_task_needs_upgrade() is False
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class TestEnsureUpgradesTheExistingTask:
|
|
101
|
+
@pytest.fixture
|
|
102
|
+
def installed(self, monkeypatch, windows):
|
|
103
|
+
monkeypatch.setattr(service, "_service_disabled", lambda: False)
|
|
104
|
+
monkeypatch.setattr(service, "is_installed", lambda: True)
|
|
105
|
+
monkeypatch.setattr(service, "update_timer_installed", lambda: True)
|
|
106
|
+
monkeypatch.setattr(service, "_needs_root_for_existing", lambda: False)
|
|
107
|
+
monkeypatch.setattr(service, "_schtask_points_nowhere", lambda task: False)
|
|
108
|
+
monkeypatch.setattr(service, "_with_token_warning", lambda m: m)
|
|
109
|
+
monkeypatch.setattr(service, "_is_active", lambda: True)
|
|
110
|
+
monkeypatch.setattr(service, "_restart_if_stale", lambda: None)
|
|
111
|
+
seen = {"refresh": 0}
|
|
112
|
+
|
|
113
|
+
def refresh():
|
|
114
|
+
seen["refresh"] += 1
|
|
115
|
+
return True, "service refreshed"
|
|
116
|
+
monkeypatch.setattr(service, "refresh", refresh)
|
|
117
|
+
return seen
|
|
118
|
+
|
|
119
|
+
def test_an_at_logon_task_is_rebuilt_on_the_next_update(self, monkeypatch, installed):
|
|
120
|
+
_query(monkeypatch, 0, "InteractiveToken")
|
|
121
|
+
ok, msg = service.ensure(restart_running=False)
|
|
122
|
+
assert ok is True and "runs while signed out" in msg
|
|
123
|
+
assert installed["refresh"] == 1
|
|
124
|
+
|
|
125
|
+
def test_an_already_upgraded_task_is_left_alone(self, monkeypatch, installed):
|
|
126
|
+
_query(monkeypatch, 0, "S4U")
|
|
127
|
+
service.ensure(restart_running=False)
|
|
128
|
+
assert installed["refresh"] == 0
|
|
129
|
+
|
|
130
|
+
def test_a_box_that_refused_it_is_not_rebuilt_every_update(self, monkeypatch, installed):
|
|
131
|
+
service._S4U_REFUSED_MARKER.parent.mkdir(parents=True)
|
|
132
|
+
service._S4U_REFUSED_MARKER.write_text("denied")
|
|
133
|
+
_query(monkeypatch, 0, "InteractiveToken")
|
|
134
|
+
service.ensure(restart_running=False)
|
|
135
|
+
assert installed["refresh"] == 0
|
|
@@ -88,11 +88,20 @@ class TestRefusesABareProgramName:
|
|
|
88
88
|
exe.write_text("")
|
|
89
89
|
calls = []
|
|
90
90
|
monkeypatch.setattr(service, "_run", lambda argv: (calls.append(argv), (0, ""))[1])
|
|
91
|
+
xml_seen = []
|
|
92
|
+
|
|
93
|
+
def run(argv):
|
|
94
|
+
calls.append(argv)
|
|
95
|
+
if "/XML" in argv:
|
|
96
|
+
xml_seen.append(Path(argv[argv.index("/XML") + 1]).read_text(encoding="utf-16"))
|
|
97
|
+
return 0, ""
|
|
98
|
+
monkeypatch.setattr(service, "_run", run)
|
|
91
99
|
ok, _ = service._install_schtask("0.0.0.0", 8765)
|
|
92
100
|
assert ok is True
|
|
93
101
|
create = calls[0]
|
|
94
102
|
assert create[:4] == ["schtasks", "/Create", "/TN", service.WIN_TASK]
|
|
95
|
-
assert
|
|
103
|
+
assert f"<Command>{exe}</Command>" in xml_seen[0]
|
|
104
|
+
assert "<Arguments>--host 0.0.0.0 --port 8765 --no-browser</Arguments>" in xml_seen[0]
|
|
96
105
|
|
|
97
106
|
|
|
98
107
|
def _task_xml(command: str) -> str:
|
|
File without changes
|
{devops_bot_sdk-1.6.75 → devops_bot_sdk-1.6.76}/devops_bot_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|