User Story
As a platform operator driving the OpenShell gateway API (operator workspace mode, Kubernetes driver) to create sandboxes with bound provider credentials,
I want the provider environment revision to be stable while nothing changes,
so that the supervisor installs the provider credentials and policy updates apply promptly.
Problem Statement
When a provider profile has more than one entry in a map field (for example two annotations), the gateway reports a different provider environment revision on successive calls although no provider, profile or policy changed. In our runs GetSandboxProviderEnvironment alternated between exactly two provider_env_revision values from poll to poll for the same sandbox, and the configuration snapshot's revision did not match the environment's.
The revision hash includes the profile's protobuf encoding (hash_scoped_profile_revision in crates/openshell-server/src/provider_profile_sources.rs calls entry.response.encode_to_vec(); also lines 105 and 126 on main). ProviderProfile.annotations is map<string, string> and openshell-core's build does not configure ordered maps, so the encoded bytes depend on hash-map iteration order.
Impact / Why This Matters
- On every settings poll the supervisor logs
Settings poll: config change detected [... provider_env_changed:true], then CONFIG:FAIL_CLOSED [HIGH] Provider environment refresh failed; static credentials were revoked ... and Provider environment is unavailable or changed during preparation: provider credentials are withheld from the workload for as long as the sandbox runs.
ReportEndpointStatus fails with FailedPrecondition ("tool server endpoint status revisions do not match the current sandbox configuration") on every report.
- Sandbox startup can fail with
Startup configuration did not stabilize after 5 attempts, and a policy update took ~60 s to load instead of ~10 s, because preparation keeps being retried.
- Workaround: keep at most one entry in every map field of provider profiles. With one annotation the revision is stable, credentials are installed and policy updates load within ~10 s.
Acceptance Criteria
Reproduction Steps
- Import a provider profile with two annotations, e.g.
ImportProviderProfiles with annotations: {"example.com/a": "1", "example.com/b": "2"} and one credential.
- Create a provider of that type and a sandbox whose policy binds an endpoint to it (
credential_binding).
- Watch the gateway log line
GetSandboxProviderEnvironment request completed successfully ... provider_env_revision=<n> over a few minutes: the value alternates between two numbers.
- Watch the supervisor log: repeated
provider_env_changed:true and CONFIG:FAIL_CLOSED events.
- Repeat with a single annotation: the revision is stable and the events stop.
Environment
- OpenShell: gateway and supervisor v0.1.0 (Helm chart); the hashing code is unchanged on
main as of 2026-09-30
- OS: Ubuntu 24.04 (kernel 6.8)
- Runtime: Kubernetes v1.34 (kubeadm), containerd 2.3; sandboxes on runc and on Kata Containers 4.2 (Cloud Hypervisor), same result
- Deployment or integration: gateway in
workspace_mode = "operator", driven through the gateway gRPC API by a control plane that creates sandboxes, provider profiles and providers
Logs
OCSF CONFIG:DETECTED [INFO] Settings poll: config change detected [old_revision:... new_revision:... policy_changed:false provider_env_changed:true]
OCSF CONFIG:FAIL_CLOSED [HIGH] Provider environment refresh failed; static credentials were revoked and previous dynamic grants remain active
OCSF CONFIG:CONFIGURATION_ERROR [HIGH] Provider environment is unavailable or changed during preparation
WARN openshell_supervisor::endpoint_status: Endpoint status report failed transiently; retaining immutable snapshot
Gateway, same sandbox, consecutive polls (no changes in between):
GetSandboxProviderEnvironment request completed successfully ... provider_env_revision=12427382202249825736
GetSandboxProviderEnvironment request completed successfully ... provider_env_revision=9706283966309050004
GetSandboxProviderEnvironment request completed successfully ... provider_env_revision=12427382202249825736
User Story
As a platform operator driving the OpenShell gateway API (operator workspace mode, Kubernetes driver) to create sandboxes with bound provider credentials,
I want the provider environment revision to be stable while nothing changes,
so that the supervisor installs the provider credentials and policy updates apply promptly.
Problem Statement
When a provider profile has more than one entry in a map field (for example two
annotations), the gateway reports a different provider environment revision on successive calls although no provider, profile or policy changed. In our runsGetSandboxProviderEnvironmentalternated between exactly twoprovider_env_revisionvalues from poll to poll for the same sandbox, and the configuration snapshot's revision did not match the environment's.The revision hash includes the profile's protobuf encoding (
hash_scoped_profile_revisionincrates/openshell-server/src/provider_profile_sources.rscallsentry.response.encode_to_vec(); also lines 105 and 126 onmain).ProviderProfile.annotationsismap<string, string>andopenshell-core's build does not configure ordered maps, so the encoded bytes depend on hash-map iteration order.Impact / Why This Matters
Settings poll: config change detected [... provider_env_changed:true], thenCONFIG:FAIL_CLOSED [HIGH] Provider environment refresh failed; static credentials were revoked ...andProvider environment is unavailable or changed during preparation: provider credentials are withheld from the workload for as long as the sandbox runs.ReportEndpointStatusfails withFailedPrecondition("tool server endpoint status revisions do not match the current sandbox configuration") on every report.Startup configuration did not stabilize after 5 attempts, and a policy update took ~60 s to load instead of ~10 s, because preparation keeps being retried.Acceptance Criteria
GetSandboxProviderEnvironment) is identical across calls when providers, profiles and policy are unchanged, for profiles with several annotations (and any other map field).FAIL_CLOSEDprovider refresh events and noReportEndpointStatusFailedPreconditionin steady state.Reproduction Steps
ImportProviderProfileswithannotations: {"example.com/a": "1", "example.com/b": "2"}and one credential.credential_binding).GetSandboxProviderEnvironment request completed successfully ... provider_env_revision=<n>over a few minutes: the value alternates between two numbers.provider_env_changed:trueandCONFIG:FAIL_CLOSEDevents.Environment
mainas of 2026-09-30workspace_mode = "operator", driven through the gateway gRPC API by a control plane that creates sandboxes, provider profiles and providersLogs
Gateway, same sandbox, consecutive polls (no changes in between):