Skip to content

Enforce the installed workspace policy on launch - #1260

Open
billiam-wang wants to merge 4 commits into
mdm-policy-writefrom
mdm-policy-read
Open

billiam-wang wants to merge 4 commits into
mdm-policy-writefrom
mdm-policy-read

Conversation

@billiam-wang

@billiam-wang billiam-wang commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

🥞 Stacked PR

Use this link to review incremental changes.


Worktree: unity-gateway | Branch: mdm-policy-read

What did you change, and why?

Second of two stacked PRs replacing #1228. It's based on #1259, which installs the policy file. Launches now read the installed policy instead of the per-user cache on Linux and macOS:

  • ug, ug claude and ug codex refuse any other workspace. Only ug configure can switch it.
  • Refresh happens at most every 5 minutes, through ~/.ucode/refresh_ts.json.
  • A first launch before any configure applies the fetched policy for that run.
  • If sudo is denied, the saved workspace stays on the installed one.

Windows, UG_SKIP_OS_SETTINGS and --user keep the per-user cache unchanged.

How do you know it works?

Unit tests cover enforcement, refresh and fallback. The CUJ and integration harnesses read the installed policy. Lint and ty are clean.

This pull request and its description were written by Isaac.

Launches read the policy installed at /etc/unitygateway/managed-settings.json,
refuse a selection for another workspace, and refresh at most every five
minutes using user-owned stamps in ~/.ucode/refresh_ts.json. Non-root launches
never install or remove the policy. The per-user cache remains only for
Windows, UG_SKIP_OS_SETTINGS, and --user. Configure restores the saved
workspace on a denied install, and other agents refuse early on a machine
managed elsewhere. Also adds ug export, dry-run workspace adoption, and the
CUJ recorder and harness reading the installed policy.

Co-authored-by: Isaac <no-reply@databricks.com>
# Conflicts:
#	docs/managed-workspace-policy.md
#	src/ucode/managed_config.py
#	tests/test_managed_config.py
@billiam-wang

Copy link
Copy Markdown
Collaborator Author

/ug-review

Comment thread src/ucode/cli.py Outdated
Comment thread src/ucode/cli.py Outdated
Comment thread src/ucode/cli.py
Comment thread src/ucode/managed_config.py
Comment thread src/ucode/managed_config.py
Comment thread tests/integration/test_ug_configure_managed.py
Comment thread tests/test_cli.py Outdated
Comment thread tests/test_cli.py
Comment thread tests/test_managed_config.py
billiam-wang and others added 2 commits October 23, 2026 03:52
- The --agent refusal says the selection stays on the installed workspace
  and to rerun configure from a terminal with sudo access.
- The launch refusal tells skip-mode users to switch without
  UG_SKIP_OS_SETTINGS, which is the only way the policy can change.
- _launch_workspace_state resolves the target workspace once.
- The configure integration test checks the policy folder is root-owned.

Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions

Copy link
Copy Markdown

Polly AI Review

Blocking issues

  1. Failed workspace switches leave launches blocked — src/ucode/cli.py:813, src/ucode/managed_config.py:910

    can we retain workspace A when configuring B cannot fetch its policy? the fallback returns normally, leaving B saved under A’s installed policy; subsequent launches refuse B.

    Extend tests/test_cli.py::TestDeniedMachineWorkspaceSwitch with token and fetch failures; assert that A remains selected.

  2. First-launch policy reads bypass the five-minute throttle — src/ucode/managed_config.py:832, src/ucode/managed_config.py:920

    can we resolve replay for non-root launches without an installed policy? a successful read stamps published but retains no policy, so the next launch immediately fetches again.

    Extend tests/test_managed_config.py::TestMachinePolicyRefresh::test_non_root_launch_applies_the_fetched_policy_without_installing with a second launch inside the TTL.

    Run-only policy storage and unconditional cross-process throttling need a consistent contract; treating the published stamp as “no policy” would drop enforcement.

Security vulnerabilities

