Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
from nemo_platform import NeMoPlatform
from nemo_platform_plugin.client.adapter import client_from_platform
from nemo_platform_plugin.files.client import FilesClient
from nemo_platform_plugin.secrets.client import SecretsClient
from nemo_platform_plugin.secrets.types import PlatformSecretCreateRequest

from e2e.services_pool_fixtures import ( # noqa: F401
_services,
Expand Down Expand Up @@ -125,10 +127,11 @@ def ngc_api_key() -> str:
def ngc_secret(sdk: NeMoPlatform, workspace: str, ngc_api_key: str) -> Iterator[str]:
"""Create a secret containing the NGC API key, cleaned up after test."""
secret_name = f"e2e-ngc-key-{uuid.uuid4().hex[:8]}"
sdk.secrets.create(workspace=workspace, name=secret_name, value=ngc_api_key)
secrets = client_from_platform(sdk, SecretsClient)
secrets.create_secret(workspace=workspace, body=PlatformSecretCreateRequest(name=secret_name, value=ngc_api_key))
yield secret_name
try:
sdk.secrets.delete(workspace=workspace, name=secret_name)
secrets.delete_secret(workspace=workspace, name=secret_name)
except Exception:
pass # Best-effort cleanup; the workspace is deleted anyway

Expand Down
13 changes: 9 additions & 4 deletions e2e/files/test_storage_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@

import pytest
from nemo_platform import NeMoPlatform
from nemo_platform_plugin.client.adapter import client_from_platform
from nemo_platform_plugin.client.errors import BadRequestError
from nemo_platform_plugin.files.client import FilesClient
from nemo_platform_plugin.files.storage_config import HuggingfaceStorageConfig, NGCStorageConfig
from nemo_platform_plugin.files.types import CreateFilesetRequest
from nemo_platform_plugin.secrets.client import SecretsClient
from nemo_platform_plugin.secrets.types import PlatformSecretCreateRequest

# ---------------------------------------------------------------------------
# NGC configuration
Expand Down Expand Up @@ -82,10 +85,11 @@ def hf_token() -> str:
def hf_secret(sdk: NeMoPlatform, workspace: str, hf_token: str) -> Iterator[str]:
"""Create a secret containing the HF token, cleaned up after test."""
secret_name = f"e2e-hf-tok-{uuid.uuid4().hex[:8]}"
sdk.secrets.create(workspace=workspace, name=secret_name, value=hf_token)
secrets = client_from_platform(sdk, SecretsClient)
secrets.create_secret(workspace=workspace, body=PlatformSecretCreateRequest(name=secret_name, value=hf_token))
yield secret_name
try:
sdk.secrets.delete(workspace=workspace, name=secret_name)
secrets.delete_secret(workspace=workspace, name=secret_name)
except Exception:
pass # Best-effort cleanup; the workspace is deleted anyway

Expand Down Expand Up @@ -202,7 +206,8 @@ def test_create_error(
"""Bad NGC configurations are rejected with 400."""
value = secret_value if secret_value is not None else ngc_api_key
secret_name = f"e2e-ngc-err-{uuid.uuid4().hex[:8]}"
sdk.secrets.create(workspace=workspace, name=secret_name, value=value)
secrets = client_from_platform(sdk, SecretsClient)
secrets.create_secret(workspace=workspace, body=PlatformSecretCreateRequest(name=secret_name, value=value))
try:
storage = NGCStorageConfig(
api_key_secret=secret_name,
Expand All @@ -220,7 +225,7 @@ def test_create_error(
),
)
finally:
sdk.secrets.delete(workspace=workspace, name=secret_name)
secrets.delete_secret(workspace=workspace, name=secret_name)

def test_create_error_nonexistent_secret(self, files_client: FilesClient, workspace: str):
"""Referencing a secret that doesn't exist is rejected with 400."""
Expand Down
16 changes: 11 additions & 5 deletions e2e/test_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
import uuid

import pytest
from nemo_platform import NeMoPlatform, NotFoundError
from nemo_platform import NeMoPlatform
from nemo_platform_plugin.client.adapter import client_from_platform
from nemo_platform_plugin.client.errors import NotFoundError
from nemo_platform_plugin.jobs.client import JobsClient
from nemo_platform_plugin.jobs.constants import DEFAULT_JOB_STORAGE_PATH
from nemo_platform_plugin.jobs.types import CreatePlatformJobRequest
from nemo_platform_plugin.secrets.client import SecretsClient
from nemo_platform_plugin.secrets.types import PlatformSecretCreateRequest
from nmp.testing.e2e import wait_for_job_logs, wait_for_platform_job

from e2e.services_pool import RunningServices
Expand Down Expand Up @@ -258,7 +261,10 @@ def test_job_using_secret_environment_variable(sdk: NeMoPlatform, workspace: str
secret_name = f"e2e-secret-{uuid.uuid4().hex[:8]}"
secret_value = "s3cret-val"

secret = sdk.secrets.create(workspace=workspace, name=secret_name, value=secret_value)
secrets = client_from_platform(sdk, SecretsClient)
secret = secrets.create_secret(
workspace=workspace, body=PlatformSecretCreateRequest(name=secret_name, value=secret_value)
).data()
assert secret.name is not None, "Failed to create platform secret"

secret_deleted = False
Expand Down Expand Up @@ -303,14 +309,14 @@ def test_job_using_secret_environment_variable(sdk: NeMoPlatform, workspace: str
all_messages = " ".join(log.message for log in step_logs.data)
assert secret_value in all_messages, "Step logs do not show secret environment variable was used"

sdk.secrets.delete(workspace=workspace, name=secret_name)
secrets.delete_secret(workspace=workspace, name=secret_name)
secret_deleted = True
with pytest.raises(NotFoundError):
sdk.secrets.retrieve(secret_name, workspace=workspace)
secrets.get_secret(name=secret_name, workspace=workspace).data()
finally:
if not secret_deleted:
try:
sdk.secrets.delete(workspace=workspace, name=secret_name)
secrets.delete_secret(workspace=workspace, name=secret_name)
except Exception:
pass

Expand Down
76 changes: 41 additions & 35 deletions e2e/test_secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import uuid

from nemo_platform import NeMoPlatform
from nemo_platform_plugin.client.adapter import client_from_platform
from nemo_platform_plugin.secrets.client import SecretsClient
from nemo_platform_plugin.secrets.types import PlatformSecretCreateRequest


def test_secret_create_and_list(sdk: NeMoPlatform, workspace: str):
Expand All @@ -22,23 +25,23 @@ def test_secret_create_and_list(sdk: NeMoPlatform, workspace: str):
"""
secret_name = f"e2e-secret-{uuid.uuid4().hex[:8]}"
secret_value = "e2e-test-secret-value"
secrets = client_from_platform(sdk, SecretsClient)

# Create a secret
secret = sdk.secrets.create(
secret = secrets.create_secret(
workspace=workspace,
name=secret_name,
value=secret_value,
)
body=PlatformSecretCreateRequest(name=secret_name, value=secret_value),
).data()
assert secret.name == secret_name
assert secret.workspace == workspace

# List secrets and verify the new secret appears
list_response = sdk.secrets.list(workspace=workspace)
secret_names = [s.name for s in list_response.data]
list_response = secrets.list_secrets(workspace=workspace)
secret_names = [s.name for s in list_response.items()]
assert secret_name in secret_names

# Retrieve the secret to verify it was created correctly
retrieved_secret = sdk.secrets.retrieve(secret_name, workspace=workspace)
retrieved_secret = secrets.get_secret(name=secret_name, workspace=workspace).data()
assert retrieved_secret.name == secret_name
assert retrieved_secret.workspace == workspace

Expand All @@ -53,18 +56,17 @@ def test_secret_create_duplicate_fails(sdk: NeMoPlatform, workspace: str):
secret_value = "e2e-duplicate-test-secret-value"

# Create the initial secret
sdk.secrets.create(
secrets = client_from_platform(sdk, SecretsClient)
secrets.create_secret(
workspace=workspace,
name=secret_name,
value=secret_value,
body=PlatformSecretCreateRequest(name=secret_name, value=secret_value),
)

# Attempt to create a duplicate secret and expect failure
try:
sdk.secrets.create(
secrets.create_secret(
workspace=workspace,
name=secret_name,
value="some-other-value",
body=PlatformSecretCreateRequest(name=secret_name, value="some-other-value"),
)
assert False, "Expected an exception when creating a duplicate secret"
except Exception as e:
Expand All @@ -82,26 +84,26 @@ def test_secret_create_and_delete(sdk: NeMoPlatform, workspace: str):
secret_value = "e2e-delete-test-secret-value"

# Create a secret
sdk.secrets.create(
secrets = client_from_platform(sdk, SecretsClient)
secrets.create_secret(
workspace=workspace,
name=secret_name,
value=secret_value,
body=PlatformSecretCreateRequest(name=secret_name, value=secret_value),
)

# Verify the secret appears in the list
list_response = sdk.secrets.list(workspace=workspace)
secret_names = [s.name for s in list_response.data]
list_response = secrets.list_secrets(workspace=workspace)
secret_names = [s.name for s in list_response.items()]
assert secret_name in secret_names

# Delete the secret
sdk.secrets.delete(
secrets.delete_secret(
workspace=workspace,
name=secret_name,
)

# Verify the secret no longer appears in the list
list_response = sdk.secrets.list(workspace=workspace)
secret_names = [s.name for s in list_response.data]
list_response = secrets.list_secrets(workspace=workspace)
secret_names = [s.name for s in list_response.items()]
assert secret_name not in secret_names


Expand All @@ -114,10 +116,13 @@ def test_secret_data_not_in_create_response(sdk: NeMoPlatform, workspace: str):
secret_name = f"e2e-no-data-create-{uuid.uuid4().hex[:8]}"
secret_value = "this-should-not-appear-in-response"

secret = sdk.secrets.create(
workspace=workspace,
name=secret_name,
value=secret_value,
secret = (
client_from_platform(sdk, SecretsClient)
.create_secret(
workspace=workspace,
body=PlatformSecretCreateRequest(name=secret_name, value=secret_value),
)
.data()
)

# Verify name and workspace are present
Expand All @@ -139,15 +144,15 @@ def test_secret_data_not_in_retrieve_response(sdk: NeMoPlatform, workspace: str)
"""
secret_name = f"e2e-no-data-retrieve-{uuid.uuid4().hex[:8]}"
secret_value = "this-should-not-appear-in-retrieve"
secrets = client_from_platform(sdk, SecretsClient)

sdk.secrets.create(
secrets.create_secret(
workspace=workspace,
name=secret_name,
value=secret_value,
body=PlatformSecretCreateRequest(name=secret_name, value=secret_value),
)

# Retrieve the secret
retrieved = sdk.secrets.retrieve(secret_name, workspace=workspace)
retrieved = secrets.get_secret(name=secret_name, workspace=workspace).data()

# Verify name and workspace are present
assert retrieved.name == secret_name
Expand All @@ -168,21 +173,22 @@ def test_secret_data_not_in_list_response(sdk: NeMoPlatform, workspace: str):
secret_name = f"e2e-no-data-list-{uuid.uuid4().hex[:8]}"
secret_value = "this-should-not-appear-in-list"

sdk.secrets.create(
secrets = client_from_platform(sdk, SecretsClient)
secrets.create_secret(
workspace=workspace,
name=secret_name,
value=secret_value,
body=PlatformSecretCreateRequest(name=secret_name, value=secret_value),
)

# List secrets
list_response = sdk.secrets.list(workspace=workspace)
list_response = secrets.list_secrets(workspace=workspace)

# Find our secret in the list
our_secret = next((s for s in list_response.data if s.name == secret_name), None)
listed_secrets = list(list_response.items())
our_secret = next((s for s in listed_secrets if s.name == secret_name), None)
assert our_secret is not None, "Created secret should appear in list"

# Verify no secrets in the list expose their values
for secret in list_response.data:
for secret in listed_secrets:
secret_dict = secret.model_dump()
assert "data" not in secret_dict or secret_dict.get("data") is None
assert "_data" not in secret_dict
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
read_env_file,
write_env_file,
)
from nemo_platform_plugin.client.adapter import client_from_platform
from nemo_platform_plugin.secrets.client import SecretsClient


def resolve_inference_key(config: IronSwarmConfig) -> tuple[str | None, str]:
Expand All @@ -29,8 +31,8 @@ def resolve_inference_key(config: IronSwarmConfig) -> tuple[str | None, str]:
explicit ``INFERENCE_API_KEY`` still wins at run time, where the job injects via ``setdefault``.
"""
try:
sdk = make_sdk(base_url())
secret = sdk.secrets.access(config.inference_secret_name, workspace=config.default_workspace)
secrets = client_from_platform(make_sdk(base_url()), SecretsClient)
secret = secrets.access_secret(name=config.inference_secret_name, workspace=config.default_workspace).data()
if secret and secret.value:
return secret.value, f"secret '{config.inference_secret_name}'"
except Exception: # Secrets store unreachable/absent → fall back to env
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
IronSwarmRunError,
)
from nemo_iron_swarm_plugin.model_config import ModelChoice, WarGameModels
from nemo_platform_plugin.client.adapter import client_from_platform
from nemo_platform_plugin.job_context import JobContext
from nemo_platform_plugin.secrets.client import SecretsClient


def require_provisioned(plugin_config: IronSwarmConfig) -> None:
Expand Down Expand Up @@ -81,7 +83,7 @@ def _resolve_secret(sdk: Any, name: str, workspace: str) -> str | None:
"""Fetch a Secret's plaintext value via the platform SDK; None if unavailable (caller warns/fails)."""
if sdk is None:
return None
secret = sdk.secrets.access(name, workspace=workspace)
secret = client_from_platform(sdk, SecretsClient).access_secret(name=name, workspace=workspace).data()
value = getattr(secret, "value", None)
return str(value) if value else None

Expand Down
Loading
Loading