Skip to content

_v1: support running a task without the session environment (embedded files + Task.File resolution) #332

Open

Description

@seant-aws

Use case

The deadline-cloud-worker-agent runs its job-attachment sync scripts as OpenJD tasks outside the session environment (use_session_env_vars=False) so that job environments (e.g. a conda virtual environment) cannot interfere with them.

What v0 provides

On the v0 openjd.sessions.Session path this capability lives inside the library: StepScriptRunner materializes the script's embedded files via write_file_for_user (handling both POSIX permissions and Windows ACLs) and resolves {{ Task.File.* }} references through the format-string engine against the session's symbol table.

The gap in _v1

The _v1 wrapper exposes:

  • run_task(...) — full embedded-file and format-string handling, but no way to opt out of the session environment
  • run_subprocess(...) — opts out of the session environment, but internally builds a StepScript with embeddedFiles=None and performs no format-string substitution

A caller that needs both must therefore reimplement embedded-file materialization and Task.File.* resolution itself.

Current stopgap

aws-deadline/deadline-cloud-worker-agent#1002 carries this reimplementation in its RustSessionRuntime adapter (a port of the attachment-sync recipe from the bindings-rs prototype: aws-deadline/deadline-cloud-worker-agent@mainline...mwiebe:deadline-cloud-worker-agent:bindings-rs).

Known limitation of doing this outside the library, which write_file_for_user already solves: no Windows ACL grant is applied to the materialized files, so an impersonated Windows job user cannot read them.

Proposal

Expose the capability in the _v1 wrapper (or the underlying crate) — e.g. run_task(..., use_session_env_vars=False) — so adapters can delegate, keeping embedded-file materialization and format-string resolution in one place across both implementations.

Activity

  1. seant-aws commented on Aug 5, 2026

    @seant-aws
    ContributorAuthor

    Closing. The reimplementation in the worker agent's RustSessionRuntime adapter (aws-deadline/deadline-cloud-worker-agent#1002) has proven stable — it's exercised by differential integration tests running the attachment-sync path on both the v0 and _v1 runtimes, and no divergence has surfaced since it merged. Given zero demand from other consumers, maintaining ~60 lines in the one caller that needs it is cheaper than adding and supporting a new library capability.

    One caveat for future readers: the known limitation vs. v0's write_file_for_user — Windows ACL handling on materialized embedded files — is currently moot because the _v1/Rust runtime is only used on POSIX. If the Rust runtime is ever enabled on Windows, this should be reopened (or the ACL handling added to the adapter) before attachment-sync runs there.

  2. leongdl commented on Aug 6, 2026

    @leongdl
    Contributor

    Requesting a re-look at this, based on two things found after it was closed.

    1. The "POSIX-only" premise isn't enforced anywhere.

    The closing note treats the missing Windows ACL handling as moot because the _v1/Rust runtime
    only runs on POSIX. Nothing in the worker agent enforces that. select_runtime
    (src/deadline_worker_agent/sessions/runtime/_select.py) is explicit:

    if configured_kind == SessionRuntimeKind.RUST:
        return SessionRuntimeKind.RUST
    # There is intentionally no capability check, escalation, or fallback here.

    No platform gate. A Windows worker with session_runtime = rust selects the Rust runtime, and
    attachment-sync then materializes embedded files that an impersonated Windows job user cannot read.
    aws-deadline/deadline-cloud-worker-agent#1040 adds --session-runtime=rust plus
    WORKER_AGENT_SESSION_RUNTIME and a hatch run e2e:test-rust script, and DEVELOPMENT.md documents
    Windows e2e infra — so the configuration that trips this is now one flag away. POSIX-only is a
    convention, not an invariant.

    2. The reimplementation has already drifted.

    PR #1040 patches {{ Task.File.* }} resolution into the adapter's command handling — the args
    path had it, command did not. That is one day after the adapter was described here as stable and
    differentially tested, which suggests the differential tests don't cover an attachment-sync script
    whose command is itself a Task.File reference.

    3. The API change is small, because the crate already does all of it.

    Session::run_task (openjd-rs crates/openjd-sessions/src/session.rs:1592) hardcodes:

    // :1619
    let env_vars = self.evaluate_env_vars(os_env_vars);

    run_subprocess in the same file (:1786, branch at :1814) already has exactly the opt-out
    branch needed. Extracting that into a shared helper and adding use_session_env_vars: bool to
    run_task is the whole core change. Everything else the adapter reimplements is already reached by
    run_task:

    • StepScriptRunner::run (runner/step_script.rs:111) → EmbeddedFiles::allocate_file_paths
      registers the Task.File.* symbols (embedded_files.rs:34), then write_file_contents.
    • run_action (runner/mod.rs:142) → resolve_action_args (:461) resolves command as args[0]
      through the real format-string engine, with the function library.
    • EmbeddedFiles::with_user → chown_for_user, which has both a POSIX branch
      (embedded_files.rs:102) and a #[cfg(windows)] branch (:141) calling
      win32_permissions::set_permissions — i.e. the ACL handling the adapter lacks already exists.

    Proposed layering, all backwards compatible:

    1. openjd-rs: run_task(..., use_session_env_vars: bool); extract the env branch from
      run_subprocess into a private helper.
    2. rust-bindings (openjd-model-for-python/rust-bindings/src/sessions/session.rs:554): add the
      param to the #[pyo3(signature = ...)] and forward, mirroring run_subprocess below it.
    3. _v1/_session.py: run_task(..., use_session_env_vars: bool = True), forwarded.
    4. Worker agent: _run_task_without_session_env collapses to a run_task call with
      use_session_env_vars=False — the tempfile loop, chmod/chown, and both regexes delete.

    Happy to carry all four if this is worth reopening.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions