Skip to content

feat(jobs): add auth-aware E2E tests and job diagnostics infrastructure - #398

Merged
ironcommit merged 1 commit into
mainfrom
auth-tests-2/rsadler
Jun 23, 2026
Merged

feat(jobs): add auth-aware E2E tests and job diagnostics infrastructure#398
ironcommit merged 1 commit into
mainfrom
auth-tests-2/rsadler

Conversation

@ironcommit

@ironcommit ironcommit commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Add auth-aware E2E tests that validate workspace isolation and principal propagation under an auth-enabled platform config. Introduce a reusable diagnostics module for structured job/step/task state collection on errors, and fix a workspace-scoping bug in list_tasks.

Changes

Auth-aware E2E test suite (e2e/test_jobs_auth.py)

  • Principal propagation: verifies a user with workspace Editor role can submit a job and read its output fileset
  • Workspace isolation: verifies a user cannot access filesets in a workspace they lack permissions for (expects 403)
  • Admin cross-workspace listing: verifies an admin can list jobs across all workspaces

Per-module platform config support (e2e/conftest.py)

  • Refactor E2E fixtures to support multiple running-services instances keyed by config hash, enabling per-test-module platform configs (e.g., auth-enabled) to coexist in a single session
  • Add pytest.mark.e2e_config(...) marker for declaring ordered config file layers and inline dict overlays per test module
  • Replace the session-scoped _services fixture with a module-scoped _services_instance backed by a session-scoped pool
  • Remove the nemo_run fixture; replace with run_nemo_local from nmp.testing

Job diagnostics module (services/core/jobs/.../controllers/diagnostics.py)

  • collect_job_diagnostics(): fetches job, step, task, status, and log data via the SDK and returns a structured dict
  • log_job_diagnostics_if_debug(): conditionally emits diagnostics at DEBUG level
  • Wired into the reconciler and scheduler to automatically log diagnostics when steps transition to ERROR or encounter unexpected exceptions

Bug fix: workspace-scoped task listing

  • Pass workspace through dispatcher.list_tasks() to store.list() so task queries for non-default workspaces return correct results
  • Added integration test reproducing the bug (test_list_tasks_uses_step_workspace_for_non_default_jobs)

Type safety improvements in scheduler/reconciler

  • Use typed PlatformJobStepsListFilterParam and SDKPlatformJobStatus instead of raw dicts/strings
  • Pass .value for enum status fields to match SDK expectations
  • Add assert step.step_spec is not None guard before accessing executor

Other

  • New e2e/configs/local-subprocess.yaml E2E config (runtime: none, subprocess executor)
  • run_nemo_local now accepts base_url and workspace keyword arguments
  • Registered e2e_config as a custom pytest marker in pytest.ini
  • Refactored test_task_auth_runtime.py to use a Protocol-based task stub returning the secret value directly instead of capturing stdout

Summary by CodeRabbit

  • Bug Fixes
    • Fixed job task listing to respect workspace boundaries end-to-end by scoping task retrieval to the current workspace.
    • Improved local subprocess job synchronization when subprocess metadata arrives late (grace period for recent pending steps).
  • New Features
    • Added include_job_logs_in_diagnostics to optionally include raw job logs in controller diagnostics.
    • Added local subprocess-based E2E configuration with per-test config layering and pooled service startup by effective config.
    • Added authenticated E2E job coverage (job principal propagation, forbidden workspace access, admin listing across workspaces).
  • Tests
    • Expanded diagnostics, scheduler/reconciler, dispatcher scoping, and subprocess backend test coverage.

@ironcommit
ironcommit requested review from a team as code owners June 23, 2026 00:52
@github-actions github-actions Bot added the feat label Jun 23, 2026
@ironcommit
ironcommit force-pushed the auth-tests-2/rsadler branch 2 times, most recently from 7fc1e79 to 224fc1e Compare June 23, 2026 00:56
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds workspace-scoped task listing to JobDispatcher.list_tasks and its API endpoint, introduces a diagnostics.py module for job/step snapshot collection integrated into JobScheduler and JobReconciler, adds a local subprocess E2E config with per-module config-hash pooling in conftest, extends run_nemo_local for platform URL injection, improves subprocess backend grace-period handling for missing metadata, and adds three auth-gated E2E job tests.

Changes

Job Auth E2E and Diagnostics

