Skip to content

feat(desktop): add Linux systemd --user service integration - #2471

Open
CX33071 wants to merge 22 commits into
oceanbase:masterfrom
CX33071:feat/desktop-linux-08e
Open

CX33071 wants to merge 22 commits into
oceanbase:masterfrom
CX33071:feat/desktop-linux-08e

Conversation

@CX33071

@CX33071 CX33071 commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Which issue or RFC does this PR close?

Related to #2110
This PR implements the 08-E Linux personal service integration workstream. It does not close #2110 because that issue covers the complete optional Linux integration, including the already merged 08-A and 08-B workstreams.

Rationale for this change

Linux Desktop needs a safe and user-scoped way to provision and manage the local PowerContext Server.
This change integrates the shared structured Installer/Ops contracts with Linux systemd --user, while preserving controller ownership, explicit-stop semantics, user-session lifetime, and the existing Windows/macOS behavior.
The integration does not install system-wide services, require root privileges, or silently enable persistent services across logouts.

What changes are included in this PR?

  • Add Linux personal service integration through systemd --user.
  • Reuse the shared structured Installer/Ops lifecycle contracts.
  • Support trusted inspection, preflight, installation, start, stop, restart, removal, and recovery operations.
  • Use only user-scoped systemd units under the current user session.
  • Prevent creation or modification of system-level units.
  • Never call loginctl enable-linger.
  • Preserve existing linger configuration instead of changing it.
  • Preserve explicit-stop semantics.
  • Keep Desktop exit separate from stopping the local Server.
  • Prevent operations from affecting unrelated user services.
  • Add Linux lifecycle behavior for unavailable user service managers.
  • Add handling for damaged or missing managed runtime resources.
  • Add qualified managed-resource bundle generation and integrity verification.
  • Require trusted resource manifests, file hashes, and validated runtime metadata.
  • Preserve private and immutable managed-resource copies.
  • Connect the structured lifecycle operations to the Linux Desktop UI and typed IPC.
  • Display structured service state, operation progress, failures, and recovery information.
  • Keep renderer input restricted to fixed typed operations without arbitrary commands or paths.
  • Document Linux login/logout behavior, user-session lifetime, systemd unit locations, and the absence of root/system-wide installation.
  • Pin the native Linux service workflow to Ubuntu 24.04.
  • Extend managed-resource candidate validation for qualified Linux Ops bundles.
  • Correct the Desktop workflow test-step naming.
  • Add Rust, frontend, IPC, managed-resource, and native Linux lifecycle regression tests.

Are there any user-facing changes?

Yes.
On supported Ubuntu 24.04 Linux Desktop environments, users can manage the local PowerContext Server from the Desktop settings UI.
The service is managed only within the current user session. Desktop exit does not silently stop the Server, and the application does not enable system-wide persistence or modify the user's existing linger configuration.
The feature requires a qualified local PowerContext runtime. Missing or damaged runtime resources produce structured actionable failures without affecting remote Server operations.
No public Server API or persisted data format is changed.

How was this change tested?

Local validation:

  • cargo test --locked --manifest-path desktop/src-tauri/Cargo.toml
  • cargo clippy --locked --manifest-path desktop/src-tauri/Cargo.toml --all-targets -- -D warnings
  • cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --check
  • pnpm --dir desktop lint
  • pnpm --dir desktop typecheck
  • pnpm --dir desktop test
  • pnpm --dir desktop build
  • git diff --check
  • Full Python unit tests with four pytest workers and local proxy variables removed:7706 passed, 346 skipped

Real Linux systemd validation:

  • 12 Linux personal-service lifecycle tests passed.
  • Tests covered user-scoped registration, start/stop, removal, recovery, explicit stop, unavailable user manager behavior, existing linger preservation, unrelated-service protection, and system-unit protection.
  • Upgrade migration cases requiring the CI-provided PowerContext 1.3.0 source runtime are executed by the native-service workflow.

Fork CI validation:

  • Desktop validation passed on Windows.
  • Desktop validation passed on Ubuntu 24.04 Linux.
  • Desktop validation passed on macOS Apple Silicon.
  • Desktop validation passed on macOS Intel.
  • The Main workflow was run with automatic upgrade selection. The full upgrade selection is not applicable to this development-version branch because the target version does not follow the required ordering after PowerContext 1.3.0.

AI usage statement

This PR was developed with OpenAI Codex powered by GPT-5. The generated changes were reviewed, tested locally on Ubuntu 24.04, and validated through the fork's GitHub Actions workflows.

@PsiACE PsiACE left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Two supported Linux paths remain blocked.

Comment on lines +36 to +37
- target: linux-x86_64
runner: ubuntu-24.04

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The new Linux candidate fails on the locked CPython archive: extract_runtime() rejects its casefold-colliding terminfo paths (reproduced with the real, hash-verified archive; also fails in CI). After extraction, _server_probe, ResourceSpec.platform and ManagedLayout.current_user still exclude Linux. Please complete the producer/consumer path before enabling this target.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this.
Linux resource handling now preserves case-sensitive paths, so real interpreter archives with paths such as TermInfo and terminfo are accepted. Windows and macOS keep their existing case-insensitive validation.
I also completed the Linux producer/consumer path by adding Linux support to ResourceSpec.platform, resource extraction, current-platform selection, _server_probe, and ManagedLayout.current_user() with XDG locations. Regression tests cover case-distinct Linux paths and the Linux managed layout.

}
pub fn binding(&self) -> Result<Binding, Error> {
if !cfg!(any(windows, target_os = "macos")) {
if !cfg!(any(windows, target_os = "macos", target_os = "linux")) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Enabling Linux exposes a broken session environment: launch() supplies only HOME/PATH/TMPDIR, then process::run() calls env_clear(). On a real systemd user session, systemctl --user show-environment succeeds normally, fails with this exact allowlist, and succeeds again with XDG_RUNTIME_DIR restored. Desktop therefore reports an available user manager as unsupported. Please preserve or safely derive the required session/XDG values in the trusted native layer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this.
The trusted Linux helper environment now preserves XDG_RUNTIME_DIR after validating that it is an absolute, non-symlink directory owned by the current user with private permissions. If it is not set, the trusted layer safely derives /run/user/<uid> when valid.
A regression test covers both the valid private runtime directory and rejection of unsafe permissions. The existing fixed environment allowlist remains in place; arbitrary renderer or process environment variables are not forwarded.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] The runtime-dir fix restores user-manager access, but launch() still drops XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME, and XDG_CACHE_HOME before env_clear(). On 911d6f8, I used the actual Trust::launch() environment with a real Ops subprocess: the same owned unit under a custom XDG_CONFIG_HOME changes from registration: installed to not_installed. ManagedLayout.current_user() also switches its program, configuration, data, cache, and journal paths back to the HOME defaults. Please preserve validated XDG home locations through this boundary and cover a non-default layout, so Desktop inspects/manages the same installation as the CLI.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this.
The trusted Linux launch environment now preserves validated XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME, and XDG_CACHE_HOME in addition to XDG_RUNTIME_DIR. Absolute paths without parent-directory traversal are accepted; invalid paths are rejected instead of silently falling back to $HOME.
This keeps ManagedLayout.current_user() consistent with the CLI for non-default XDG layouts. I also added regression coverage for the non-default layout and invalid path handling. Rust and Python focused tests pass locally.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] The non-default layout now round-trips correctly on 2e168b1, but empty XDG values introduce a regression. With XDG_CACHE_HOME="" (likewise any of the other three home variables), Trust::launch() returns Unavailable before starting Ops; leaving it unset succeeds. I reproduced this against the actual Rust trust layer and confirmed the previous head accepts the same empty value. ManagedLayout.current_user() already treats empty as unset, as required by the XDG specification. Please skip empty values before the absolute-path check so a valid default-layout session can still inspect/manage its service.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verified on c5b9a19a: the reported session-environment gap is closed, and the empty-value regression from 2e168b1a is gone.

  • launch() now inserts XDG_RUNTIME_DIR after validating it through trusted_linux_runtime_dir() — absolute, non-symlink directory, matching uid, mode & 0o077 == 0, with /run/user/<uid> as the derived fallback (desktop/src-tauri/src/ops_bridge/trust.rs:304-309, trust.rs:325-347).
  • The four home variables survive env_clear() through trusted_linux_xdg_environment() (trust.rs:351-380).
  • Empty values are dropped before the absolute-path check (trust.rs:369-372), so XDG_CACHE_HOME="" returns an environment instead of Unavailable; linux_xdg_home_environment_preserves_a_non_default_layout (desktop/src-tauri/src/ops_bridge/tests.rs:978-1018) now asserts the all-empty map yields an empty environment, and linux_runtime_environment_is_preserved_only_for_a_private_owned_directory (tests.rs:957-975) covers the 0o755 rejection and the unset/empty equivalence.