No confirmed new vulnerability found in the reviewed changes. Installed-policy precedence under UG_SKIP_OS_SETTINGS is intentional, not an authorization bypass. Directory-ownership coverage lost during test consolidation should be restored below.

Non-blocking notes

  • README.md:465: can we correct the claim that revert leaves policy installed? revert_machine_policy removes it when permitted; the detailed documentation and tests agree.
  • tests/integration/test_ug_configure_managed.py:122: can we restore policy.parent.stat().st_uid == 0 in test_ug_managed_config_launch_reuses_cache_within_ttl? consolidation dropped it.
  • tests/e2e_cuj/helpers/tui_request_recorder.py:90: can we bound the sudo copy with a timeout and explicit stdin? an authentication wait can otherwise stall the CUJ.
  • tests/test_managed_config.py: can we preserve successful FEATURE_DISABLED deletion and stored-config equality assertions when replacing the old installation cases?

No added or modified source comments warrant a conciseness finding.

Approach

Separating protected policy from user-owned refresh metadata is sound when an installed policy exists. The first-launch storage/throttling conflict needs resolution rather than another fallback branch.

The repeated refresh-result construction and overlapping token/fetch handling in src/ucode/managed_config.py:917, src/ucode/managed_config.py:948, and src/ucode/managed_config.py:1004 offer a small consolidation opportunity, not a reason to block.

Summary

Diff size (computed): 20 files; +1829 / -537 lines (2366 changed text lines); 0 binary files.

Category Files Added Deleted Share of changed text lines
Tests and test support 12 1113 329 60.9%
Documentation 3 309 41 14.8%
Dependencies and lockfiles 0 0 0 0.0%
Implementation / other 5 407 167 24.3%

Shares use additions + deletions, including generated text and lockfiles. Binary files have no line count. Tests include fixtures/helpers under test paths and colocated test/spec files; categories are path-based, not coverage measurements.

Changes

The PR makes installed machine policy authoritative for launch workspace selection, separates freshness metadata into a user-owned sidecar, and restores the installed workspace after denied configure writes. It also migrates integration/CUJ evidence sources and updates documentation.

Most of the size follows the persistence migration and state-transition coverage. No dependency or lockfile changes are included. Sharing refresh plumbing could reduce duplication without changing the design.

Tests

Test-by-test assessment

The frozen diff’s checksum was verified and both trusted policy files were read. Tests were not executed; the PR’s reported green results were not independently verified. The supplied base/head Git objects were unavailable locally, so unchanged context came from the supplied trusted checkout rather than the exact target tree.

The tables account for changed cases, removed cases, and support edits. Existing callers are identified where a changed helper alters their evidence source. Parameterized inputs with the same purpose share a row.

Shared support, documentation, and CUJ adapters

Test / case Behavior protected Layer Needed? Action / rationale
tests/README.md — removed installation-only coverage row Coverage inventory follows consolidated scenario Documentation keep Removes an obsolete test reference, not executable coverage.
tests/README.md — machine-policy coverage narrative Explains sidecar, workspace enforcement, and evidence limits Documentation keep Relevant documentation; reconcile its TTL claim with blocking issue 2.
tests/conftest.py::_isolate_ucode_state Redirects policy, sidecar, and cache away from real paths Fixture keep Necessary isolation for the new persistence source.
tests/conftest.py::_isolate_ucode_state::install_test_policy Simulates install/removal and file mode Helper keep Appropriate component primitive; does not prove real ownership or elevation.
tests/conftest.py — default Linux/root simulation Existing component cases exercise machine-policy flow Fixture keep Explicit non-root cases remain necessary; this default does not establish ordinary-user replay.
tests/e2e_cuj/helpers/tui_request_recorder.py::TuiRequestRecorder.prepare_launch Refreshes recorder-targeted sidecar and fingerprint E2E support keep Required source migration; rewriting freshness metadata is not product TTL evidence.
tests/e2e_cuj/helpers/tui_request_recorder.py::TuiRequestRecorder.retarget_session Retargets saved workspace and installed policy E2E support keep Required by workspace authority; bound the privileged subprocess.
tests/e2e_cuj/test_cuj1_explicit_models.py::_managed_config Reads installed raw policy E2E assertion helper keep Changes the evidence source without adding a scenario.
tests/e2e_cuj/test_cuj1_explicit_models.py::TestCujManagedConfiguration::test_cuj_managed_configuration — helper-affected caller Configure assertions inspect installed policy Existing E2E keep Existing process/configuration boundary remains relevant.
tests/e2e_cuj/test_cuj1_explicit_models.py::TestCujManagedClaude::test_cuj_managed_claude — helper-affected caller Claude inference expectations use installed policy Existing E2E keep Retains native-agent/request correlation.
tests/e2e_cuj/test_cuj1_explicit_models.py::TestCujManagedCodex::test_cuj_managed_codex — helper-affected caller Codex inference expectations use installed policy Existing E2E keep Covers a distinct agent boundary.
tests/e2e_cuj/test_cuj1_explicit_models.py::TestCujManagedTracing::test_cuj_managed_tracing — helper-affected caller Tracing expectations use installed policy Existing E2E keep Maintains existing tracing evidence; no new scenario.
tests/e2e_cuj/test_cuj2_mps_mcp.py::_assert_configured_files MPS/MCP assertions read installed manifest E2E assertion helper keep Retains assertions while changing their source.
tests/e2e_cuj/test_cuj2_mps_mcp.py::TestCuj2Configuration::test_cuj_configuration — helper-affected caller Configuration and generated MCP listing Existing E2E keep Existing configuration boundary, not a new refresh test.
tests/e2e_cuj/test_cuj2_mps_mcp.py::TestCuj2CodexInference::test_cuj_codex_inference — helper-affected caller Codex inference and configured-file checks Existing E2E keep Preserves existing native-agent evidence.
tests/e2e_cuj/test_cuj2_mps_mcp.py::TestCuj2ClaudeInference::test_cuj_claude_inference — helper-affected caller Claude inference and configured-file checks Existing E2E keep Preserves the separate Claude boundary.
tests/integration/README.md — policy/TTL narrative and coverage inventory Explains changed test guarantees Documentation keep Distinguishes component evidence from live provisioning.
tests/integration/README.md — clean-machine prerequisite Avoids interference from existing machine policy Documentation keep Relevant prerequisite, not an executable isolation guarantee.
tests/integration/utils/managed.py::is_managed_config_control_plane_cache Excludes sidecar from agent-owned file comparisons Helper keep Correctly classifies control-plane metadata.

Integration cases

Test / case Behavior protected Layer Needed? Action / rationale
tests/integration/test_ug_configure_managed.py::test_ug_configure_installs_workspace_policy_machine_wide — removed Root-owned policy, wrapper shape, file/directory modes Integration consolidate Existing TTL journey is a suitable survivor, but transfer the directory-owner assertion.
tests/integration/test_ug_configure_managed.py::test_ug_managed_config_launch_reuses_cache_within_ttl Configure, warm reuse, expired unchanged refresh, unchanged policy metadata Integration keep Real process/OS-file boundary is useful; restore the removed parent-directory UID assertion.
tests/integration/test_ug_configure_managed.py::test_ug_managed_machine_refuses_foreign_workspace_launch — bare/Claude/Codex × normal/dry-run Public entry points reject foreign workspace without state changes Integration keep Subprocess checks establish CLI parsing and preservation across public entry points. Loop variants are not separate collected cases.
tests/integration/test_ug_codex_managed_model_discovery.py::_assert_managed_provider_catalog[installed=True,False] Installed versus run-only policy and exact native catalogs Integration helper keep Fresh-state branch stops requiring nonexistent persistence while retaining catalog assertions.
tests/integration/test_ug_codex_managed_model_discovery.py::test_case_02_managed_codex_uses_admin_discovery_after_configure — helper-affected caller Configured policy and native catalog agree Existing integration keep Retains configured-state evidence through the new source.
tests/integration/test_ug_codex_managed_model_discovery.py::test_case_02_managed_codex_uses_admin_discovery_from_fresh_state First non-root launch applies discovery without installing policy Integration keep Distinct first-launch boundary; exact catalog assertions remain meaningful.

CLI cases

Test / case Behavior protected Layer Needed? Action / rationale
tests/test_cli.py::TestDeniedMachineWorkspaceSwitch::test_denied_switch_keeps_the_saved_workspace_on_the_installed_one[replace,remove] Denied mutation restores installed workspace Component keep Both mutation paths matter; extend with token/fetch failures for blocking issue 1.
tests/test_cli.py::TestUnrelatedConfigureFailure::test_other_errors_leave_the_saved_workspace_alone Unrelated exceptions do not trigger broad rollback Unit keep Protects narrow restoration semantics; does not cover normal-return fetch failure.
tests/test_cli.py::TestDryRunAdoptsInstalledWorkspace::test_dry_run_launch_state_uses_the_installed_workspace Dry-run adopts workspace in memory Unit keep Distinct no-save path.
tests/test_cli.py::TestConfigureOtherAgentReadsPolicyOnly::test_only_claude_and_codex_force_the_policy_read[opencode-False,claude-True] Configure dispatch chooses refresh mode Unit keep Representative branches suffice; proves dispatch arguments, not privilege behavior.
tests/test_cli.py::TestConfigureOtherAgentOnAnotherWorkspacesMachine::test_other_agent_configure_keeps_the_machine_workspace Other-agent configure refuses B and restores A Component keep Separate path from Claude/Codex installation.
tests/test_cli.py::TestInstalledMachineWorkspace::test_foreign_workspace_launch_fails_before_setup — state/flag × bare/Claude × normal/dry-run Refusal precedes setup, authentication, refresh, and launch CLI component keep Matrix belongs below live-agent tests; shared launch-tool coverage represents other agents.
tests/test_cli.py::TestInstalledMachineWorkspace::test_bare_launch_without_user_workspace_uses_installed_workspace Fresh user adopts installed workspace and dispatches CLI component keep Tests observable dispatch beyond resolver output.

Persistence and TTL cases

Test / case Behavior protected Layer Needed? Action / rationale
tests/test_managed_config.py::TestPersistence::test_saved_file_is_0600 → test_saved_file_is_0644 Machine policy is readable under its new contract Component keep User-cache and sidecar privacy are assessed separately.
tests/test_managed_config.py::TestPersistence::test_empty_config_overwrites_a_previous_one → test_empty_config_removes_a_matching_policy Removal leaves no empty policy tombstone Component keep Preserves stale-policy prevention with deletion semantics.
tests/test_managed_config.py::TestPersistence::test_outcome_stamps_retrieved_at_and_outcome → test_policy_contains_only_workspace_and_raw_config Protected wrapper excludes refresh metadata Component keep Timestamp/outcome assertions move to sidecar cases.
tests/test_managed_config.py::TestRefreshTTL::_write_cache Seeds installed policy with matching freshness metadata Helper keep Adapts existing TTL scenarios without new E2E setup.
tests/test_managed_config.py::TestRefreshTTL::test_fresh_published_cache_short_circuits Warm installed policy avoids fetching Component keep Covers installed state, not the absent-policy path in blocking issue 2.
tests/test_managed_config.py::TestRefreshTTL::test_fresh_legacy_cache_normalizes_to_smart_defaults Cached legacy manifest normalizes compatibly Component keep Distinct compatibility assertion.
tests/test_managed_config.py::TestRefreshTTL::test_fresh_no_config_cache_short_circuits Fresh negative outcome avoids fetching Component keep Establishes sidecar-only negative replay.
tests/test_managed_config.py::TestRefreshTTL::test_fresh_feature_disabled_cache_short_circuits Disabled outcome replays its flag Component keep Distinct from ordinary absence.
tests/test_managed_config.py::TestRefreshTTL::test_stale_cache_refetches TTL expiry triggers refresh Component keep Smallest reliable layer for clock boundary.
tests/test_managed_config.py::TestRefreshTTL::test_future_dated_cache_refetches Invalid future stamp is rejected Component keep Separate invalid-age boundary.
tests/test_managed_config.py::TestRefreshTTL::test_missing_timestamp_refetches Missing freshness stamp triggers read Component keep Existing behavior remains relevant with sidecar storage.
tests/test_managed_config.py::TestRefreshTTL::test_invalid_timestamp_refetches Malformed sidecar timestamp triggers read Component keep Correct corruption input for the new source.
tests/test_managed_config.py::TestRefreshTTL::test_other_workspace_cache_refetches Foreign negative stamp cannot satisfy current workspace Component keep Installed foreign-policy refusal is covered separately.
tests/test_managed_config.py::TestRefreshTTL::test_force_refresh_bypasses_a_fresh_cache Explicit configure bypasses warm freshness Component keep Distinct authority/refresh control.
tests/test_managed_config.py::TestRefreshTTL::test_first_launch_with_no_cache_fetches — helper-affected Initial read occurs Component keep Existing assertion is useful but lacks the second read exposing blocking issue 2.
tests/test_managed_config.py::TestRefreshTTL::test_non_utf8_cache_file_refetches — fixture-affected Corrupt policy is handled forgivingly Component keep Existing body now exercises redirected machine storage.
tests/test_managed_config.py::TestRefreshTTL::test_successful_read_stamps_retrieved_at_and_outcome Policy wrapper, published stamp, and private sidecar Component keep Transfers metadata coverage to its new location.
tests/test_managed_config.py::TestRefreshTTL::test_no_config_read_caches_none_outcome Absence records metadata without machine file Component keep Distinct negative persistence contract.
tests/test_managed_config.py::TestRefreshTTL::test_feature_disabled_read_caches_feature_disabled_outcome Disabled response records its outcome Component keep Preserves distinction from ordinary absence.
tests/test_managed_config.py::TestRefreshTTL::test_failed_read_does_not_advance_retrieved_at Failure preserves installed fallback and successful stamp Component keep Meaningful outage assertion transferred to sidecar.

Machine-policy refresh cases