Layer / File(s) Summary
Workspace-scoped list_tasks
services/core/jobs/src/nmp/core/jobs/app/dispatcher.py, services/core/jobs/src/nmp/core/jobs/api/v2/jobs/endpoints.py, services/core/jobs/tests/test_dispatcher_cross_workspace.py
list_tasks now requires workspace and passes it to the store; endpoint forwards the request workspace; cross-workspace tests updated and extended for non-default workspace.
Job diagnostics module
services/core/jobs/src/nmp/core/jobs/config.py, services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py, services/core/jobs/tests/controllers/test_diagnostics.py
New JobDiagnosticTarget protocol, collect_job_diagnostics (multi-endpoint snapshot with per-call error isolation and optional job logs), log_job_diagnostics_if_debug (DEBUG-gated emission), and config flag include_job_logs_in_diagnostics.
Diagnostics in scheduler
services/core/jobs/src/nmp/core/jobs/controllers/scheduler.py, services/core/jobs/tests/controllers/test_scheduler.py
Stores self._logger, calls log_job_diagnostics_if_debug in error paths, switches to typed PlatformJobStepsListFilterParam, asserts step_spec is not None, adds conflict-handling helper for stale PENDING updates; tests validate diagnostics emission and conflict handling.
Diagnostics in reconciler
services/core/jobs/src/nmp/core/jobs/controllers/reconciler.py, services/core/jobs/tests/controllers/test_reconciler.py
Stores self._logger, calls log_job_diagnostics_if_debug on error state transitions and exceptions, types status list as SDKPlatformJobStatus, switches to typed filter params; test validates diagnostics emission on error transition.
Subprocess backend grace period
services/core/jobs/src/nmp/core/jobs/controllers/backends/subprocess.py, services/core/jobs/tests/controllers/test_subprocess_backend.py
Tolerates temporarily missing subprocess metadata for PENDING steps via grace-period constant, implements fallback task lookup, detects staleness using step timestamps, and provides test coverage for active and pending fallback scenarios.
Task auth integration test refactor
services/core/jobs/tests/integration/test_task_auth_runtime.py
Replaces ModuleType-based secret task with a typed _SecretAccessTask Protocol; test assertions move from stdout capture to returned secret value.
run_nemo_local URL and workspace injection
packages/nmp_testing/src/nmp/testing/utils.py, packages/nmp_testing/src/nmp/testing/__init__.py
Adds optional base_url and workspace parameters that inject NMP_BASE_URL and NMP_WORKSPACE into subprocess environment.
Local subprocess E2E config and marker
e2e/configs/local-subprocess.yaml, pytest.ini, docs/set-up/config-reference.mdx
New no-Docker YAML config with subprocess executor, disabled auth (unsigned JWT allowed), local storage, and logs-in-diagnostics enabled; e2e_config marker registered for config resolution and pooling; docs updated.
Per-module config-hash pooling harness
e2e/conftest.py
Refactors conftest to resolve e2e_config marker layers, deep-merge configs, compute canonical hash, pool nemo services run processes per hash, derive auth enablement from effective config, and poll /status endpoint for readiness.
Auth E2E tests and module markers
e2e/test_jobs_auth.py, e2e/test_jobs.py, e2e/test_data_designer.py
Three new auth tests: principal propagation, cross-workspace access denial (403), admin ALL_WORKSPACES listing; existing modules updated to use e2e_config marker and run_nemo_local.

Sequence Diagram

sequenceDiagram
  participant Test as E2E Test Module
  participant Services as Pooled Services
  participant Auth as Auth Subsystem
  participant Dispatcher as JobDispatcher
  participant Diagnostics as Diagnostics Logger
  Test->>Services: request base_url (config pooled by hash)
  alt auth_enabled in config
    Services-->>Test: base_url + requires auth headers
    Test->>Auth: generate unsigned JWT
    Test->>Test: inject Authorization header
  else auth disabled
    Services-->>Test: base_url
  end
  Test->>Dispatcher: list_tasks(step_id, workspace=workspace)
  Dispatcher-->>Test: scoped tasks
  Test->>Services: submit job with workspace context
  alt job fails
    Services->>Diagnostics: log_job_diagnostics_if_debug(context)
    Diagnostics-->>Services: snapshot (status, steps, tasks, logs)
  end
Loading

Possibly related PRs

  • NVIDIA-NeMo/nemo-platform#377: Adds principal propagation and NMP_PRINCIPAL environment variable handling in job task execution to test get_task_sdk(...).secrets.access(...) with on-behalf-of semantics.
  • NVIDIA-NeMo/nemo-platform#393: Updates E2E harness service readiness probing to use GET {base_url}/status endpoint, overlapping with this PR's services startup refactor.

Suggested reviewers

  • mckornfield
  • crookedstorm
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title accurately summarizes the main change: adding auth-aware E2E tests and job diagnostics infrastructure to the jobs service.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch auth-tests-2/rsadler

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
services/core/jobs/tests/integration/test_task_auth_runtime.py (1)

33-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a concrete type for http_client in the protocol and implementation.

http_client is currently untyped, which weakens static checks for this helper.

Proposed change
+import httpx
 from typing import Protocol

 class _SecretAccessTask(Protocol):
-    def run(self, *, http_client) -> str: ...
+    def run(self, *, http_client: httpx.Client) -> str: ...
@@
     class _Task:
         `@staticmethod`
-        def run(*, http_client) -> str:
+        def run(*, http_client: httpx.Client) -> str:

As per coding guidelines, **/*.py: "Always prefer concrete type hints over string-based ones in Python code; do not import types under TYPE_CHECKING, instead import types as regular imports when possible".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/jobs/tests/integration/test_task_auth_runtime.py` around lines
33 - 40, The `http_client` parameter in both the `_SecretAccessTask` protocol's
`run` method and the `_Task` class's `run` method in
`_secret_access_task_module` function lacks a concrete type hint. Add a concrete
type annotation to the `http_client` parameter in both locations using the
appropriate HTTP client type. Import the HTTP client type as a regular import at
the top of the file rather than under TYPE_CHECKING to comply with the coding
guidelines and enable proper static type checking.

Source: Coding guidelines

services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py (1)

4-4: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove postponed annotations from this module.

from __future__ import annotations is unnecessary here and makes runtime annotations string-based.

As per coding guidelines, **/*.py: Always prefer concrete type hints over string-based ones in Python code.

Suggested change
-from __future__ import annotations
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py` at line 4,
Remove the `from __future__ import annotations` import statement from the top of
the diagnostics module as it converts type hints to strings at runtime, which
violates the coding guideline that mandates concrete type hints over
string-based annotations. Simply delete this import line from the imports
section.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@e2e/conftest.py`:
- Around line 363-373: The teardown logic in the process termination loop does
not guard against processes that have already exited before teardown reaches
them, which can cause terminate() to raise an exception. Before calling
services.proc.terminate(), check if the process has already exited using
services.proc.poll() which returns None if the process is still running or a
return code if it has exited. Skip the termination and wait logic for processes
that have already exited to avoid raising exceptions during fixture teardown.

In `@e2e/test_data_designer.py`:
- Around line 15-16: The `run_nemo_local` function call around lines 189-199
does not check the subprocess result for failures. When the CLI exits with a
non-zero status code, the test continues executing instead of failing
immediately, causing later assertions to fail with misleading context. Capture
the return value from `run_nemo_local` and add a check to verify it succeeded
(exit code 0). If it failed, raise an exception with a clear error message
immediately so the test fails fast with proper context about the actual CLI
failure.

In `@services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py`:
- Around line 123-125: The code directly includes raw user-controlled job log
messages (entry.message) in the diagnostics dictionary, which can leak secrets
and PII when the diagnostics are logged via logger.debug. To fix this, sanitize
or filter the log entries before adding them to diagnostics["job_logs"] instead
of directly copying entry.message. Consider either redacting sensitive patterns
from the messages, limiting the log content to non-sensitive fields, or
replacing the raw messages with generic indicators. Apply the same sanitization
approach to all occurrences where job logs are added to diagnostics, including
the similar code referenced at lines 152-160.

---

Nitpick comments:
In `@services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py`:
- Line 4: Remove the `from __future__ import annotations` import statement from
the top of the diagnostics module as it converts type hints to strings at
runtime, which violates the coding guideline that mandates concrete type hints
over string-based annotations. Simply delete this import line from the imports
section.

In `@services/core/jobs/tests/integration/test_task_auth_runtime.py`:
- Around line 33-40: The `http_client` parameter in both the `_SecretAccessTask`
protocol's `run` method and the `_Task` class's `run` method in
`_secret_access_task_module` function lacks a concrete type hint. Add a concrete
type annotation to the `http_client` parameter in both locations using the
appropriate HTTP client type. Import the HTTP client type as a regular import at
the top of the file rather than under TYPE_CHECKING to comply with the coding
guidelines and enable proper static type checking.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a83518d1-5a7e-4e59-9ae0-cf7ac1d59374

