Services¶
registry ¶
Gateway registry: persistent list of every known OpenShell endpoint.
Single source of truth for "which gateways does ShoreGuard know
about". Backed by the gateways SQL table. Tracks connection
material (endpoint, scheme, auth mode, mTLS cert bundle),
per-gateway metadata the UI consumes (labels, free-text
description), and the last-known health status maintained by the
background health monitor.
The registry intentionally does not own live gRPC clients — those
belong to :class:~shoreguard.services.gateway.GatewayService.
Keeping CRUD separate from client lifecycle means a registry
edit never has to worry about tearing down an in-flight call.
GatewayRegistry ¶
Persistent CRUD and health tracking for registered gateways.
Handles insert / update / delete of gateway rows, label + metadata
merging, and lazy health-status updates from the background health
monitor. Does not manage live gRPC channels — those live in
:class:~shoreguard.services.gateway.GatewayService — and does
not enforce endpoint-format validation, which is applied at the
API route layer before any call reaches this service.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_factory
|
sessionmaker[Session]
|
SQLAlchemy session factory used to open a fresh session per call. |
required |
register ¶
register(
name: str,
endpoint: str,
scheme: str = "https",
auth_mode: str | None = "mtls",
*,
ca_cert: bytes | None = None,
client_cert: bytes | None = None,
client_key: bytes | None = None,
metadata: dict[str, Any] | None = None,
description: str | None = None,
labels: dict[str, str] | None = None,
) -> dict[str, Any]
Register a new gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Unique gateway name. |
required |
endpoint
|
str
|
Gateway endpoint address. |
required |
scheme
|
str
|
Connection scheme (e.g. "https"). |
'https'
|
auth_mode
|
str | None
|
Authentication mode (e.g. "mtls"). |
'mtls'
|
ca_cert
|
bytes | None
|
CA certificate bytes for TLS. |
None
|
client_cert
|
bytes | None
|
Client certificate bytes for mTLS. |
None
|
client_key
|
bytes | None
|
Client private key bytes for mTLS. |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata dict. |
None
|
description
|
str | None
|
Optional free-text description. |
None
|
labels
|
dict[str, str] | None
|
Optional key-value labels for filtering. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: The registered gateway record. |
Raises:
| Type | Description |
|---|---|
ConflictError
|
If a gateway with the given name already exists. |
unregister ¶
Remove a gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name to unregister. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the gateway existed and was removed. |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the commit fails. |
get ¶
Return a single gateway or None.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
dict[str, Any] | None: Gateway record, or None if not found. |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the query fails. |
list_all ¶
Return all registered gateways, optionally filtered by labels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
labels_filter
|
dict[str, str] | None
|
If provided, only return gateways whose labels contain all specified key-value pairs. |
None
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Gateway records ordered by name. |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the query fails. |
update_health ¶
Update health status and last-seen timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
status
|
str
|
New health status string. |
required |
last_seen
|
datetime
|
Timestamp of the health check. |
required |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the commit fails. |
update_metadata ¶
Replace the metadata JSON blob.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
metadata
|
dict[str, Any]
|
New metadata dict to store. |
required |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the commit fails. |
update_gateway_metadata ¶
update_gateway_metadata(
name: str,
*,
description: str | None | object = _UNSET,
labels: dict[str, str] | None | object = _UNSET,
) -> dict[str, Any] | None
Update description and/or labels for a gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
description
|
str | None | object
|
New description, None to clear, or _UNSET to skip. |
_UNSET
|
labels
|
dict[str, str] | None | object
|
New labels dict, None to clear, or _UNSET to skip. |
_UNSET
|
Returns:
| Type | Description |
|---|---|
dict[str, Any] | None
|
dict[str, Any] | None: Updated gateway dict, or None if not found. |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the commit fails. |
get_credentials ¶
Return raw cert bytes for a gateway (for connection logic only).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str | bytes | None] | None
|
dict[str, str | bytes | None] | None: Credential dict, or None if not found. |
Raises:
| Type | Description |
|---|---|
SQLAlchemyError
|
If the query fails. |
gateway ¶
Live gRPC channel management for registered gateways.
Companion to :mod:shoreguard.services.registry: the registry
owns what gateways exist, this module owns the actual live
:class:ShoreGuardClient instances connected to each one.
Provides lazy client lookup, connection health probing, graceful
channel shutdown on gateway removal, and an in-memory cache so
every API call does not pay the mTLS handshake cost.
Separating client lifecycle from persistent CRUD means registry edits (e.g. rename, label change) never need to tear down an in-flight call, and a channel failure only affects the one gateway rather than wedging the whole service.
GatewayService ¶
Gateway connection management and registry-backed discovery.
Handles gRPC client connections, backoff, health probing, and gateway registration/unregistration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
registry
|
GatewayRegistry
|
Gateway registry for persistence. |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
registry |
GatewayRegistry
|
The underlying gateway registry. |
get_client ¶
Return a client for the given gateway, attempting reconnect with backoff.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ShoreGuardClient |
ShoreGuardClient
|
Connected gRPC client. |
Raises:
| Type | Description |
|---|---|
GatewayNotConnectedError
|
If connection fails. |
set_client ¶
Set or clear a client for the given gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
ShoreGuardClient | None
|
Client to cache, or None to clear. |
required |
name
|
str
|
Gateway name. |
required |
reset_backoff ¶
Reset connection backoff for a gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
register ¶
register(
name: str,
endpoint: str,
scheme: str = "https",
auth_mode: str | None = "mtls",
*,
ca_cert: bytes | None = None,
client_cert: bytes | None = None,
client_key: bytes | None = None,
metadata: dict[str, Any] | None = None,
description: str | None = None,
labels: dict[str, str] | None = None,
) -> dict[str, Any]
Register a gateway and attempt initial connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Unique gateway name. |
required |
endpoint
|
str
|
Gateway endpoint address. |
required |
scheme
|
str
|
Connection scheme (e.g. "https"). |
'https'
|
auth_mode
|
str | None
|
Authentication mode (e.g. "mtls"). |
'mtls'
|
ca_cert
|
bytes | None
|
CA certificate bytes for TLS. |
None
|
client_cert
|
bytes | None
|
Client certificate bytes for mTLS. |
None
|
client_key
|
bytes | None
|
Client private key bytes for mTLS. |
None
|
metadata
|
dict[str, Any] | None
|
Optional metadata dict. |
None
|
description
|
str | None
|
Optional free-text description. |
None
|
labels
|
dict[str, str] | None
|
Optional key-value labels for filtering. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Gateway record with connection status. |
unregister ¶
Unregister a gateway and close its connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the gateway existed and was removed. |
test_connection ¶
Explicitly test connectivity to a registered gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Connection test result. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the gateway is not registered. |
update_gateway_metadata ¶
update_gateway_metadata(
name: str,
*,
description: str | None | object = _UNSET,
labels: dict[str, str] | None | object = _UNSET,
) -> dict[str, Any]
Update description and/or labels for a gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
description
|
str | None | object
|
New description, None to clear, or sentinel to skip. |
_UNSET
|
labels
|
dict[str, str] | None | object
|
New labels dict, None to clear, or sentinel to skip. |
_UNSET
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated gateway record. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the gateway does not exist. |
list_all ¶
List all registered gateways with cached connection status.
Uses the cached client state instead of live health probes to avoid
N+1 blocking gRPC calls. The background health monitor keeps
last_status up-to-date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
labels_filter
|
dict[str, str] | None
|
If provided, only return gateways matching all specified label key-value pairs. |
None
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Gateway records with connection status. |
get_info ¶
Get detailed info for a gateway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Detailed gateway information. |
get_config ¶
Fetch the gateway configuration via gRPC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Gateway configuration. |
update_setting ¶
update_setting(
name: str,
key: str,
value: str | bool | int | None = None,
*,
delete: bool = False,
) -> dict[str, Any]
Update (or delete) a single global gateway setting via gRPC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
key
|
str
|
Setting key. |
required |
value
|
str | bool | int | None
|
New value. Ignored when |
None
|
delete
|
bool
|
If True, remove the setting instead of updating it. |
False
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: |
check_all_health ¶
Probe all registered gateways and update their health in the registry.
get_cached_client ¶
Return the cached client for a gateway, or None if not connected.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
ShoreGuardClient | None
|
ShoreGuardClient | None: Cached client, or None. |
sandbox ¶
Sandbox lifecycle operations: create, list, delete, exec, metadata.
Wraps the ShoreGuardClient.sandboxes gRPC surface with
behavior the raw client does not provide: merging sandbox
metadata from the local sandbox_meta_store into list + detail
responses, running pre-create validation hooks before
CreateSandbox reaches the gateway, and running post-create
warm-up hooks inside the new sandbox once it is up.
The create flow is intentionally centralised here so both the Web UI and the TUI can share the same preset-application + metadata + boot-hook sequence — earlier versions of ShoreGuard duplicated most of it in browser JS.
SandboxService ¶
SandboxService(
client: ShoreGuardClient,
meta_store: SandboxMetaStore | None = None,
*,
boot_hooks: BootHookService | None = None,
gateway_name: str | None = None,
)
Gateway-scoped sandbox lifecycle operations.
One instance is constructed per (gateway, operation)
invocation so the embedded gRPC client is already bound to
the right endpoint. Methods are synchronous because the gRPC
client is synchronous; async callers wrap them via
asyncio.to_thread.
Metadata merging, preset application, and pre/post-create hook dispatch happen inside this service rather than in the route layer so the same flow is available to the TUI and any future programmatic client without duplicated code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
ShoreGuardClient
|
OpenShell gRPC client bound to the target gateway. |
required |
meta_store
|
SandboxMetaStore | None
|
Optional store for sandbox labels + description kept locally in ShoreGuard (OpenShell does not model them). |
None
|
boot_hooks
|
BootHookService | None
|
Optional hook service invoked around
|
None
|
gateway_name
|
str | None
|
Gateway name this service is bound to, used
for hook lookups when |
None
|
list ¶
list(
*,
limit: int = 100,
offset: int = 0,
gateway_name: str | None = None,
labels_filter: dict[str, str] | None = None,
) -> list[dict[str, Any]]
List all sandboxes with merged metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of sandboxes to return. |
100
|
offset
|
int
|
Number of sandboxes to skip. |
0
|
gateway_name
|
str | None
|
Gateway name for metadata lookup. |
None
|
labels_filter
|
dict[str, str] | None
|
Filter sandboxes by label key-value pairs. |
None
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Sandbox records with metadata. |
get ¶
Get a sandbox by name with merged metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
gateway_name
|
str | None
|
Gateway name for metadata lookup. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Sandbox record with metadata. |
delete ¶
Delete a sandbox by name and clean up metadata.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
gateway_name
|
str | None
|
Gateway name for metadata cleanup. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the sandbox was deleted. |
exec ¶
exec(
name: str,
command: str | list[str],
*,
workdir: str = "",
env: dict[str, str] | None = None,
timeout_seconds: int = 0,
tty: bool = False,
) -> dict[str, Any]
Execute a command inside a sandbox.
Accepts command as a raw string (parsed with shlex) or list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
command
|
str | list[str]
|
Command as a string or list of arguments. |
required |
workdir
|
str
|
Working directory inside the sandbox. |
''
|
env
|
dict[str, str] | None
|
Environment variables to set. |
None
|
timeout_seconds
|
int
|
Execution timeout (0 for no timeout). |
0
|
tty
|
bool
|
Allocate a TTY for the command (for interactive programs). |
False
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Execution result with stdout, stderr, exit code. |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If the command string has invalid syntax. |
get_logs ¶
get_logs(
name: str,
*,
lines: int = 200,
since_ms: int = 0,
sources: list[str] | None = None,
min_level: str = "",
) -> list[dict[str, Any]]
Fetch recent logs from a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
lines
|
int
|
Maximum number of log lines to return. |
200
|
since_ms
|
int
|
Only return logs after this epoch millisecond timestamp. |
0
|
sources
|
list[str] | None
|
Filter by log source names. |
None
|
min_level
|
str
|
Minimum log level filter. |
''
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Log entries. |
create_ssh_session ¶
Create an SSH session for a sandbox, resolving name to ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: SSH session details including token. |
get_config ¶
Get the stored sandbox configuration from the gateway.
Resolves name to sandbox id, then calls GetSandboxConfig. The
returned dict is the gateway-side spec (policy, providers,
template, etc.) as the gateway currently has it recorded — the
source of truth for "what is this sandbox configured with" in the
pinning / GitOps workflow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Sandbox configuration as returned by the gateway. |
get_provider_environment ¶
Get the provider environment variables injected into a sandbox.
Resolves name to sandbox id, then calls
GetSandboxProviderEnvironment. Returns the env map the
gateway will hand to the sandbox's runtime when it launches.
Values may be secret — callers that surface this over REST
should redact against the shared secret-key pattern.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
dict[str, str]: Environment key-value pairs. |
list_providers ¶
List provider records attached to a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name (canonical lookup key). |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Attached provider records. |
attach_provider ¶
Attach a provider record to a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
provider_name
|
str
|
Provider name to attach. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: |
detach_provider ¶
Detach a provider record from a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name. |
required |
provider_name
|
str
|
Provider name to detach. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: |
revoke_ssh_session ¶
Revoke an active SSH session by token.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
Session token to revoke. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the session was revoked. |
update_metadata ¶
update_metadata(
gateway_name: str,
name: str,
*,
description: str | None | object = _UNSET,
labels: dict[str, str] | None | object = _UNSET,
) -> dict[str, Any]
Update labels and/or description for a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gateway_name
|
str
|
Name of the gateway. |
required |
name
|
str
|
Sandbox name. |
required |
description
|
str | None | object
|
New description (or _UNSET to skip). |
_UNSET
|
labels
|
dict[str, str] | None | object
|
New labels (or _UNSET to skip). |
_UNSET
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated sandbox record with metadata. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If no meta store is configured. |
create ¶
create(
*,
name: str = "",
image: str = "",
gpu: bool = False,
providers: list[str] | None = None,
environment: dict[str, str] | None = None,
presets: list[str] | None = None,
gateway_name: str | None = None,
description: str | None = None,
labels: dict[str, str] | None = None,
skip_hooks: bool = False,
log_level: str = "",
) -> dict[str, Any]
Create a sandbox and optionally apply presets.
This replaces the multi-step wizard polling loop that was in the browser JS. The entire workflow happens server-side: 1. Create sandbox 2. Wait for ready state 3. Wait for initial policy 4. Apply presets sequentially
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Sandbox name (empty for auto-generated). |
''
|
image
|
str
|
Container image to use. |
''
|
gpu
|
bool
|
Whether to enable GPU support. |
False
|
providers
|
list[str] | None
|
Provider names to attach. |
None
|
environment
|
dict[str, str] | None
|
Environment variables to set. |
None
|
presets
|
list[str] | None
|
Policy presets to apply after creation. |
None
|
gateway_name
|
str | None
|
Gateway name for metadata storage. |
None
|
description
|
str | None
|
Optional sandbox description. |
None
|
labels
|
dict[str, str] | None
|
Optional sandbox labels. |
None
|
skip_hooks
|
bool
|
If true, bypass pre/post boot hook execution (admin override for cases where a broken hook would block recreation). |
False
|
log_level
|
str
|
Supervisor log verbosity (empty = gateway default). |
''
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Created sandbox record with preset status |
dict[str, Any]
|
and (when hooks ran) |
dict[str, Any]
|
hook failures bubble up as |
dict[str, Any]
|
hook service. |
policy ¶
High-level sandbox policy operations for UI and API callers.
Wraps the gRPC ShoreGuardClient.policies surface with
additional behavior the raw client does not offer: atomic
add/delete of individual network rules and filesystem paths over
a read-modify-write loop, eager preset resolution into the stored
policy so the gateway's effective view matches the declared
document, and submit-time capture of denial context so the
approval detail modal can render binary ancestry and L7 samples
without a round-trip.
PolicyService ¶
Policy management shared by the Web UI, TUI, and REST API.
Thin wrapper over ShoreGuardClient.policies that lifts a
few operations up from the raw gRPC surface: atomic single-rule
CRUD (against an API that only exposes replace-whole-policy),
preset application with server-side merge, and denial-context
capture for approvals. Everything is synchronous because the
gRPC client is synchronous; callers that need to avoid blocking
the event loop wrap individual methods in asyncio.to_thread.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
ShoreGuardClient
|
OpenShell gRPC client scoped to the target gateway. |
required |
get ¶
Get the current active policy for a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Policy data. |
get_effective ¶
Get the effective policy — what the gateway currently enforces.
In the current architecture, presets are merged eagerly into the
declared policy at apply time (read-modify-write in
:meth:apply_preset), so the gateway's stored policy is already
the fully resolved document. This method returns that document
under a stable /policy/effective contract, giving the UI and
API clients a dedicated endpoint that will keep working if
OpenShell ever separates declared from effective server-side.
The return value is the same envelope policies.get returns
(active_version, revision, policy) with an added
source: "gateway_runtime" marker so callers can distinguish
this response from the plain GET /policy route.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Effective policy envelope. |
submit_analysis ¶
submit_analysis(
sandbox_name: str,
*,
summaries: list[dict[str, Any]],
proposed_chunks: list[dict[str, Any]],
analysis_mode: str = "",
) -> dict[str, Any]
Forward a policy analysis submission to the gateway.
Thin pass-through to :meth:PolicyManager.submit_analysis. The
gateway merges accepted chunks into the draft policy; rejected
chunks come back with a per-chunk reason. Used by external
analyzers (LLM-backed or rule-based) that observe sandbox denials
and propose fixes — ShoreGuard itself does not generate analysis
results, it only brokers them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Target sandbox name. |
required |
summaries
|
list[dict[str, Any]]
|
|
required |
proposed_chunks
|
list[dict[str, Any]]
|
|
required |
analysis_mode
|
str
|
Opaque mode tag forwarded verbatim, e.g.
|
''
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: ``{"accepted_chunks": int, "rejected_chunks": |
dict[str, Any]
|
int, "rejection_reasons": list[str]}``. |
update ¶
Push a new policy version and return the full PolicyResponse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
policy_dict
|
dict
|
Policy content as a dict. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
update_merge ¶
Apply incremental merge operations and return the fresh policy.
Thin wrapper over
:meth:shoreguard.client.policies.PolicyManager.apply_merge_operations
that reshapes the response into the same PolicyResponse
envelope :meth:update returns, so route handlers can treat the
two write paths as interchangeable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
operations
|
list[dict[str, Any]]
|
Ordered merge-operation dicts, as synthesised by
:func: |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
get_version ¶
Get a specific policy revision by version number.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
version
|
int
|
Revision version number. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Policy revision data. |
diff_revisions ¶
Fetch two revisions and return both for client-side diffing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
version_a
|
int
|
First revision version number. |
required |
version_b
|
int
|
Second revision version number. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Both policy revisions for comparison. |
list_revisions ¶
List policy revision history.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
limit
|
int
|
Maximum number of revisions to return. |
20
|
offset
|
int
|
Number of revisions to skip. |
0
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Revision history entries. |
apply_preset ¶
Apply a policy preset to a sandbox (merges network_policies).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
preset_name
|
str
|
Name of the preset to apply. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If the preset name is not found. |
add_network_rule ¶
Add or update a single network rule (read-modify-write).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
key
|
str
|
Network rule key. |
required |
rule
|
dict[str, Any]
|
Rule definition dict. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
delete_network_rule ¶
Delete a single network rule (read-modify-write).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
key
|
str
|
Network rule key to remove. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
add_filesystem_path ¶
Add a filesystem path (read-modify-write).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
path
|
str
|
Filesystem path to add. |
required |
access
|
str
|
Access mode ("ro" or "rw"). |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
delete_filesystem_path ¶
Delete a filesystem path (read-modify-write).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
path
|
str
|
Filesystem path to remove. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
update_process_policy ¶
update_process_policy(
sandbox_name: str,
*,
run_as_user: str | None = None,
run_as_group: str | None = None,
landlock_compatibility: str | None = None,
) -> dict[str, Any]
Update process and landlock settings (read-modify-write).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
run_as_user
|
str | None
|
User to run processes as. |
None
|
run_as_group
|
str | None
|
Group to run processes as. |
None
|
landlock_compatibility
|
str | None
|
Landlock compatibility level. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated policy response. |
approvals ¶
Draft-policy approval workflow wrapper over the gRPC approval RPCs.
OpenShell's approval flow works in terms of draft policy chunks: each time a denial fires, the gateway emits a chunk that proposes the rules that would allow the blocked action. This service mediates the operator-facing view of that flow — listing pending chunks, approving / rejecting / editing individual ones, and supporting bulk approve-all and undo operations.
The service is deliberately thin: almost every call forwards
directly to ShoreGuardClient.approvals with additional
request-level validation and audit logging. Multi-stage quorum
is not handled here — that lives in
:class:~shoreguard.services.approval_workflow.ApprovalWorkflowService,
which the approval route consults before calling through to
this service.
ApprovalService ¶
Draft policy approval operations shared by Web UI and TUI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
ShoreGuardClient
|
OpenShell gRPC client instance. |
required |
get_draft ¶
Get draft policy recommendations for a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
status_filter
|
str
|
Optional status to filter by. |
''
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Draft policy data with denial context enrichment. |
get_pending ¶
Get only pending (unapproved) draft chunks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Pending draft chunks with denial context. |
approve ¶
Approve a single draft policy chunk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
chunk_id
|
str
|
Identifier of the chunk to approve. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated chunk data. |
reject ¶
Reject a single draft policy chunk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
chunk_id
|
str
|
Identifier of the chunk to reject. |
required |
reason
|
str
|
Optional reason for rejection. |
''
|
approve_all ¶
Approve all pending draft chunks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
include_security_flagged
|
bool
|
Whether to include security-flagged chunks. |
False
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Summary of approved chunks. |
edit ¶
Edit a pending draft chunk's proposed rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
chunk_id
|
str
|
Identifier of the chunk to edit. |
required |
proposed_rule
|
dict
|
New proposed rule content. |
required |
undo ¶
Reverse an approval decision.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
chunk_id
|
str
|
Identifier of the chunk to undo. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Updated chunk data. |
clear ¶
Clear all pending draft chunks for a sandbox.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
dict[str, int]: Count of cleared chunks. |
get_history ¶
Get decision history for a sandbox's draft policy.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sandbox_name
|
str
|
Name of the sandbox. |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Decision history entries. |
operations ¶
Persistent state for long-running async operations.
Some REST endpoints — sandbox create, SSH session setup, gateway
restart — take long enough that returning 202 with an operation
id is better than holding the HTTP connection open. This service
backs that pattern: endpoints enqueue an operation, return the
id, and clients poll GET /operations/{id} until the status
flips from running to a terminal value.
Operations are stored in SQL so a poll survives server restarts and fan out across replicas via the shared database. The worker side of each operation lives in the calling service; this module only owns lifecycle and state transitions.
AsyncOperationService ¶
AsyncOperationService(
session_factory: async_sessionmaker[AsyncSession],
running_ttl: float = 600.0,
retention_days: int = 30,
)
DB-backed operation tracking using async SQLAlchemy.
Provides create/start/complete/fail/cancel plus cleanup helpers, with
an in-memory task registry that lets cancel() interrupt a running
asyncio task.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_factory
|
async_sessionmaker[AsyncSession]
|
Async SQLAlchemy session factory. |
required |
running_ttl
|
float
|
Seconds before a stuck running operation is timed out. |
600.0
|
retention_days
|
int
|
Days to keep completed operations before cleanup. |
30
|
create
async
¶
create(
resource_type: str,
resource_key: str,
*,
actor: str | None = None,
gateway_name: str | None = None,
idempotency_key: str | None = None,
) -> OperationRecord
Create a new operation in pending state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource_type
|
str
|
Type of resource being operated on. |
required |
resource_key
|
str
|
Name of the resource. |
required |
actor
|
str | None
|
Identity of the user starting the operation. |
None
|
gateway_name
|
str | None
|
Gateway the operation targets. |
None
|
idempotency_key
|
str | None
|
Optional client-provided idempotency key. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
OperationRecord |
OperationRecord
|
The newly created operation record. |
create_if_not_running
async
¶
create_if_not_running(
resource_type: str,
resource_key: str,
*,
actor: str | None = None,
gateway_name: str | None = None,
idempotency_key: str | None = None,
) -> OperationRecord | None
Create a new operation if none is active for this resource.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource_type
|
str
|
Type of resource being operated on. |
required |
resource_key
|
str
|
Name of the resource. |
required |
actor
|
str | None
|
Identity of the user starting the operation. |
None
|
gateway_name
|
str | None
|
Gateway the operation targets. |
None
|
idempotency_key
|
str | None
|
Optional client-provided idempotency key. |
None
|
Returns:
| Type | Description |
|---|---|
OperationRecord | None
|
OperationRecord | None: The new operation, or None if one is already active. |
start
async
¶
Transition pending → running.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID to start. |
required |
complete
async
¶
Mark an operation as succeeded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID to complete. |
required |
result
|
dict[str, Any]
|
Result payload to store. |
required |
fail
async
¶
Mark an operation as failed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID to mark as failed. |
required |
error
|
str
|
Human-readable error message. |
required |
error_code
|
str
|
Machine-readable error code. |
internal
|
update_progress
async
¶
Update progress for an active operation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID to update. |
required |
pct
|
int
|
Progress percentage (0-100). |
required |
message
|
str | None
|
Optional progress message. |
None
|
get
async
¶
Get an operation by ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID to look up. |
required |
Returns:
| Type | Description |
|---|---|
OperationRecord | None
|
OperationRecord | None: The operation record, or None if not found. |
get_by_idempotency_key
async
¶
Look up an operation by its idempotency key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The idempotency key to search for. |
required |
Returns:
| Type | Description |
|---|---|
OperationRecord | None
|
OperationRecord | None: The matching operation record, or None. |
list_ops
async
¶
list_ops(
*,
status: str | None = None,
resource_type: str | None = None,
limit: int = 50,
offset: int = 0,
) -> tuple[list[OperationRecord], int]
List operations with optional filtering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
status
|
str | None
|
Filter by status. |
None
|
resource_type
|
str | None
|
Filter by resource type. |
None
|
limit
|
int
|
Maximum number of results (max 200). |
50
|
offset
|
int
|
Number of results to skip. |
0
|
Returns:
| Type | Description |
|---|---|
tuple[list[OperationRecord], int]
|
tuple[list[OperationRecord], int]: Tuple of (operations, total_count). |
is_running
async
¶
Check if there is an active operation for the given resource.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource_type
|
str
|
Type of resource to check. |
required |
resource_key
|
str
|
Name of the resource to check. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if an active (pending/running) operation exists. |
status_counts
async
¶
Return counts of operations grouped by status.
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
dict[str, int]: Mapping of status to count. |
register_task ¶
Register an asyncio task for cancellation support.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID. |
required |
task
|
Task[None]
|
The asyncio task running the operation. |
required |
cancel
async
¶
Cancel an active operation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op_id
|
str
|
The operation ID to cancel. |
required |
Returns:
| Type | Description |
|---|---|
OperationRecord | None
|
OperationRecord | None: The updated operation record, or None if |
OperationRecord | None
|
not found or not active. |
recover_orphans
async
¶
Mark all active operations as failed (startup recovery).
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
Number of orphaned operations recovered. |
cleanup
async
¶
Expire stuck active operations and remove old completed ones.
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
Number of operations cleaned up. |
to_dict
staticmethod
¶
Convert an operation record to a JSON-serializable dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
op
|
OperationRecord
|
The operation record to convert. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: JSON-serializable representation for the API. |
providers ¶
LLM provider CRUD with schema metadata from openshell.yaml.
Providers are the named credential containers OpenShell uses to
route sandbox inference (Anthropic, OpenAI, Nvidia, ...). This
service wraps the gRPC provider RPCs and overlays schema metadata
read from the gateway's openshell.yaml so the UI can render
a typed form rather than a generic KV editor: which fields each
provider type requires, which are secret, which are optional,
and what the default env-var projection looks like.
Credentials only flow one way — into the service — and are never
returned in responses; the /env projection redacts values to
[REDACTED] with a source annotation so operators can
debug provider configuration without seeing the secret material.
ProviderService ¶
Provider management shared by Web UI and TUI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
ShoreGuardClient
|
OpenShell gRPC client instance. |
required |
list ¶
List all providers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of providers to return. |
100
|
offset
|
int
|
Number of providers to skip. |
0
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Provider records. |
get ¶
Get a provider by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Provider name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Provider record. |
create ¶
create(
*,
name: str,
provider_type: str,
api_key: str,
extra_credentials: dict[str, str] | None = None,
config: dict[str, str] | None = None,
) -> dict[str, Any]
Create a provider with automatic credential key mapping.
Looks up the correct environment variable name from openshell.yaml. Falls back to API_KEY for unknown types.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Provider name. |
required |
provider_type
|
str
|
Provider type identifier. |
required |
api_key
|
str
|
Primary API key value. |
required |
extra_credentials
|
dict[str, str] | None
|
Additional credential key-value pairs. |
None
|
config
|
dict[str, str] | None
|
Optional provider configuration. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: The created provider record. |
update ¶
update(
*,
name: str,
provider_type: str = "",
credentials: dict[str, str] | None = None,
config: dict[str, str] | None = None,
) -> dict[str, Any]
Update an existing provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Provider name. |
required |
provider_type
|
str
|
New provider type (empty string to keep current). |
''
|
credentials
|
dict[str, str] | None
|
New credential key-value pairs. |
None
|
config
|
dict[str, str] | None
|
New provider configuration. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: The updated provider record. |
delete ¶
Delete a provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Provider name. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the provider was deleted. |
configure_refresh ¶
configure_refresh(
*,
provider: str,
credential_key: str,
strategy: str,
material: dict[str, str] | None = None,
secret_material_keys: list[str] | None = None,
expires_at_ms: int | None = None,
) -> dict[str, Any]
Configure automatic refresh for a provider credential.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider name. |
required |
credential_key
|
str
|
Credential key within the provider to refresh. |
required |
strategy
|
str
|
Refresh strategy (e.g. |
required |
material
|
dict[str, str] | None
|
Strategy-specific material (token URLs, client ids, etc.). |
None
|
secret_material_keys
|
list[str] | None
|
Keys within material that hold secret values. |
None
|
expires_at_ms
|
int | None
|
Optional absolute expiry of the current credential. |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: The resulting refresh status. |
get_refresh_status ¶
List credential-refresh status entries for a provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider name. |
required |
credential_key
|
str
|
Optional credential key; empty returns all entries. |
''
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: One status dict per configured credential. |
rotate_credential ¶
Rotate a provider credential immediately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider name. |
required |
credential_key
|
str
|
Credential key to rotate. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: The refresh status after rotation. |
delete_refresh ¶
Delete a credential-refresh configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider name. |
required |
credential_key
|
str
|
Credential key whose refresh config is removed. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if a configuration existed and was deleted. |
get_env ¶
Get the redacted environment projection for a provider.
Returns the environment variables this provider injects into
sandboxes. Secret values are never included — only keys, their
source (credential, config, type_default), and a
constant [REDACTED] placeholder.
The key set is derived from three places:
- Every key in the provider's
credentialsdict (source=credential). - Every key in the provider's
configdict (source=config). - The provider type's
cred_keyfromopenshell.yaml(source=type_default), added only if it was not already present in the credentials dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Provider name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Record with |
list_known_types
staticmethod
¶
Return metadata about known provider types from openshell.yaml.
Returns:
| Type | Description |
|---|---|
list[dict[str, str]]
|
list[dict[str, str]]: Provider type metadata records. |
audit ¶
Persistent audit log for every state-changing operation.
Every API route that mutates state calls audit_log with a
short action verb (policy.update, approval.approved,
sbom.uploaded, ...), a resource type, a resource id, and
optional detail payload. The row is written asynchronously so a
slow audit path never blocks the request, and a background task
fans it out to the webhook pipeline.
The audit log is the single source of truth for "who did what when" — it is filterable, exportable as CSV or JSON, and deliberately append-only. Retention is up to operators; there is no built-in prune.
AuditIntegrityError ¶
Bases: RuntimeError
Raised when code tries to mutate or delete an AuditEntry illegally.
AuditService ¶
DB-backed audit trail for all state-changing operations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_factory
|
sessionmaker
|
SQLAlchemy session factory for database access. |
required |
exporter
|
AuditExporter | None
|
Optional :class: |
None
|
log ¶
log(
*,
actor: str,
actor_role: str,
action: str,
resource_type: str,
resource_id: str = "",
gateway: str | None = None,
detail: dict[str, Any] | None = None,
client_ip: str | None = None,
) -> None
Write an audit entry. Never raises -- failures are logged and swallowed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
actor
|
str
|
Identity of the user performing the action. |
required |
actor_role
|
str
|
Role of the actor (e.g. "admin", "viewer"). |
required |
action
|
str
|
Action being performed (e.g. "create", "delete"). |
required |
resource_type
|
str
|
Type of resource affected. |
required |
resource_id
|
str
|
Identifier of the affected resource. |
''
|
gateway
|
str | None
|
Optional gateway name for scoping. |
None
|
detail
|
dict[str, Any] | None
|
Optional structured detail payload. |
None
|
client_ip
|
str | None
|
IP address of the client. |
None
|
list ¶
list(
*,
limit: int = 100,
offset: int = 0,
actor: str | None = None,
action: str | None = None,
resource_type: str | None = None,
gateway: str | None = None,
since: str | None = None,
until: str | None = None,
) -> list[dict[str, Any]]
Query audit entries with optional filters and pagination.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of entries to return. |
100
|
offset
|
int
|
Number of entries to skip. |
0
|
actor
|
str | None
|
Filter by actor identity. |
None
|
action
|
str | None
|
Filter by action type. |
None
|
resource_type
|
str | None
|
Filter by resource type. |
None
|
gateway
|
str | None
|
Filter by gateway name (matches the |
None
|
since
|
str | None
|
ISO-format start timestamp filter. |
None
|
until
|
str | None
|
ISO-format end timestamp filter. |
None
|
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
list[dict[str, Any]]: Matching audit entries. |
list_with_count ¶
list_with_count(
*,
limit: int = 100,
offset: int = 0,
actor: str | None = None,
action: str | None = None,
resource_type: str | None = None,
gateway: str | None = None,
since: str | None = None,
until: str | None = None,
) -> tuple[list[dict[str, Any]], int]
Query audit entries with total count for pagination.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
limit
|
int
|
Maximum number of entries to return. |
100
|
offset
|
int
|
Number of entries to skip. |
0
|
actor
|
str | None
|
Filter by actor identity. |
None
|
action
|
str | None
|
Filter by action type. |
None
|
resource_type
|
str | None
|
Filter by resource type. |
None
|
gateway
|
str | None
|
Filter by gateway name. |
None
|
since
|
str | None
|
ISO-format start timestamp filter. |
None
|
until
|
str | None
|
ISO-format end timestamp filter. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[list[dict[str, Any]], int]
|
tuple[list[dict[str, Any]], int]: Entries and total matching count. |
export_csv ¶
export_csv(
*,
actor: str | None = None,
action: str | None = None,
resource_type: str | None = None,
gateway: str | None = None,
since: str | None = None,
until: str | None = None,
) -> str
Export audit entries as a CSV string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
actor
|
str | None
|
Filter by actor identity. |
None
|
action
|
str | None
|
Filter by action type. |
None
|
resource_type
|
str | None
|
Filter by resource type. |
None
|
gateway
|
str | None
|
Filter by gateway name. |
None
|
since
|
str | None
|
ISO-format start timestamp filter. |
None
|
until
|
str | None
|
ISO-format end timestamp filter. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
CSV-formatted string of matching entries. |
cleanup ¶
Delete audit entries older than the given number of days.
Uses row-by-row deletion (not Query.delete()) so that the
before_delete listener fires and the ContextVar bypass is
honoured. Retention cleanup runs once per cleanup_interval
so the slight extra cost is negligible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
older_than_days
|
int | None
|
Age threshold in days. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
Number of entries deleted. |
export_json ¶
export_json(
*,
actor: str | None = None,
action: str | None = None,
resource_type: str | None = None,
gateway: str | None = None,
since: str | None = None,
until: str | None = None,
) -> str
Export audit entries as a JSON array string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
actor
|
str | None
|
Filter by actor identity. |
None
|
action
|
str | None
|
Filter by action type. |
None
|
resource_type
|
str | None
|
Filter by resource type. |
None
|
gateway
|
str | None
|
Filter by gateway name. |
None
|
since
|
str | None
|
ISO-format start timestamp filter. |
None
|
until
|
str | None
|
ISO-format end timestamp filter. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
JSON-formatted list of matching entries. |
audit_log
async
¶
audit_log(
request: Request,
action: str,
resource_type: str,
resource_id: str = "",
*,
gateway: str | None = None,
detail: dict[str, Any] | None = None,
) -> None
Route-handler helper that extracts actor/role/IP from the request.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
request
|
Request
|
The incoming HTTP request. |
required |
action
|
str
|
Action being performed. |
required |
resource_type
|
str
|
Type of resource affected. |
required |
resource_id
|
str
|
Identifier of the affected resource. |
''
|
gateway
|
str | None
|
Optional gateway name for scoping. |
None
|
detail
|
dict[str, Any] | None
|
Optional structured detail payload. |
None
|
local_gateway ¶
Local gateway lifecycle — Docker containers, openshell CLI, port management.
Only used when SHOREGUARD_LOCAL_MODE=1 or for backward-compatible v0.2 workflows.
LocalGatewayManager ¶
Docker and openshell CLI lifecycle for locally-managed gateways.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gateway_service
|
GatewayService
|
Gateway service for connection management. |
required |
diagnostics ¶
Check Docker availability, daemon status, and permissions.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Diagnostic information about Docker and openshell. |
start ¶
Start a gateway by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Result with success status and output or error. |
stop ¶
Stop a gateway by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Result with success status and output or error. |
restart ¶
Restart a gateway (stop + start).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Result from the start step. |
create ¶
create(
name: str,
port: int | None = None,
*,
remote_host: str | None = None,
gpu: bool = False,
) -> dict[str, Any]
Create a new gateway via openshell CLI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
port
|
int | None
|
Port number, or None for auto-selection. |
None
|
remote_host
|
str | None
|
Remote host for the gateway. |
None
|
gpu
|
bool
|
Whether to enable GPU support. |
False
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Gateway info or error result. |
destroy ¶
Destroy a gateway and remove its configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Gateway name. |
required |
force
|
bool
|
Force destruction even if resources still exist. |
False
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
dict[str, Any]: Result with success status. |