feat(auth): add access key listing and revocation - #1095
Conversation
|
d0efd70 to
93a8189
Compare
1e539f7 to
a8d7976
Compare
a8d7976 to
6ae7a2d
Compare
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughScoped Access Keys now support persisted lifecycle metadata, paginated listing, revocation, structured API responses, CLI lifecycle commands, and lifecycle-aware bearer authentication. Tests and documentation cover the new behavior. ChangesScoped Access Key lifecycle
Sequence Diagram(s)sequenceDiagram
participant Client
participant AuthAPI
participant PersistentAccessKeyIssuer
participant AccessKeyRegistry
participant AuthorizationMiddleware
Client->>AuthAPI: Create, list, or revoke access key
AuthAPI->>PersistentAccessKeyIssuer: Execute lifecycle operation
PersistentAccessKeyIssuer->>AccessKeyRegistry: Persist or update lifecycle metadata
AccessKeyRegistry-->>AuthAPI: Return metadata or revocation result
Client->>AuthorizationMiddleware: Send access-key bearer token
AuthorizationMiddleware->>AuthAPI: Validate lifecycle state
AuthAPI->>AccessKeyRegistry: Check active JTI for principal
AccessKeyRegistry-->>AuthorizationMiddleware: Return active claims or rejection
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
openapi/ga/individual/platform.openapi.yaml (1)
260-284: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winAccept legacy JTIs in the revoke path.
Backfill persists the original legacy
jtiwithout normalization. Values such asak_legacydo not match^ak_[0-9a-f]{32}$, so revoke requests receive 422 before the handler runs. Remove the pattern or broaden it, and add a backfilled-key revoke test.🤖 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 `@openapi/ga/individual/platform.openapi.yaml` around lines 260 - 284, Update the revoke_access_key path parameter schema for jti to accept legacy persisted JTIs such as ak_legacy by removing or broadening the restrictive hexadecimal pattern, while keeping the parameter required and string-typed. Add a test covering revocation of a backfilled key with a legacy JTI and verify the handler succeeds instead of returning validation error 422.openapi/ga/openapi.yaml (1)
267-275: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winAllow legacy
jtivalues in the revoke path.New keys use the required format, but backfill stores legacy values unchanged. The
ak_legacyfixture does not match^ak_[0-9a-f]{32}$; DELETE therefore returns 422 instead of revoking the key. Accept legacy values or migrate them before enforcing this pattern.🤖 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 `@openapi/ga/openapi.yaml` around lines 267 - 275, Update the revoke-path jti parameter schema to accept legacy stored values such as ak_legacy while retaining validation for the new ak_ plus 32-hex-character format. Remove or broaden the restrictive pattern on the jti path parameter so DELETE revocation does not return 422 for backfilled legacy keys.
🧹 Nitpick comments (2)
packages/nmp_common/src/nmp/common/auth/access_keys.py (1)
402-414: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winDowngrade the catch-all log to debug or throttle it.
Any invalid or tampered access-key token now emits a warning with a stack trace. An unauthenticated caller can flood logs by sending garbage bearer tokens.
🤖 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 `@packages/nmp_common/src/nmp/common/auth/access_keys.py` around lines 402 - 414, Update the broad exception handler around TokenClaims construction to log validation failures at debug level instead of warning, and disable stack-trace logging for these expected invalid-token cases. Preserve the existing exception propagation for httpx.HTTPError.packages/nmp_common/tests/auth/test_middleware.py (1)
826-833: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClose the
httpx.AsyncClient.This client is created but never closed, so the test can emit unclosed-client warnings. Other tests here use
async with. Wrap it or register a cleanup.🤖 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 `@packages/nmp_common/tests/auth/test_middleware.py` around lines 826 - 833, Update the test setup around the AsyncClient used by AuthorizationMiddleware to ensure the httpx.AsyncClient is closed after the test completes. Prefer an async-context-manager or the test’s existing cleanup mechanism, while keeping the same client instance supplied to both middleware parameters.
🤖 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 `@packages/nmp_common/src/nmp/common/auth/access_keys.py`:
- Around line 92-107: Update is_access_key_token_candidate to catch the broader
jwt.PyJWTError base exception around jwt.decode, returning False for any
malformed or otherwise invalid token while preserving the existing token-type
check for successfully decoded payloads.
In `@packages/nmp_platform_runner/src/nmp/platform_runner/server.py`:
- Around line 235-240: Update create_app and its AuthorizationMiddleware setup
to use a dedicated lifecycle HTTP client for lifecycle requests instead of
reusing the endpoint-bound http_client. Add and thread a separate
lifecycle-client parameter through the relevant call sites, or explicitly
enforce and document that the injected client must reach the auth endpoint.
---
Outside diff comments:
In `@openapi/ga/individual/platform.openapi.yaml`:
- Around line 260-284: Update the revoke_access_key path parameter schema for
jti to accept legacy persisted JTIs such as ak_legacy by removing or broadening
the restrictive hexadecimal pattern, while keeping the parameter required and
string-typed. Add a test covering revocation of a backfilled key with a legacy
JTI and verify the handler succeeds instead of returning validation error 422.
In `@openapi/ga/openapi.yaml`:
- Around line 267-275: Update the revoke-path jti parameter schema to accept
legacy stored values such as ak_legacy while retaining validation for the new
ak_ plus 32-hex-character format. Remove or broaden the restrictive pattern on
the jti path parameter so DELETE revocation does not return 422 for backfilled
legacy keys.
---
Nitpick comments:
In `@packages/nmp_common/src/nmp/common/auth/access_keys.py`:
- Around line 402-414: Update the broad exception handler around TokenClaims
construction to log validation failures at debug level instead of warning, and
disable stack-trace logging for these expected invalid-token cases. Preserve the
existing exception propagation for httpx.HTTPError.
In `@packages/nmp_common/tests/auth/test_middleware.py`:
- Around line 826-833: Update the test setup around the AsyncClient used by
AuthorizationMiddleware to ensure the httpx.AsyncClient is closed after the test
completes. Prefer an async-context-manager or the test’s existing cleanup
mechanism, while keeping the same client instance supplied to both middleware
parameters.
🪄 Autofix
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: 8ef44860-452c-4f37-bf43-151225a4dd59
⛔ Files ignored due to path filters (17)
sdk/python/nemo-platform/.nmpcontext/openapi.yamlis excluded by!sdk/**sdk/python/nemo-platform/.nmpcontext/stainless.yamlis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/cli/commands/auth.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/cli/core/errors.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/resources/access_keys/access_keys.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/resources/access_keys/api.mdis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/__init__.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_create_params.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_create_response.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_list_params.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_list_response.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_metadata_response.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_revoke_response.pyis excluded by!sdk/**sdk/python/nemo-platform/tests/api_resources/test_access_keys.pyis excluded by!sdk/**sdk/python/nemo-platform/tests/vendored/nemo_platform_ext/cli/commands/test_auth.pyis excluded by!sdk/**sdk/python/nemo-platform/tests/vendored/nemo_platform_ext/cli/core/test_errors.pyis excluded by!sdk/**sdk/stainless.yamlis excluded by!sdk/**
📒 Files selected for processing (41)
docs/auth/authentication/using-authentication.mdxdocs/auth/deployment/configuration.mdxdocs/cli/reference.mdxopenapi/ga/individual/platform.openapi.yamlopenapi/ga/openapi.yamlopenapi/openapi.yamlpackages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/auth.pypackages/nemo_platform_ext/src/nemo_platform_ext/cli/core/errors.pypackages/nemo_platform_ext/tests/cli/commands/test_auth.pypackages/nemo_platform_ext/tests/cli/core/test_errors.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/client.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/endpoints.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/issuer.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/types.pypackages/nemo_platform_plugin/tests/auth/access_keys/test_client.pypackages/nemo_platform_plugin/tests/auth/access_keys/test_endpoints.pypackages/nmp_common/src/nmp/common/auth/access_keys.pypackages/nmp_common/src/nmp/common/auth/jwt.pypackages/nmp_common/src/nmp/common/auth/middleware.pypackages/nmp_common/src/nmp/common/config/base.pypackages/nmp_common/src/nmp/common/entities/client.pypackages/nmp_common/tests/auth/test_access_keys.pypackages/nmp_common/tests/auth/test_jwt.pypackages/nmp_common/tests/auth/test_middleware.pypackages/nmp_common/tests/entities/test_client.pypackages/nmp_platform_runner/src/nmp/platform_runner/server.pypackages/nmp_platform_runner/tests/test_server.pyservices/core/auth/src/nmp/core/auth/api/v2/access_keys/endpoints.pyservices/core/auth/src/nmp/core/auth/api/v2/access_keys/schemas.pyservices/core/auth/src/nmp/core/auth/api/v2/authenticate.pyservices/core/auth/src/nmp/core/auth/api/v2/workload_token_exchange.pyservices/core/auth/src/nmp/core/auth/app/access_keys.pyservices/core/auth/src/nmp/core/auth/entities/__init__.pyservices/core/auth/src/nmp/core/auth/entities/entities.pyservices/core/auth/tests/integration/test_scoped_access_keys.pyservices/core/auth/tests/test_access_key_registry.pyservices/core/auth/tests/test_access_keys.pyservices/core/auth/tests/test_authenticate.pyservices/core/auth/tests/test_embedded_pdp_stress.pyservices/core/auth/tests/test_workload_token_exchange.pyservices/core/inference-gateway/tests/integration/test_middleware_pipeline.py
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/inference-gateway/tests/integration/test_mock_provider_mode.py`:
- Line 70: Rename the provider created by
test_fixture_add_provider_with_error_status so it uses a unique name instead of
duplicating the error-provider created by test_example_simulate_server_error.
Update all references within that fixture and its test flow consistently.
🪄 Autofix
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: f0b91852-db36-4df6-a314-a9271567e780
📒 Files selected for processing (2)
services/core/inference-gateway/tests/integration/test_igw_with_auth.pyservices/core/inference-gateway/tests/integration/test_mock_provider_mode.py
6dcc562 to
9c3ecd7
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
packages/nmp_platform_runner/tests/test_server.py (1)
283-288: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the lifecycle client in the build tests.
Both
fake_create_appfunctions acceptaccess_key_lifecycle_http_clientbut discard it. The tests can pass even ifbuild_platform_appstops forwarding the argument. Store the value, pass a non-Noneclient to at least one call, and assert object identity.Suggested test update
captured["http_client"] = http_client + captured["access_key_lifecycle_http_client"] = access_key_lifecycle_http_client app = server.build_platform_app( ... + access_key_lifecycle_http_client=lifecycle_http_client, ) ... + assert captured["access_key_lifecycle_http_client"] is lifecycle_http_clientApply the capture assignment to both fakes.
Also applies to: 313-318
🤖 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 `@packages/nmp_platform_runner/tests/test_server.py` around lines 283 - 288, Update both fake_create_app functions to capture the access_key_lifecycle_http_client argument, then pass a non-None client through at least one build_platform_app test invocation and assert the captured value is the identical object provided. Preserve the existing test setup while ensuring both fakes record the lifecycle client.packages/nmp_common/tests/auth/test_access_key_lifecycle.py (1)
81-107: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd circuit-breaker coverage.
The tests exercise the happy path, the non-access-key rejection, and one malformed response. The fail-closed circuit breaker is untested: no test drives three consecutive failures to open the circuit, asserts the
retry_aftervalue, asserts the 503 raised while the circuit is open, or covers the half-open reset after the window lapses. TheAuthenticationError→Nonepath, the missing-jti→ 503 path, and theAPITimeoutError→ 504 path are also uncovered.This is the logic that decides whether requests are accepted when the auth service degrades. Add cases that call
authenticaterepeatedly against a failing handler and assertstatus_code,retry_after, and recovery after the open window.Run tests with
uv run pytest packages/nmp_common/tests/auth/test_access_key_lifecycle.py.I can draft these tests. Do you want me to?
As per coding guidelines: "Run Python scripts and tools through uv, such as
uv run script.py,uv run pytest".🤖 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 `@packages/nmp_common/tests/auth/test_access_key_lifecycle.py` around lines 81 - 107, Expand test coverage around AccessKeyLifecycleAuthenticator.authenticate for AuthenticationError returning None, missing jti producing 503, and APITimeoutError producing 504. Add circuit-breaker tests that trigger three consecutive failures, assert the open-circuit 503 and retry_after, verify requests are blocked during the window, and confirm half-open recovery resets the breaker after the window expires. Run the targeted file with uv run pytest packages/nmp_common/tests/auth/test_access_key_lifecycle.py.Source: Coding guidelines
packages/nmp_common/tests/auth/test_middleware.py (1)
850-894: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClose the
httpx.AsyncClientcreated at Line 854.The other lifecycle tests use
async with. This test leaks the client, which produces unclosed-transport warnings. Close it after the request, for example withclient.portal-free teardown viaasyncio.run(http_client.aclose())in afinallyblock, or convert the test to async and useasync with.🤖 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 `@packages/nmp_common/tests/auth/test_middleware.py` around lines 850 - 894, Close the httpx.AsyncClient created in this test after the request completes. Update the test lifecycle around the visible http_client setup and client.get call to guarantee http_client.aclose() runs in a finally block, or convert the test to async and manage it with async with, while preserving the existing assertions.
🤖 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.
Nitpick comments:
In `@packages/nmp_common/tests/auth/test_access_key_lifecycle.py`:
- Around line 81-107: Expand test coverage around
AccessKeyLifecycleAuthenticator.authenticate for AuthenticationError returning
None, missing jti producing 503, and APITimeoutError producing 504. Add
circuit-breaker tests that trigger three consecutive failures, assert the
open-circuit 503 and retry_after, verify requests are blocked during the window,
and confirm half-open recovery resets the breaker after the window expires. Run
the targeted file with uv run pytest
packages/nmp_common/tests/auth/test_access_key_lifecycle.py.
In `@packages/nmp_common/tests/auth/test_middleware.py`:
- Around line 850-894: Close the httpx.AsyncClient created in this test after
the request completes. Update the test lifecycle around the visible http_client
setup and client.get call to guarantee http_client.aclose() runs in a finally
block, or convert the test to async and manage it with async with, while
preserving the existing assertions.
In `@packages/nmp_platform_runner/tests/test_server.py`:
- Around line 283-288: Update both fake_create_app functions to capture the
access_key_lifecycle_http_client argument, then pass a non-None client through
at least one build_platform_app test invocation and assert the captured value is
the identical object provided. Preserve the existing test setup while ensuring
both fakes record the lifecycle client.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 9239cf6f-de13-4a8e-849a-4416c4408ab3
⛔ Files ignored due to path filters (17)
sdk/python/nemo-platform/.nmpcontext/openapi.yamlis excluded by!sdk/**sdk/python/nemo-platform/.nmpcontext/stainless.yamlis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/cli/commands/auth.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/cli/core/errors.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/resources/access_keys/access_keys.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/resources/access_keys/api.mdis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/__init__.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_create_params.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_create_response.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_list_params.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_list_response.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_metadata_response.pyis excluded by!sdk/**sdk/python/nemo-platform/src/nemo_platform/types/access_keys/access_key_revoke_response.pyis excluded by!sdk/**sdk/python/nemo-platform/tests/api_resources/test_access_keys.pyis excluded by!sdk/**sdk/python/nemo-platform/tests/vendored/nemo_platform_ext/cli/commands/test_auth.pyis excluded by!sdk/**sdk/python/nemo-platform/tests/vendored/nemo_platform_ext/cli/core/test_errors.pyis excluded by!sdk/**sdk/stainless.yamlis excluded by!sdk/**
📒 Files selected for processing (45)
docs/auth/authentication/using-authentication.mdxdocs/auth/deployment/configuration.mdxdocs/cli/reference.mdxopenapi/ga/individual/platform.openapi.yamlopenapi/ga/openapi.yamlopenapi/openapi.yamlpackages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/auth.pypackages/nemo_platform_ext/src/nemo_platform_ext/cli/core/errors.pypackages/nemo_platform_ext/tests/cli/commands/test_auth.pypackages/nemo_platform_ext/tests/cli/core/test_errors.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/client.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/endpoints.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/issuer.pypackages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/types.pypackages/nemo_platform_plugin/tests/auth/access_keys/test_client.pypackages/nemo_platform_plugin/tests/auth/access_keys/test_endpoints.pypackages/nmp_common/src/nmp/common/auth/access_key_lifecycle.pypackages/nmp_common/src/nmp/common/auth/access_keys.pypackages/nmp_common/src/nmp/common/auth/jwt.pypackages/nmp_common/src/nmp/common/auth/middleware.pypackages/nmp_common/src/nmp/common/auth/token_resolver.pypackages/nmp_common/src/nmp/common/config/base.pypackages/nmp_common/src/nmp/common/entities/client.pypackages/nmp_common/tests/auth/test_access_key_lifecycle.pypackages/nmp_common/tests/auth/test_access_keys.pypackages/nmp_common/tests/auth/test_jwt.pypackages/nmp_common/tests/auth/test_middleware.pypackages/nmp_common/tests/entities/test_client.pypackages/nmp_platform_runner/src/nmp/platform_runner/server.pypackages/nmp_platform_runner/tests/test_server.pypackages/nmp_testing/src/nmp/testing/client.pyservices/core/auth/src/nmp/core/auth/api/v2/access_keys/endpoints.pyservices/core/auth/src/nmp/core/auth/api/v2/access_keys/schemas.pyservices/core/auth/src/nmp/core/auth/api/v2/authenticate.pyservices/core/auth/src/nmp/core/auth/api/v2/workload_token_exchange.pyservices/core/auth/src/nmp/core/auth/app/access_keys.pyservices/core/auth/src/nmp/core/auth/entities/__init__.pyservices/core/auth/src/nmp/core/auth/entities/entities.pyservices/core/auth/tests/integration/test_scoped_access_keys.pyservices/core/auth/tests/test_access_key_registry.pyservices/core/auth/tests/test_access_keys.pyservices/core/auth/tests/test_authenticate.pyservices/core/auth/tests/test_embedded_pdp_stress.pyservices/core/auth/tests/test_workload_token_exchange.pyservices/core/inference-gateway/tests/integration/test_mock_provider_mode.py
🚧 Files skipped from review as they are similar to previous changes (30)
- services/core/auth/src/nmp/core/auth/entities/init.py
- packages/nmp_common/src/nmp/common/config/base.py
- services/core/auth/src/nmp/core/auth/api/v2/workload_token_exchange.py
- services/core/auth/tests/test_workload_token_exchange.py
- services/core/inference-gateway/tests/integration/test_mock_provider_mode.py
- services/core/auth/tests/integration/test_scoped_access_keys.py
- docs/cli/reference.mdx
- packages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/endpoints.py
- docs/auth/authentication/using-authentication.mdx
- packages/nmp_common/tests/auth/test_jwt.py
- docs/auth/deployment/configuration.mdx
- packages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/issuer.py
- packages/nemo_platform_plugin/tests/auth/access_keys/test_endpoints.py
- packages/nmp_common/tests/entities/test_client.py
- packages/nmp_common/src/nmp/common/entities/client.py
- packages/nemo_platform_plugin/tests/auth/access_keys/test_client.py
- packages/nemo_platform_ext/tests/cli/commands/test_auth.py
- packages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/client.py
- packages/nmp_common/src/nmp/common/auth/jwt.py
- services/core/auth/src/nmp/core/auth/api/v2/access_keys/schemas.py
- services/core/auth/src/nmp/core/auth/api/v2/access_keys/endpoints.py
- packages/nemo_platform_plugin/src/nemo_platform_plugin/auth/access_keys/types.py
- services/core/auth/src/nmp/core/auth/app/access_keys.py
- services/core/auth/src/nmp/core/auth/api/v2/authenticate.py
- packages/nemo_platform_ext/src/nemo_platform_ext/cli/core/errors.py
- packages/nmp_common/src/nmp/common/auth/middleware.py
- openapi/openapi.yaml
- openapi/ga/openapi.yaml
- packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/auth.py
- openapi/ga/individual/platform.openapi.yaml
9c3ecd7 to
ebdbf49
Compare
eed507a to
63248e0
Compare
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
63248e0 to
02e326b
Compare
Local and CI reproduction attempts show the worker-crash on this test is not fixed by resetting the wasmtime policy singleton on shutdown (still crashes with no traceback after that change), so the xdist_group mitigation and the coverage added alongside it are reverted pending further root-causing. Signed-off-by: anastasia-nesterenko <anesterenko@nvidia.com>
Summary
Adds persistent lifecycle management for Scoped Access Keys across the auth service, Python SDK, and NeMo CLI. Previously keys could be created but not inventoried or revoked; this change stores lifecycle metadata, exposes list and revoke operations, and rejects expired or revoked keys during authentication.
Changes
ACTIVE,EXPIRED, orREVOKED, including legacy-key backfill and fail-closed validation for current keys.GET /apis/auth/v2/access-keysand idempotentDELETE /apis/auth/v2/access-keys/{jti}endpoints.nemo auth access-keys listandnemo auth access-keys revoke <jti>commands, optional key descriptions, truncation warnings, and actionable error handling.Type of Change
Quality Gates
Verification
Signed-off-by:traileruv run pre-commit run -apasses, or any blocked checks are identified belowTargeted validation:
uv run pre-commit run -a— passed for the PR content.uv run --frozen pytest packages/nemo_platform_ext/tests/cli/commands/test_auth.py packages/nemo_platform_ext/tests/cli/core/test_errors.py packages/nemo_platform_plugin/tests/auth/access_keys/test_client.py packages/nmp_common/tests/auth/test_access_keys.py packages/nmp_common/tests/auth/test_jwt.py packages/nmp_common/tests/auth/test_middleware.py services/core/auth/tests/test_access_key_registry.py services/core/auth/tests/test_access_keys.py -q— 259 passed.uv run --frozen pytest tests/vendored/nemo_platform_ext/cli/commands/test_auth.py tests/vendored/nemo_platform_ext/cli/core/test_errors.py -qfromsdk/python/nemo-platform— 90 passed.uv run --frozen pytest services/core/auth/tests/integration/test_scoped_access_keys.py -v— 1 passed.uv run --frozen pytest -n 4 --maxprocesses=16 --max-worker-restart=0 --dist loadgroup --timeout=120 -vv services/core/inference-gateway/tests/integration/test_igw_with_auth.py services/core/inference-gateway/tests/integration/test_middleware_pipeline.py— 37 passed.UV_PYTHON=3.12 uv run --frozen pytest -n 3 --maxprocesses=16 --max-worker-restart=0 --dist loadgroup --timeout=120 -q services/core/inference-gateway/tests/integration/test_mock_provider_mode.py— 54 passed.uv run --frozen ruff check services/core/inference-gateway/tests/integration/test_middleware_pipeline.py services/core/inference-gateway/tests/integration/test_igw_with_auth.py— passed.uv run --frozen ruff format --check services/core/inference-gateway/tests/integration/test_middleware_pipeline.py services/core/inference-gateway/tests/integration/test_igw_with_auth.py— passed.Summary by CodeRabbit