📥 Commits

Reviewing files that changed from the base of the PR and between 7ef7c77 and 9b06990.

📒 Files selected for processing (17)
  • e2e/configs/local-subprocess.yaml
  • e2e/conftest.py
  • e2e/test_data_designer.py
  • e2e/test_jobs.py
  • e2e/test_jobs_auth.py
  • packages/nmp_testing/src/nmp/testing/__init__.py
  • packages/nmp_testing/src/nmp/testing/utils.py
  • pytest.ini
  • services/core/jobs/src/nmp/core/jobs/api/v2/jobs/endpoints.py
  • services/core/jobs/src/nmp/core/jobs/app/dispatcher.py
  • services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py
  • services/core/jobs/src/nmp/core/jobs/controllers/reconciler.py
  • services/core/jobs/src/nmp/core/jobs/controllers/scheduler.py
  • services/core/jobs/tests/controllers/test_reconciler.py
  • services/core/jobs/tests/controllers/test_scheduler.py
  • services/core/jobs/tests/integration/test_task_auth_runtime.py
  • services/core/jobs/tests/test_dispatcher_cross_workspace.py

Comment thread e2e/conftest.py Outdated
Comment thread e2e/test_data_designer.py Outdated
Comment thread services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py Outdated
@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 20908/27478 76.1% 61.2%
Integration Tests 12108/26247 46.1% 19.5%

@ironcommit
ironcommit force-pushed the auth-tests-2/rsadler branch from 224fc1e to bc2a2e5 Compare June 23, 2026 16:25
@github-actions

Copy link
Copy Markdown
Contributor

@ironcommit
ironcommit force-pushed the auth-tests-2/rsadler branch from bc2a2e5 to 4610ba5 Compare June 23, 2026 17:30

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
e2e/conftest.py (2)

82-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use concrete Python type hints.

These string-based annotations violate the repo rule; move the stash key below _E2EServicesPool and annotate pytest.Node directly.

Proposed fix
-_services_pool_manager_key = pytest.StashKey["_E2EServicesPool"]()
-
 ...
-def _resolve_e2e_config_layers_from_node(node: "pytest.Node") -> list[str | dict[str, Any]]:
+def _resolve_e2e_config_layers_from_node(node: pytest.Node) -> list[str | dict[str, Any]]:
 ...
-def _load_effective_e2e_config_from_node(node: "pytest.Node") -> tuple[list[Path], dict[str, Any]]:
+def _load_effective_e2e_config_from_node(node: pytest.Node) -> tuple[list[Path], dict[str, Any]]:
 class _E2EServicesPool:
     ...
             services.proc.wait(timeout=5)
 
 
+_services_pool_manager_key = pytest.StashKey[_E2EServicesPool]()
+
+
 def _services_log_dir(tmp_path_factory: pytest.TempPathFactory) -> Path:

As per coding guidelines, "**/*.py: Always prefer concrete type hints over string-based ones in Python code; do not import types under TYPE_CHECKING, instead import types as regular imports when possible."

Also applies to: 297-297, 362-362

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/conftest.py` at line 82, The variable _services_pool_manager_key at line
82 uses a string-based type annotation "_E2EServicesPool" which violates the
concrete type hints requirement. Remove the quotes around _E2EServicesPool and
ensure the _E2EServicesPool class or type is defined and imported before the
pytest.StashKey declaration so you can reference it directly without string
quotes. Additionally, import pytest.Node directly and use it as a concrete type
hint instead of as a string in the same line and in the other occurrences at
lines 297 and 362. This ensures all type annotations use concrete types rather
than string-based forward references.

Source: Coding guidelines


341-351: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Do not pass the canonicalized config to services.

Line 383 returns normalized config, and _materialize_config_path writes that same data, so jobs.executors can be reordered before the platform starts. Keep normalization for hashing only.

Proposed fix
-    return resolved_paths, _normalize_config(effective_config)
+    return resolved_paths, effective_config

Also applies to: 383-383

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/conftest.py` around lines 341 - 351, The normalization logic in the code
that sorts items for the jobs.executors path should only be used for hashing and
comparison purposes, not for modifying the actual configuration passed to
services. Currently, the normalized (sorted) version is being returned and used
by _materialize_config_path, which causes the executors to be reordered before
the platform starts. Keep the normalization logic intact for sorting/hashing,
but return the original unsorted value instead of the normalized version so that
the configuration maintains its original order when passed to services.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/core/jobs/src/nmp/core/jobs/controllers/scheduler.py`:
- Around line 155-157: The conflict handling logic in the scheduler is too
permissive for RESUMING steps. When a PENDING update conflicts and retrieve()
still returns RESUMING, the code silently ignores the failure instead of
detecting that the step is stuck. Fix this by modifying the conflict handling to
check if the persisted status has actually advanced from the originally fetched
status before ignoring the conflict. After catching a conflict exception, fetch
the current status again and compare it with the status that was initially
retrieved. Only ignore the conflict when the persisted status has progressed
beyond the RESUMING state that was found, not when it remains RESUMING. Apply
this logic to both the filter_params section around line 155 and the conflict
handling block mentioned in lines 193-203.

---

Nitpick comments:
In `@e2e/conftest.py`:
- Line 82: The variable _services_pool_manager_key at line 82 uses a
string-based type annotation "_E2EServicesPool" which violates the concrete type
hints requirement. Remove the quotes around _E2EServicesPool and ensure the
_E2EServicesPool class or type is defined and imported before the
pytest.StashKey declaration so you can reference it directly without string
quotes. Additionally, import pytest.Node directly and use it as a concrete type
hint instead of as a string in the same line and in the other occurrences at
lines 297 and 362. This ensures all type annotations use concrete types rather
than string-based forward references.
- Around line 341-351: The normalization logic in the code that sorts items for
the jobs.executors path should only be used for hashing and comparison purposes,
not for modifying the actual configuration passed to services. Currently, the
normalized (sorted) version is being returned and used by
_materialize_config_path, which causes the executors to be reordered before the
platform starts. Keep the normalization logic intact for sorting/hashing, but
return the original unsorted value instead of the normalized version so that the
configuration maintains its original order when passed to services.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7e53a7d9-e9e1-446c-94b1-e270f2333901

📥 Commits

Reviewing files that changed from the base of the PR and between bc2a2e5 and 4610ba5.

📒 Files selected for processing (20)
  • docs/set-up/config-reference.mdx
  • e2e/configs/local-subprocess.yaml
  • e2e/conftest.py
  • e2e/test_data_designer.py
  • e2e/test_jobs.py
  • e2e/test_jobs_auth.py
  • packages/nmp_testing/src/nmp/testing/__init__.py
  • packages/nmp_testing/src/nmp/testing/utils.py
  • pytest.ini
  • services/core/jobs/src/nmp/core/jobs/api/v2/jobs/endpoints.py
  • services/core/jobs/src/nmp/core/jobs/app/dispatcher.py
  • services/core/jobs/src/nmp/core/jobs/config.py
  • services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py
  • services/core/jobs/src/nmp/core/jobs/controllers/reconciler.py
  • services/core/jobs/src/nmp/core/jobs/controllers/scheduler.py
  • services/core/jobs/tests/controllers/test_diagnostics.py
  • services/core/jobs/tests/controllers/test_reconciler.py
  • services/core/jobs/tests/controllers/test_scheduler.py
  • services/core/jobs/tests/integration/test_task_auth_runtime.py
  • services/core/jobs/tests/test_dispatcher_cross_workspace.py
✅ Files skipped from review due to trivial changes (4)
  • e2e/test_jobs.py
  • pytest.ini
  • docs/set-up/config-reference.mdx
  • packages/nmp_testing/src/nmp/testing/init.py
🚧 Files skipped from review as they are similar to previous changes (13)
  • services/core/jobs/src/nmp/core/jobs/api/v2/jobs/endpoints.py
  • services/core/jobs/tests/controllers/test_diagnostics.py
  • services/core/jobs/src/nmp/core/jobs/app/dispatcher.py
  • services/core/jobs/tests/controllers/test_reconciler.py
  • e2e/test_data_designer.py
  • services/core/jobs/tests/test_dispatcher_cross_workspace.py
  • e2e/configs/local-subprocess.yaml
  • services/core/jobs/src/nmp/core/jobs/config.py
  • services/core/jobs/tests/integration/test_task_auth_runtime.py
  • e2e/test_jobs_auth.py
  • packages/nmp_testing/src/nmp/testing/utils.py
  • services/core/jobs/src/nmp/core/jobs/controllers/reconciler.py
  • services/core/jobs/src/nmp/core/jobs/controllers/diagnostics.py

Comment thread services/core/jobs/src/nmp/core/jobs/controllers/scheduler.py

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
services/core/jobs/tests/controllers/test_subprocess_backend.py (2)

341-351: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for stale pending metadata path.

This suite tests only the non-stale pending branch. Add a case where updated_at/created_at is older than the grace window and assert sync() returns ERROR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/jobs/tests/controllers/test_subprocess_backend.py` around lines
341 - 351, Add a new test function to cover the stale pending metadata path
where the step has been pending for longer than the grace window. Create a test
that sets up a pending step with updated_at and created_at timestamps older than
the configured grace period, calls backend.sync() on that step, and asserts that
the returned update status is ERROR rather than PENDING. This complements the
existing
test_sync_keeps_recent_pending_step_pending_when_local_metadata_is_missing
function which only covers the non-stale pending case.

