You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(credentials): resolver becomes a per-request callback
Replace the static-token storage model with a host-side callback that
produces the token at request-dispatch time, so resolvers can refresh
tokens (IMDS, OAuth, Key Vault, ...) without re-registering credentials.
Core (`hyperlight_sandbox`):
* `ResolverFn = Arc<dyn Fn() -> Result<String, String> + Send + Sync>`,
invoked once per credentialed outgoing request. The registry mutex
is released *before* the resolver runs, so a slow resolver cannot
stall unrelated requests.
* `CredentialEntry::with_static_resolver` for tests / short-lived
tokens.
* Manual `Debug` impl on `CredentialEntry` renders the resolver as
`<callback>` so captured secrets cannot leak via logs, panics, or
`dbg!` output.
* Re-export `ResolverFn` from the crate root.
Wire path (`wasi_impl/http_handler.rs`):
* Clone the credential entry by id, drop the mutex, enforce scope
(URL prefix) before the existing `allow_domain` network gate,
invoke the resolver, filter any guest-set header of the same name
(case-insensitive), then inject `<header>: <prefix><token>`.
* On resolver `Err`, the diagnostic is dropped before crossing the
guest boundary; the guest sees only
`InternalError("credential resolver failed")`. `ResolverFn` rustdoc
updated to match this behaviour (was previously inaccurate).
Python SDK (`hyperlight_sandbox` / `wasm_backend`):
* `register_credential(..., resolver: Callable[[], str])` accepts any
zero-arg Python callable. The PyO3 bridge re-acquires the GIL on
every invocation. When the resolver raises, only the exception
**type name** is forwarded across the FFI boundary; the message
body is dropped (it may have been assembled from secret material).
Integration tests (`src/wasm_sandbox/tests/credential_integration.rs`):
* `resolver_invoked_per_request` — atomic counter + rotating tokens
prove the resolver runs on every request, not once at registration.
* `resolver_failure_surfaces_as_error` — resolver returns a
secret-bearing diagnostic; the test asserts the diagnostic is
absent from guest stdout and from the surfaced error payload.
* `isolated_registries_across_sandboxes` — two sandboxes register the
same credential id with different tokens; each sees only its own.
Hygiene:
* Fix joined-line whitespace bug in `wasm_backend/src/lib.rs`.
* Sort `sandbox_executor` imports in guest `hyperlight.py` for the
new `attach_credential` entry (was `I001`).
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
0 commit comments