Test / case Behavior protected Layer Needed? Action / rationale
tests/test_managed_config.py::TestMachinePolicyRefresh::_stub_clock_and_fetch Explicit clock/auth/API inputs Fixture consolidate Share matching setup with TestPolicyWithoutInstallation without expanding global mocks.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_unchanged_policy_never_invokes_privileged_writer Unchanged configure preserves policy and records check Component keep Distinct forced-read no-op guarantee.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_expired_unchanged_policy_advances_only_user_timestamp Expired launch changes only sidecar Component keep Complements forced configure with TTL behavior.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_server_retrieval_time_change_does_not_trigger_sudo Volatile retrieval metadata is not policy drift Component keep Distinct comparison rule.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_only_explicit_configure_allows_policy_elevation[False,True] Writer receives appropriate sudo/interactive options Unit/component keep Tests argument selection, not real elevation.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_denied_changed_policy_warns_and_reuses_installed_policy Failed replacement preserves manifest and warm replay Component keep Covers fallback and immediate replay together.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_denied_initial_install_warns_and_applies_the_fetched_policy Failed initial write still supplies fetched policy Component keep Distinct fallback without an installed source.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_non_root_launch_applies_the_fetched_policy_without_installing Ordinary first launch avoids protected write Component keep Extend with a second call inside TTL for blocking issue 2.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_non_root_configure_installs_the_policy Explicit configure can install for non-root caller Component keep Distinct from root-default launch behavior.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_configure_reports_failed_install_and_preserves_policy Failed configure raises and preserves policy Component keep Necessary failure-path coverage.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_no_remote_policy_never_creates_machine_file Absence creates only metadata Component keep Distinct no-install side-effect guarantee.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_removed_policy_is_deleted_instead_of_replaced_with_empty_file Successful removal deletes policy Component keep Add successful FEATURE_DISABLED removal input to transfer deleted coverage.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_failed_policy_removal_warns_and_preserves_installed_policy[None,FEATURE_DISABLED] Removal failure preserves effective policy Component keep Both response forms matter.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_cached_feature_disabled_read_keeps_its_flag_when_removal_failed Warm replay preserves retained manifest and diagnostic Component keep Distinct replay branch; does not by itself prove every consumer handles the pair.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_configure_for_a_workspace_without_policy_removes_another_workspaces Configure can remove foreign installed policy Component keep Important configure-only authority.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_launch_never_removes_another_workspaces_policy Foreign launch preserves policy Component consolidate Carry preservation assertion into broader mismatch-ordering case.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_launch_for_another_workspace_without_policy_keeps_it Low-level empty save cannot remove foreign policy Unit/component keep Exercises persistence primitive separately from launch guard.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_timestamps_are_keyed_by_workspace_without_policy_copies Metadata partitions workspaces without raw policy Component keep Distinct storage-shape invariant.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_workspace_urls_with_trailing_slash_share_policy_and_timestamp Canonical URL shares warm entry Component keep Covers cache identity.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_external_policy_change_invalidates_recent_stamp External replacement invalidates fingerprint Component keep Necessary MDM/other-process transition.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_legacy_home_cache_is_not_a_policy_fallback Normal machine path ignores old user policy Component keep Explicit migration/trust-boundary behavior.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_launch_dry_run_does_not_fetch_or_stamp Installed-policy preview is offline/read-only Component keep Appropriate layer for refresh side effects.
tests/test_managed_config.py::TestMachinePolicyRefresh::_deny_policy_updates Shared denied-writer and warning capture Helper keep Bounded primitive with faults/assertions visible in cases.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_same_pending_change_warns_once_across_expired_checks Same pending change suppresses repeated warnings Component keep Stateful expiry sequence adds value; repeated later expiry steps add little new evidence.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_distinct_pending_change_warns_again New policy drift warns again Component keep Distinct from repeated identical drift.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_pending_hash_ignores_retrieval_time_and_object_key_order Stable hash ignores non-semantic changes Component keep Protects comparison/hash semantics.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_pending_removal_warns_once_across_expired_checks[None,FEATURE_DISABLED] Removal warnings are deduplicated Component keep Appropriate shared parameterized scenario.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_reconciliation_clears_pending_hash[remote,mdm,configure] Each reconciliation route resets suppression Component keep Distinct transitions belong below E2E; configure case should assert stored replacement content too.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_reintroduced_change_warns_after_remote_reverts Later recurrence warns after reconciliation Component keep Distinct lifecycle sequence.
tests/test_managed_config.py::TestMachinePolicyRefresh::test_fetch_failure_preserves_pending_hash_and_check_time Transient failure preserves prior metadata Component keep Necessary failure after deferred update.

Per-user fallback and workspace resolution

Test / case Behavior protected Layer Needed? Action / rationale
tests/test_managed_config.py::TestPolicyWithoutInstallation::_stub_clock_and_fetch Explicit clock/auth/API inputs Fixture consolidate Reuse matching local refresh fixture.
tests/test_managed_config.py::TestPolicyWithoutInstallation::not_installable[skip_os_settings,windows] Selects fallback mode and forbids privileged writes Fixture keep Explicit reusable inputs; scope plumbing elsewhere does not prove cache lifecycle.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_fetched_policy_applies_without_installing — fallback mode × forced/ordinary refresh User policy applies without protected file Component keep Compact matrix at the smallest reliable layer.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_launch_reuses_the_per_user_cache_within_the_ttl[skip_os_settings,windows] Compatibility-mode positive replay Component keep Distinct preservation of legacy cache behavior.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_failed_fetch_falls_back_to_the_per_user_cache[skip_os_settings,windows] Outage retains user policy Component keep Distinct fallback failure path.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_removed_policy_replaces_the_per_user_cache[skip_os_settings,windows] Authoritative absence clears stale user policy Component keep Prevents resurrection after a later outage.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_per_user_cache_is_private[skip_os_settings,windows] User cache retains private POSIX mode Component keep Separate from readable machine-policy contract; host-Windows mode skip is appropriate.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_windows_ignores_a_planted_posix_policy_file Windows does not trust POSIX policy location Component keep Distinct platform boundary.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_export_finds_the_per_user_cache_without_a_saved_workspace[skip_os_settings,windows] Resolver discovers fallback-cache workspace Unit/component consolidate Calls resolver, not export; extend existing TestBuildPayload::test_falls_back_to_managed_state_workspace for export evidence.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_installed_policy_still_wins_with_skip Skip mode cannot bypass installed authority Component keep Intentional policy precedence.
tests/test_managed_config.py::TestPolicyWithoutInstallation::test_configure_with_skip_degrades_like_a_launch Same-workspace skip configure warns on drift Component keep Distinct forced-refresh behavior.
tests/test_managed_config.py::TestInstalledWorkspaceLaunch::test_mismatched_launch_is_refused_before_cache_auth_fetch_or_write[False,True] Refusal precedes refresh side effects Component keep Lower-layer ordering complements CLI entry-point checks.
tests/test_managed_config.py::TestInstalledWorkspaceLaunch::test_installed_workspace_is_the_refresh_source — absent/canonical/trailing-slash/scheme-less workspace Installed identity drives authentication and fetch Component keep Useful identity matrix; profile selection remains asserted.
tests/test_managed_config.py::TestInstalledWorkspaceLaunch::test_foreign_warm_unmanaged_stamp_cannot_bypass_installed_workspace Crafted negative stamp cannot evade guard Component consolidate Merge input/assertion into mismatch-ordering case, which already checks guard-before-cache behavior.
tests/test_managed_config.py::TestInstalledWorkspaceLaunch::test_explicit_configure_can_replace_the_machine_workspace Configure may switch installed workspace Component keep Necessary positive counterpart to refusal.

Removed installation cases

These rows refer to the removed TestMachinePolicyInstall block in tests/test_managed_config.py.

Test / case Behavior protected Layer Needed? Action / rationale
tests/test_managed_config.py::TestMachinePolicyInstall::_stub_token Authentication isolation Fixture remove Replaced by new class fixtures.
tests/test_managed_config.py::TestMachinePolicyInstall::_recording_installer Records simulated install calls Helper remove New writer sentinels/recorders replace it.
tests/test_managed_config.py::TestMachinePolicyInstall::_installed Reads redirected wrapper Helper remove Direct installed-policy readers replace it.
tests/test_managed_config.py::TestMachinePolicyInstall::OTHER_WORKSPACE Foreign workspace input Test data remove No remaining consumer in removed class.
tests/test_managed_config.py::TestMachinePolicyInstall::test_configure_installs_workspace_and_config Exact installed workspace/raw wrapper Component consolidate Persistence shape, install/switch, and integration assertions cover the applicable contract.
tests/test_managed_config.py::TestMachinePolicyInstall::test_unchanged_policy_writes_nothing Retrieval-only change does not reinstall Component consolidate Replaced by stronger unchanged/retrieval-drift sentinels.
tests/test_managed_config.py::TestMachinePolicyInstall::test_changed_policy_is_reinstalled Changed content is actually persisted Component consolidate Transfer explicit stored-config equality into configure reconciliation; hash clearing alone is weaker.
tests/test_managed_config.py::TestMachinePolicyInstall::test_configure_without_policy_removes_the_same_workspaces_policy Same-workspace configure removal Component consolidate Successful-removal and force-option cases replace the path; include forced mode explicitly if transferring the assertion.
tests/test_managed_config.py::TestMachinePolicyInstall::test_configure_without_policy_removes_another_workspaces_policy Configure removes foreign policy Component consolidate Direct replacement is the new foreign-workspace removal case.
tests/test_managed_config.py::TestMachinePolicyInstall::test_feature_disabled_configure_removes_installed_policy Disabled configure successfully deletes policy Component consolidate Add disabled input to successful-removal scenario; no exact replacement currently asserts deletion.
tests/test_managed_config.py::TestMachinePolicyInstall::test_launch_never_writes_the_machine_policy Old blanket launch-write prohibition Component remove Obsolete: root launch refresh may write; non-root restriction has separate coverage.
tests/test_managed_config.py::TestMachinePolicyInstall::test_launch_within_ttl_reads_the_per_user_cache Old normal-platform cache source and replay Component consolidate Source is obsolete; installed TTL and fallback-mode cases cover applicable guarantees.
tests/test_managed_config.py::TestMachinePolicyInstall::test_denied_install_raises_actionable_error Typed configure denial and guidance Component consolidate New failed-install and CLI restoration cases replace it.
tests/test_managed_config.py::TestMachinePolicyInstall::test_denied_removal_raises Configure removal denial raises Component consolidate CLI removal-denial switch case covers the installed-policy journey.
tests/test_managed_config.py::TestMachinePolicyInstall::test_denied_launch_refresh_does_not_raise Failed initial write still yields fetched policy Component consolidate Directly replaced by denied-initial-install case.
tests/test_managed_config.py::TestMachinePolicyInstall::test_platforms_without_machine_policy_never_write[OS.WINDOWS] Windows avoids protected writes Component consolidate New Windows fallback matrix covers the lifecycle more fully.
tests/test_managed_config.py::TestMachinePolicyInstall::test_platforms_without_machine_policy_never_write[OS.OTHER] Other-platform fallback avoids machine writes Component uncertain No explicit replacement input; retain one if OS.OTHER remains a supported compatibility promise.
tests/test_managed_config.py::TestMachinePolicyInstall::test_skip_os_settings_never_writes_the_machine_policy Opt-out avoids protected writes Component consolidate New fallback matrix adds cache-lifecycle assertions.

Revert and recorder adaptations

Test / case Behavior protected Layer Needed? Action / rationale
tests/test_managed_config.py::TestRevertMachinePolicy::test_revert_removes_the_installed_policy Revert removes authoritative policy Component keep Path adaptation retains important behavior.
tests/test_managed_config.py::TestRevertMachinePolicy::test_revert_leaves_the_policy_where_ug_does_not_manage_it[skip_os_settings,windows] Unsupported/opted-out revert leaves policy untouched Component keep Preserves prior assertions through source change.
tests/test_managed_config.py::TestRevertMachinePolicy::test_revert_without_sudo_warns_and_keeps_the_policy Failed revert preserves policy and gives guidance Component keep Necessary denial behavior; path adaptation only.
tests/test_tui_request_recorder.py::_configured_session and nested Session.configure Isolated state/sidecar inputs and command recording Helper keep Bounded extraction shared by two scenarios.
tests/test_tui_request_recorder.py::test_configures_isolated_session_state_for_recorder Configure command, retargeted workspace, copied sidecar, absent-policy no-op Component keep Old user-cache rewrite assertion is intentionally replaced; installed freshness moves to the next case.
tests/test_tui_request_recorder.py::test_retargets_an_installed_policy_to_the_recorder Staging/copy, workspace retargeting, timestamp/fingerprint refresh Component keep Distinct installed-policy branch; fake sudo proves content flow, not real ownership preservation.

The concrete missing regressions are failed authoritative reads during workspace switching and repeated non-root first-launch reads. Existing unit/component scenarios are the smallest suitable place to add them; new live suites are unnecessary. Removed installation assertions should be transferred as noted rather than restoring a separate integration journey.

After those changes, run the focused suites in a prepared environment:

uv run --offline pytest tests/test_managed_config.py tests/test_cli.py tests/test_tui_request_recorder.py

On a disposable machine, also verify that configuring B while its policy read fails leaves A selected, and that two ordinary-user launches within five minutes follow the resolved first-launch throttling contract.

Scope

No clearly unrelated changes were found. Policy persistence, workspace enforcement, configure recovery, harness migration, and documentation support the stated outcome. The first-launch TTL inconsistency is a contract problem within that scope, not a separate feature.


Automated review by Polly · workflow run

@billiam-wang
billiam-wang marked this pull request as ready for review October 23, 2026 04:07
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