319-322: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid spawning unmanaged sleep 10 in this unit test.

Line 319 starts a real process, and Line 321 drops its registry handle, so backend cleanup can’t terminate it. Build the missing-metadata scenario without launching a live subprocess.

Suggested simplification
-    _schedule_without_otel_export(backend, step)
-    key = SubprocessProcessKey(step.workspace, step.job, str(step.attempt_id), step.name)
-    backend._process_registry.pop(key)
+    # Keep local registry empty to simulate missing metadata.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/core/jobs/tests/controllers/test_subprocess_backend.py` around lines
319 - 322, The test spawns a real subprocess with
`_schedule_without_otel_export(backend, step)` and then removes it from the
process registry via `backend._process_registry.pop(key)`, leaving an unmanaged
subprocess that cannot be cleaned up by the backend. Instead of launching a live
subprocess to test the missing-metadata scenario, mock the necessary components
and process state to simulate the condition without actually spawning a
subprocess, ensuring proper resource cleanup during test execution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@services/core/jobs/src/nmp/core/jobs/controllers/backends/subprocess.py`:
- Around line 384-390: The `_pending_step_missing_metadata_is_stale` function
assumes that `anchor` (derived from `step.updated_at` or `step.created_at`) is a
datetime object, but it can be a string timestamp. Before performing datetime
arithmetic operations with `datetime.timedelta` on the `anchor` variable, check
if it is a string and parse it into a datetime object if necessary. This will
prevent type errors when the code path receives string timestamps and metadata
is missing.
- Around line 361-376: The code accesses tasks.data as an attribute on lines 373
and 376, but NemoResponse.data is a method that requires parentheses to be
invoked, not a property. Change tasks.data to tasks.data() in both locations:
the conditional check if not tasks.data() and in the max() function call with
tasks.data(). Also apply the same fix to the other locations mentioned:
diagnostics.py:119, base.py:306, and kubernetes_job.py:378 where this pattern
appears.

---

Nitpick comments:
In `@services/core/jobs/tests/controllers/test_subprocess_backend.py`:
- Around line 341-351: Add a new test function to cover the stale pending
metadata path where the step has been pending for longer than the grace window.
Create a test that sets up a pending step with updated_at and created_at
timestamps older than the configured grace period, calls backend.sync() on that
step, and asserts that the returned update status is ERROR rather than PENDING.
This complements the existing
test_sync_keeps_recent_pending_step_pending_when_local_metadata_is_missing
function which only covers the non-stale pending case.
- Around line 319-322: The test spawns a real subprocess with
`_schedule_without_otel_export(backend, step)` and then removes it from the
process registry via `backend._process_registry.pop(key)`, leaving an unmanaged
subprocess that cannot be cleaned up by the backend. Instead of launching a live
subprocess to test the missing-metadata scenario, mock the necessary components
and process state to simulate the condition without actually spawning a
subprocess, ensuring proper resource cleanup during test execution.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 32244c68-414d-4e86-b260-ea79bdc877b9

📥 Commits

Reviewing files that changed from the base of the PR and between 4610ba5 and 2ee08bf.

📒 Files selected for processing (3)
  • services/core/jobs/src/nmp/core/jobs/controllers/backends/subprocess.py
  • services/core/jobs/tests/controllers/test_scheduler.py
  • services/core/jobs/tests/controllers/test_subprocess_backend.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/core/jobs/tests/controllers/test_scheduler.py

@mckornfield mckornfield 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.

mostly q

Comment thread e2e/configs/local-subprocess.yaml Outdated
Comment thread e2e/conftest.py Outdated
Comment thread e2e/test_jobs.py
Comment thread services/core/jobs/src/nmp/core/jobs/api/v2/jobs/endpoints.py
Comment thread services/core/jobs/src/nmp/core/jobs/controllers/reconciler.py
@ironcommit
ironcommit force-pushed the auth-tests-2/rsadler branch 2 times, most recently from fca1e87 to 2023793 Compare June 23, 2026 19:57
@ironcommit
ironcommit enabled auto-merge June 23, 2026 21:23
@ironcommit
ironcommit disabled auto-merge June 23, 2026 21:26
@ironcommit
ironcommit force-pushed the auth-tests-2/rsadler branch 2 times, most recently from 74d2dd0 to b62e8ab Compare June 23, 2026 21:34
Add a new E2E test suite (`test_jobs_auth.py`) that validates workspace
isolation and principal propagation under an auth-enabled platform config.
Introduce a reusable `diagnostics.py` module in the jobs controller layer
to collect and log structured job/step/task state on errors, and wire it
into the reconciler and scheduler for automatic debug-level diagnostics
when steps transition to ERROR or encounter unexpected exceptions.

Refactor `e2e/conftest.py` to support multiple running-services instances
keyed by config hash, enabling per-test-module platform configs (e.g.,
`local-subprocess.yaml` with auth enabled) to coexist in a single session.
Add a `local-subprocess.yaml` E2E config and extend `nmp_testing` utilities
with `grant_workspace_role`, `unique_email`, and `TEST_ADMIN_EMAIL` helpers
needed by the auth test scenarios.

Signed-off-by: Ryan S <267728323+ironcommit@users.noreply.github.com>
@ironcommit
ironcommit force-pushed the auth-tests-2/rsadler branch from b62e8ab to db3a5e7 Compare June 23, 2026 21:47
@ironcommit
ironcommit enabled auto-merge June 23, 2026 21:48
@ironcommit
ironcommit added this pull request to the merge queue Jun 23, 2026
Merged via the queue into main with commit 04bd2a5 Jun 23, 2026
53 checks passed
@ironcommit
ironcommit deleted the auth-tests-2/rsadler branch June 23, 2026 22:09
mikeknep pushed a commit that referenced this pull request Jun 24, 2026
…re (#398)

Add a new E2E test suite (`test_jobs_auth.py`) that validates workspace
isolation and principal propagation under an auth-enabled platform config.
Introduce a reusable `diagnostics.py` module in the jobs controller layer
to collect and log structured job/step/task state on errors, and wire it
into the reconciler and scheduler for automatic debug-level diagnostics
when steps transition to ERROR or encounter unexpected exceptions.

Refactor `e2e/conftest.py` to support multiple running-services instances
keyed by config hash, enabling per-test-module platform configs (e.g.,
`local-subprocess.yaml` with auth enabled) to coexist in a single session.
Add a `local-subprocess.yaml` E2E config and extend `nmp_testing` utilities
with `grant_workspace_role`, `unique_email`, and `TEST_ADMIN_EMAIL` helpers
needed by the auth test scenarios.

Signed-off-by: Ryan S <267728323+ironcommit@users.noreply.github.com>
matthewgrossman pushed a commit that referenced this pull request Jun 24, 2026
…re (#398)

Add a new E2E test suite (`test_jobs_auth.py`) that validates workspace
isolation and principal propagation under an auth-enabled platform config.
Introduce a reusable `diagnostics.py` module in the jobs controller layer
to collect and log structured job/step/task state on errors, and wire it
into the reconciler and scheduler for automatic debug-level diagnostics
when steps transition to ERROR or encounter unexpected exceptions.

Refactor `e2e/conftest.py` to support multiple running-services instances
keyed by config hash, enabling per-test-module platform configs (e.g.,
`local-subprocess.yaml` with auth enabled) to coexist in a single session.
Add a `local-subprocess.yaml` E2E config and extend `nmp_testing` utilities
with `grant_workspace_role`, `unique_email`, and `TEST_ADMIN_EMAIL` helpers
needed by the auth test scenarios.

Signed-off-by: Ryan S <267728323+ironcommit@users.noreply.github.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants