Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
1fee71b
feat(blueprint): add Okta runtime identity wrapper
afourniernv Jul 20, 2026
85292df
feat(blueprint): add Entra identity reference
afourniernv Jul 20, 2026
2a7ef35
fix(blueprint): keep runtime identity Okta-only
afourniernv Jul 20, 2026
590e385
fix(blueprint): harden Okta identity validation
afourniernv Jul 21, 2026
cb6d516
Merge branch 'main' into 6871-agent-identity-references/af
ericksoa Jul 23, 2026
b990376
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
3518f36
fix(blueprint): harden runtime identity lifecycle
ericksoa Jul 27, 2026
d35d4c6
fix(blueprint): close identity review gaps
ericksoa Jul 27, 2026
537c216
fix(blueprint): address identity review findings
ericksoa Jul 27, 2026
bdcd239
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
9a484a7
test(blueprint): keep identity fixtures linear
ericksoa Jul 27, 2026
182dc26
fix(blueprint): fail closed on identity DNS rebinding
ericksoa Jul 27, 2026
549106e
fix(blueprint): require owned identity providers
ericksoa Jul 27, 2026
a78525e
fix(blueprint): constrain runtime identity policy
ericksoa Jul 27, 2026
71e4496
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
4b32c5e
fix(blueprint): import validated identity profile bytes
ericksoa Jul 27, 2026
2a5c17c
test(blueprint): keep identity lifecycle linear
ericksoa Jul 27, 2026
0242437
fix(identity): prove runtime OAuth flow end to end
ericksoa Jul 27, 2026
7b79ce8
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
f7df500
test(identity): keep rotation proof linear
ericksoa Jul 27, 2026
0bc4646
fix(identity): tighten ownership and DNS trust
ericksoa Jul 27, 2026
5497274
fix(identity): bind client ID source to policy
ericksoa Jul 27, 2026
72e1193
fix(identity): keep failed rollback retryable
ericksoa Jul 27, 2026
b07fca5
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
7a85de9
fix(identity): reuse existing sandbox before create
ericksoa Jul 27, 2026
f2cbbf0
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
ff871ea
fix(identity): fail closed on sandbox inspection
ericksoa Jul 27, 2026
258f034
docs(identity): document sandbox preflight order
ericksoa Jul 27, 2026
d717806
test(identity): keep sandbox fixture linear
ericksoa Jul 27, 2026
0718158
fix(identity): reuse configured inference provider
ericksoa Jul 27, 2026
e0b5470
Merge remote-tracking branch 'origin/main' into pr-7265
ericksoa Jul 27, 2026
616c896
docs(identity): clarify provider preflight order
ericksoa Jul 27, 2026
7a35fc5
fix(identity): track inference provider ownership
ericksoa Jul 27, 2026
fa7a376
fix(identity): revalidate provider create races
ericksoa Jul 27, 2026
8fc7df8
fix(blueprint): verify inference before identity attach
ericksoa Jul 27, 2026
8ea8850
fix(blueprint): preserve active inference route
ericksoa Jul 27, 2026
20c64fb
docs(architecture): clarify route timeout reuse
ericksoa Jul 27, 2026
58dcf6e
test(blueprint): keep route timeout case linear
ericksoa Jul 27, 2026
1734e67
fix(blueprint): revalidate raced sandbox
ericksoa Jul 27, 2026
ba3b1ec
fix(blueprint): recheck sandbox before identity attach
ericksoa Jul 27, 2026
3d71424
fix(schema): align runtime client id names
ericksoa Jul 28, 2026
0fcf798
fix(identity): prove provider policy auth path
ericksoa Jul 28, 2026
c5b1821
fix(identity): bound inference route parsing
ericksoa Jul 28, 2026
efb00ba
test(e2e): verify preserved sandbox with supported command
ericksoa Jul 28, 2026
7ea7370
test(e2e): align runtime identity phase evidence
ericksoa Jul 28, 2026
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
81 changes: 81 additions & 0 deletions docs/reference/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,87 @@ flowchart LR
4. Apply. The runner executes the plan by calling `openshell` CLI commands.
5. Status. The runner reports current state.

### Experimental Runtime Identity

The direct blueprint runner can opt in to a provider-neutral runtime identity component.
This experimental reference capability is not enabled by the shipped blueprint, and normal `$$nemoclaw onboard` does not collect or provision its inputs.
The bundled Okta profile is the first data-only implementation of the component.
The blueprint schema describes the OpenShell provider binding and OAuth refresh inputs without using the identity provider as a schema discriminator.

<Warning>
The pinned OpenShell runtime resolves the OAuth token URL and provider endpoint hostnames again after NemoClaw validates them.
Because that boundary cannot yet preserve both the validated peer and the original HTTPS identity, the direct runner rejects every DNS-backed runtime identity destination before profile import.
The current `okta-runtime-v1` trust policy admits only `okta.com` hostnames, so the bundled profile is a reference contract and does not currently provide an activatable production Okta path.
Remove this fail-closed restriction only when the OpenShell refresh and provider endpoint contracts atomically validate and connect to the same peer.
</Warning>

Enable provider-derived policy on the target gateway before applying a blueprint that attaches this component:

```bash
openshell settings set --global --key providers_v2_enabled --value true --yes
```

Copy `nemoclaw-blueprint/provider-profiles/okta-runtime-v1.yaml` into the blueprint you operate as `provider-profiles/acme-okta-runtime.yaml`.
You can choose another tenant-specific filename, but set `profile_path` below to that exact relative path.
Set its `token_url` to the tenant's authorization-server token endpoint.
Replace `api.example.okta.com` with the approved upstream API host.
Keep the token endpoint and upstream host in the profile so refresh material and bearer-token presentation cannot be redirected by blueprint input.

Configure the reference under `components`:

```yaml
identity:
profile_path: provider-profiles/acme-okta-runtime.yaml
provider_type: okta-runtime-v1
provider_name: acme-okta-runtime
credential_key: OKTA_ACCESS_TOKEN
client_id_env: OKTA_CLIENT_ID
refresh_token_env: OKTA_REFRESH_TOKEN
client_secret_env: OKTA_CLIENT_SECRET
```

`client_secret_env` is optional, but when it is configured its environment variable must be present.
Secret-material environment names must equal one of `API_KEY`, `TOKEN`, `SECRET`, `PASSWORD`, or `CREDENTIAL`, or end in one of those terms preceded by an underscore.
Subprocess-control names such as `NODE_OPTIONS` and names forwarded by the general subprocess allowlist, such as the `OPENSHELL_`, `GRPC_`, and `XDG_` prefixes, are rejected.
The profile path must name an existing regular file whose resolved path stays inside the blueprint directory; absolute paths, outward traversal, and outward symlinks are rejected.
The profile `id` must match `provider_type`, and the profile must declare exactly one credential whose name matches `credential_key`.
Before import, the runner validates the complete credential-delivery policy and rejects unknown fields.
The Okta reference requires bearer presentation through the `authorization` header, the reviewed OAuth refresh-material shape, enforced REST `GET /**` endpoint rules, and exactly the bundled Node.js and curl executable allowlist.
Before importing the profile, the runner requires HTTPS refresh and endpoint destinations, restricts them to the provider type's trusted host policy, and sends each through NemoClaw's DNS-aware SSRF boundary; private, loopback, link-local, and unresolved destinations are rejected.
DNS-backed HTTPS destinations are also rejected because the pinned OpenShell runtime would resolve their hostnames again after validation.
The current `okta-runtime-v1` policy accepts `okta.com` and its subdomains; custom Okta domains are not supported in this slice.
Before applying the blueprint, export the named environment variables in the host process that runs the direct blueprint runner.
Obtain the refresh token through an authorized OAuth bootstrap flow for the same Okta client and authorization server as the profile.
`openshell gateway login` authenticates a CLI user to the gateway and is not part of this runtime-credential flow.

During plan, the runner reports only the non-secret provider type, provider name, and credential key.
During apply, the runner first inspects the requested provider name and stops if any same-name provider already exists.
It validates an existing provider's non-secret binding to produce a precise error, but never reuses it for this mutable refresh flow because OpenShell does not expose a secret-safe snapshot that rollback could restore.
Only an absent provider proceeds to profile import, or exact export comparison when that profile is already registered, followed by provider creation, gateway-managed OAuth refresh configuration, initial token rotation, and sandbox attachment.
Each successful apply therefore creates and owns the provider whose refresh state it mutates.
The persisted run plan records whether that apply created the provider and its sandbox attachment.
The runner writes that ownership receipt as each identity resource is acquired, so `status` and a later `rollback` retain a recovery path if automatic compensation fails.
If a later apply step fails, the runner detaches the provider when that apply attached it, deletes the provider when that apply created it, and removes a sandbox created by that apply.
The runner never places the refresh token or optional client secret in command arguments or persisted plans.
It passes those values to `openshell provider refresh configure` through a scoped subprocess environment, and OpenShell stores the resulting credential material in the gateway credential store.
All other runner subprocesses receive the allowlisted environment without the identity material.
The sandbox receives an opaque `OKTA_ACCESS_TOKEN` placeholder, and the OpenShell L7 proxy substitutes the current access token only for admitted HTTPS requests.

Check the gateway-side state without printing credential values:

```bash
openshell provider refresh status acme-okta-runtime --credential-key OKTA_ACCESS_TOKEN
openshell sandbox provider list <sandbox-name>
```

The direct runner `status` action reports the non-secret identity ownership receipt.
The `rollback` action verifies the current provider binding again, detaches it only when that apply created the sandbox attachment, and deletes it only when that apply created the provider.
Rollback stops without mutating a same-name provider when the binding no longer matches the receipt.

Runtime identity does not add a generic blueprint middleware surface in this slice.
Configure any deployment-specific pre-credential policy through separately supported OpenShell tooling.
This reference does not package an OAuth bootstrap application, an on-behalf-of exchange, or a production identity middleware service.

## Sandbox Environment

<AgentOnly variant="openclaw,hermes">
Expand Down
51 changes: 51 additions & 0 deletions nemoclaw-blueprint/provider-profiles/okta-runtime-v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# Data-only reference for the experimental runtime identity contract.
# The direct runner fails closed for DNS-backed profile destinations while the
# pinned OpenShell runtime cannot preserve NemoClaw's validated peer across
# refresh and provider-profile import. This profile is not currently an
# activatable production Okta integration.
# The direct runner validates this complete credential-delivery shape before
# import, including the exact executable allowlist and enforced endpoint rule.
# Copy this file, replace the example authorization-server URL and API host,
# and review the endpoint rules before use.
id: okta-runtime-v1
display_name: Okta Runtime Credentials v1
description: Gateway-managed Okta access-token refresh for an attached sandbox
category: agent
credentials:
- name: OKTA_ACCESS_TOKEN
description: Short-lived Okta API access token
env_vars:
- OKTA_ACCESS_TOKEN
required: true
auth_style: bearer
header_name: authorization
refresh:
strategy: oauth2_refresh_token
token_url: https://example.okta.com/oauth2/default/v1/token
refresh_before_seconds: 300
max_lifetime_seconds: 3600
material:
- name: client_id
required: true
- name: refresh_token
required: true
secret: true
- name: client_secret
required: false
secret: true
endpoints:
- host: api.example.okta.com
port: 443
protocol: rest
enforcement: enforce
rules:
- allow: { method: GET, path: "/**" }
binaries:
- /usr/local/bin/node
- /usr/bin/node
- /usr/local/bin/curl
- /usr/bin/curl
inference_capable: false
Loading
Loading