One residual asymmetry, which is not the original defect: an absolute value containing .. still returns Err(Error::Unavailable) (trust.rs:374-377), while trusted_linux_runtime_dir_from treats the same shape as ignore (returns None, trust.rs:327-333) and the XDG specification says to ignore. Because launch() propagates the error, a single ..-bearing XDG home keeps Local Server unavailable — the same outcome class this thread was about, for a rarer input. That branch is also the only untested one: relative and empty values are covered, .. is not.

@AlexStocks AlexStocks added the 1.5.1 v1.5.1 release tracking label Nov 5, 2026

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Rechecked 6b2f53bd: the custom-XDG layout and empty-XDG failures are fixed. The native trust layer now preserves configured locations and treats empty values as unset; I found no new correctness issue in the changed paths.

Merge validation is still incomplete. The Python 3.13 unit job fails with ProcessLookupError while _process_identity() reads /proc/<pid>/stat in test_upgrade_command_owner_finishes_cleanup_after_gate_cancellation[parent-term]. That test is unchanged from the base, so this appears to be an existing test race rather than a defect introduced here. Desktop, native-service and managed-resource-candidate validation were consequently skipped. Please obtain a successful run including those checks before merging.

@knqiufan knqiufan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please keep the optional Linux candidate from blocking the required Windows/macOS pipeline.

fail-fast: false
matrix:
include:
- target: linux-x86_64

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2] Keep the optional Linux candidate outside the required aggregate

Adding Linux to this shared matrix makes a Linux-only failure fail the candidate workflow and therefore the Main CI aggregate. The aggregation script returns failure for that simulated result. This conflicts with #2112's explicit requirement that an optional Linux failure must not block mandatory Windows/macOS checks. Please isolate the Linux result so its failure remains visible without failing the required aggregate.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Confirmed on 6b2f53bd. The CI rerun is now green, including the Linux candidate, but the optional-failure handling remains incorrect. Running the actual ci-result script with modeled job results succeeds when all jobs succeed and exits 1 with CI checks did not succeed: {'managed-resource-candidates': 'failure'} when that workflow alone fails. The new Linux matrix member has no failure isolation, so a Linux-only failure reaches this required aggregate even when Windows/macOS succeed. Please keep that failure visible while preserving the required-platform-only outcome specified in #2112.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this.
I isolated the optional Linux candidate from the required aggregate. The required managed-resource-candidates call now runs only Windows and macOS targets and remains in ci-result.needs.
Linux runs through a separate managed-resource-candidates-linux call. Its diagnostics and artifacts remain visible, but it is intentionally excluded from the required aggregate, so a Linux-only failure cannot block the required Windows/macOS pipeline.
I also added regression tests covering the target split and terminal CI result behavior. The focused CI tests pass locally.

@hidb4ai hidb4ai removed the 1.5.1 v1.5.1 release tracking label Nov 9, 2026
@AlexStocks AlexStocks added the 1.6.0 v1.6.0 release tracking label Nov 9, 2026

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The target split is correct, but the two calls still share a cancellation group. The current run has already cancelled the required candidate workflow.

${{ !cancelled() && needs.quality.result == 'success' &&
contains(fromJSON('["success","skipped"]'), needs.tests.result) &&
(fromJSON(needs.quality.outputs.suites || '{}').managed_resources) }}
uses: ./.github/workflows/managed-resource-candidates.yml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Give the required and optional callers separate concurrency groups

Both calls inherit managed-resource-candidates-${{ github.event.pull_request.number || github.ref }}-${{ github.event_name }} with cancel-in-progress: true, so they cancel each other despite the target split. On 24018fb0, the required selector job is already cancelled with the annotation Canceling since a higher priority waiting request for managed-resource-candidates-2471-pull_request exists; its candidate matrix is cancelled too. Please distinguish the two callers in the concurrency key so optional Linux cannot preempt the required Windows/macOS qualification.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this.
The required and optional callers now use separate concurrency groups. The required Windows/macOS caller passes concurrency_suffix: required, while the optional Linux caller passes concurrency_suffix: linux. The suffix is included in the reusable workflow’s concurrency key, so the Linux run can no longer cancel the required candidate run.
I also added regression assertions for the two caller-specific groups. The focused CI tests pass locally.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2 resolved at c5b9a19] The two callers now use distinct concurrency keys: the reusable group is managed-resource-candidates-<pr|ref>-<event>-<concurrency_suffix|default>, and master.yml passes concurrency_suffix: required for the windows/macos caller and concurrency_suffix: linux for the optional Linux caller. A Linux run can no longer cancel the required selection. Both callers still share github.event.pull_request.number || github.ref with cancel-in-progress: true, so a re-run of the same caller still supersedes its own earlier run, which is the intended behaviour.

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-reviewed d52ec006. The required and optional resource callers now use separate concurrency groups, and all four candidate targets completed successfully on this head. The earlier XDG and optional-platform findings are addressed; I found no remaining correctness issue introduced by this PR. No new product API or database table is added.

The overall CI result is still red for OpenDAL typing and SQLite/OceanBase acceptance failures in unchanged paths. This code approval does not override those CI gates or the remaining review requirements.

@CX33071
CX33071 requested review from PsiACE and knqiufan November 10, 2026 15:56
@CX33071

CX33071 commented Nov 10, 2026

Copy link
Copy Markdown
Contributor Author

The four red checks reduce to three unrelated CI issues:

  • OpenDAL typing fails at source.py:160 with ty reporting discarded Pydantic arguments. This path was not changed by this PR, and local make opendal-test passes.
  • SQLite acceptance fails because the ACP runner cannot import text_block from the installed acp package.
  • OceanBase acceptance executes all 22 tests successfully, but the step exceeds the 50-minute timeout.

The Linux Desktop, systemd-user, and all managed-resource candidate checks pass.

@hireview001 hireview001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@CX33071

CX33071 commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

The only remaining failure is the unchanged dsh-package runtime test:setup validates native include trees observed by a real DSH startup.
All 08-E checks pass, including Linux Desktop, systemd --user lifecycle,Linux managed-resource qualification, and the required Windows/macOS candidate checks.
I cannot rerun the failed job because GitHub requires repository admin permission for rerunning this workflow. Could you please rerun the failed jobs or advise whether this baseline DSH failure should be tracked separately?

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-reviewed dcf60c39. The master merge preserves the reviewed Linux changes, including XDG handling and separate concurrency groups for required and optional candidates. I found no new correctness defect introduced by this PR. No new product API or database table is added.

CI remains blocked by the DSH runtime setup test. Its code and job are unchanged from the base; I found no evidence connecting that failure to this PR. Linux Desktop, real systemd-user lifecycle, and all four managed-resource candidates passed on this head. This approval does not override the failing CI gate or other outstanding reviews.

@hireview001 hireview001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • Resolve merge conflicts with the target branch.
  • CI failed: CI result (failure).
  • CI failed: dsh-package (failure).
  • CI failed: Main (failure).

@hidb4ai hidb4ai left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Re-reviewed ed2a2332. I found no new runtime correctness defect in the merge. One non-blocking documentation inconsistency remains below.

Current-head CI qualification is incomplete: the macOS ARM Desktop job was cancelled before acquiring a hosted runner. GitHub reports runner capacity constraints; this is not a demonstrated code regression. A successful run is still required.

Comment thread desktop/VALIDATION.md Outdated
uv run --no-sync pytest -q tests/native/test_personal_service_lifecycle.py
```

The Desktop page currently performs a read-only status inspection through `ops.inspect`; it does not install, start, stop or restart a service. The product uses the current user's `systemctl --user` manager and does not enable linger, write system units or require root. A passing Rust, lifecycle or candidate-bundle test does not by itself qualify a signed package or a normal user's login-session configuration.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P3] Update the obsolete read-only UI description

After the master merge, LocalServerSettings exposes install, repair, start, stop and restart, and useLocalServer.execute() dispatches the approved plan through opsApi.apply(). With a valid Linux binding, the page is therefore no longer limited to ops.inspect. Please distinguish the read-only inspection from the explicitly approved lifecycle operations here, while retaining the existing limits on installed-session and signed-package qualification.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this.
I updated desktop/VALIDATION.md to distinguish read-only status inspection through ops.inspect from explicitly approved lifecycle plans dispatched through ops.apply. The documentation now covers install, repair, start, stop, and restart for a valid Linux binding.

@knqiufan knqiufan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address the two blocking findings before merging: keep Local Server operations available when an XDG home variable contains a relative path, and preserve the existing Linux Server CLI lifecycle gate. The Rust toolchain and README findings are non-blocking.

.components()
.any(|component| matches!(component, Component::ParentDir))
{
return Err(Error::Unavailable);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2 · Blocking] Ignore relative XDG home paths instead of disabling Local Server

With XDG_CACHE_HOME=relative-cache, this validation returns Unavailable before the Ops helper starts, so even read-only inspection fails despite a valid binding and an available user manager. I reproduced the rejection in this Rust helper and confirmed that ManagedLayout.current_user() in src/powercontext/ops/installer.py also rejects the same input. The XDG Base Directory Specification says to ignore relative values. Please use the default directory for relative values at both boundaries while preserving valid absolute overrides.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2 partially resolved at c5b9a19] Relative values are now ignored at both boundaries as requested: trusted_linux_xdg_environment_from skips a non-absolute XDG_* value (continue), so the helper starts with the platform defaults, and ManagedLayout.current_user() keeps its fallback for the same input. The new linux_xdg_home_environment_preserves_a_non_default_layout test asserts that XDG_CONFIG_HOME=relative/config is absent from the forwarded environment.

One residual difference remains for an absolute value that contains .., e.g. XDG_CONFIG_HOME=/home/u/x/../.config: trusted_linux_xdg_environment_from returns Error::Unavailable, which fails the whole launch, while ManagedLayout.current_user() treats the same value as unusable and falls back to ~/.config. So the read-only inspection is unavailable through the bridge for an environment the Python consumer would have accepted with the default layout. If the intent is "never disable Local Server for an unusable XDG value", skipping that value here would match installer.py; if the intent is to fail closed on any traversal segment, the two boundaries should agree.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2 · Still blocking] The Rust bridge now drops relative XDG home values, but the managed installer still reads a relative XDG_DATA_HOME when choosing the Server data directory. On c5b9a19a, I ran the managed install preflight with a simulated service manager and XDG_DATA_HOME=relative-data. Preflight succeeded, but target_summary.data_dir was <cwd>/relative-data/powercontext. With the variable unset or empty, the same preflight returned $HOME/.local/share/powercontext, which is also the expected path for a relative value.

ManagedLayout.current_user() uses the validated fallback for the managed program directory, but calls default_data_dir() separately for Server data, which reads the original environment again. Please use the validated XDG data base for the Server data directory too, and cover target_summary.data_dir in the regression test while preserving valid absolute overrides.

Comment thread .github/workflows/native-service.yml Outdated
runs-on: ubuntu-latest
# Linux native service qualification is optional under #2112; do not make
# it block the required macOS and Windows service checks.
continue-on-error: true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P2 · Blocking] Keep the existing Linux Server CLI lifecycle gate required

This job already tests the supported powercontext service lifecycle against a real systemd --user manager. Applying continue-on-error to the whole job means a Linux CLI regression can now leave Main's required CI result green when the other platforms pass. Please preserve the pre-existing CLI gate and apply the optional policy only to the new Linux Desktop qualification.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2 resolved at c5b9a19] This job no longer carries continue-on-error: linux-systemd-user (native-service.yml, ubuntu-24.04, POWERCONTEXT_RUN_NATIVE_SERVICE_TESTS=1) is a plain required job again, so a Linux CLI lifecycle regression still fails the aggregate. The optional policy now lives only on desktop.yml's linux job (continue-on-error: true).

Consequence worth stating for the record: that optional job is also the only place the newly Linux-enabled Rust suites run (#[cfg(all(test, any(target_os = "macos", target_os = "linux")))] in ops_bridge, plus the linux-only tests in ops_bridge/tests.rs). Under #2112 their results are advisory, so a Linux-only regression in the Ops Bridge still leaves Main green. That is consistent with the stated policy, not a request to change it.

{
echo "bundle=$POWERCONTEXT_OPS_TEST_BUNDLE"
echo "bundle_manifest_sha256=$POWERCONTEXT_OPS_TEST_BUNDLE_SHA256"
CARGO_BUILD_JOBS=2 cargo test --locked --manifest-path desktop/src-tauri/Cargo.toml --lib actual_independent_bundle_runs_through_native_trust_and_read_only_bridge -- --ignored

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3 · Non-blocking] Select the pinned Rust toolchain for the candidate test

This step runs cargo from the repository root. --manifest-path does not make rustup discover desktop/rust-toolchain.toml; I verified that the root selected the default toolchain, while desktop/ selected 1.95.0. Please select 1.95.0 explicitly or run the command from desktop/ so the test actually uses the toolchain installed above.

Comment thread desktop/README.md Outdated

On Linux, the Local Server settings page can inspect the PowerContext user service through the trusted Ops Bridge. This check is read-only: it reports supported, registration, ownership, manager, liveness, readiness and maintenance status, while keeping paths, commands, environment values and raw process output out of the UI.

The bridge only addresses PowerContext's registered service target and rejects untrusted windows, remote origins and arbitrary renderer input. A missing or unavailable local service does not disable remote Server connections. This workstream does not add install, start, stop or restart controls; those mutations remain in the service-management boundary and must use the same ownership and approval rules.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P3 · Non-blocking] Describe the approved lifecycle actions in both READMEs

With a valid Linux binding, Local Server settings already offers install, repair, start, stop, and restart; approved plans go through ops.apply. This paragraph and its counterpart in desktop/README.zh.md still say the controls are absent. Please align both READMEs with desktop/VALIDATION.md: inspection is read-only, and lifecycle operations require explicit approval.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the detailed review. All four findings have been addressed.

  • Relative XDG home values are now ignored and fall back to the default directories in both the trusted Rust launch environment and ManagedLayout.current_user(). Valid absolute overrides are still preserved.
  • The existing Linux Server CLI lifecycle gate is required again. Optional handling remains limited to the new Linux Desktop qualification job.
  • The Linux managed-resource native Ops test now explicitly runs with Rust 1.95.0.
  • Both English and Chinese Desktop READMEs now distinguish read-only ops.inspect from explicitly approved lifecycle plans dispatched through ops.apply, including install, repair, start, stop, and restart.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.6.0 v1.6.0 release tracking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(desktop): implement optional Linux native integration

6 participants