ai-operations
The Zero-Trust Automation Boundary: Why OpsPilot Sandboxes AI PowerShell Suggestions
Why a cloud-operations assistant should convert intent into fixed, validated read queries instead of executing model-generated PowerShell scripts.
The phrase “AI PowerShell sandbox” can create a false sense of protection. A process boundary is not an authorization model, and a generated command is still code with the authority of the identity that runs it. For cloud operations, OpsPilot should translate an operator’s request into a small structured plan, validate it against a fixed catalog, and let application code build the actual query. The plan may say “list users” with a bounded limit; it must never supply a token, tenant, endpoint, shell fragment, or resource group.
The useful mental model is a compiler with a narrow language. The natural-language request is input. The model proposes an operation and structured filters. A deterministic validator checks known operation IDs, allowed fields, lengths, types, and per-operation compatibility. Trusted server configuration supplies tenant and Azure resource scope. A fixed adapter constructs an HTTPS GET to an approved Graph or ARM endpoint, selects required fields, limits rows and bytes, and redacts what the report does not need. The final draft explains freshness and partial collection.
User request
-> structured plan (operation, limit, permitted filters)
-> strict schema validation and independent allowlist check
-> authenticated customer and fixed target scope from server state
-> code-owned read-only Graph or ARM request
-> bounded, redacted evidence and report draft
This path is different from asking a model to write Get-MgUser | ... and piping its response into PowerShell. Do not use Invoke-Expression, dynamic command construction, or a tool that executes arbitrary model text. The current OpsPilot cloud query design accepts only fixed read operations and parameters. Unsupported or action-oriented requests should return a clarification rather than expanding the schema on the fly. A preview may show a code-owned equivalent query, but preview text is not an execution payload.
Structured output helps with shape; it does not prove the request is authorized, correct, or safe. OpenAI documents JSON Schema structured outputs and function calling, yet applications must still validate generated arguments before invoking their code. That means validation belongs after the model response, not only in a prompt. Reject extra properties such as command, script, uri, tenantId, subscriptionId, resourceGroup, token, or accessToken. Normalize accepted fields into a new object. Never trust a model-created target because the target appeared in conversation history.
Keep scope outside planner control. Authentication identifies the operator; server-side membership and customer-access checks decide which customer can be queried; a resolver selects the provider tenant binding; resource-group scope comes from stored authorization, not the chat. Match scope IDs between layers for consistency, but remember that matching strings is not authorization. Every request should be bound to one selected customer and an explicitly approved provider target. A tenant connected once does not mean every task has blanket permission to read or write every workload.
Read and write actions need different contracts. A fixed read can be automatically executed only when the service has already approved that catalog entry and the selected scope, permissions, data limits, and audit behavior are clear. OpsPilot’s current supported cloud query path runs validated supported reads; it is not a generic command runner. Human approval for write actions is not implemented. Do not claim that arbitrary scripts are sandboxed or that every read requires a separate click. Future write support would need its own exact preview, target, effects, permission, approval, timeout, audit, and verification flow before it is enabled.
PowerShell language modes are not a substitute for this boundary. Microsoft describes ConstrainedLanguage and NoLanguage behavior and explains their ties to system policy or session configuration. Those mechanisms can restrict language features, but they do not turn an arbitrary script into a safe workload request or replace tenant-level least privilege. The strongest design here is to avoid executing model-authored PowerShell at all. Use deterministic adapters with named operations and validated values.
Operationally, keep a catalog version and adapter contract with each report. Set hard caps for rows, pages, bytes, and elapsed time. Mark an unfollowed continuation as partial. Do not interpret an empty response as “secure” or “no objects.” Keep raw identities and source records out of generic prompts unless a reviewed task truly needs them. Use synthetic provider fixtures in tests, verify each report’s selected fields, and test malformed, stale, oversized, cross-customer, and injected model responses. The result should remain understandable to an operator: show what operation ran, on which authorized customer scope, when it was observed, how much was returned, which limits applied, and what the counts do not prove. A report is evidence for a person to review, not an AI-issued certification. Keep permissions task-specific to reduce risks from mistakes or compromise.
Sources: OpenAI Responses API structured output reference, OpenAI function-calling guidance, and PowerShell language modes. The product scope and catalog—not a generated string—define which reads exist.