Skip to content

bug(providers): provider v2 profile lint does not validate L7 endpoint constraints (protocol/access/rules) #1714

Closed
gracesmith6504/OpenShell
#4

Description

@Tojaj

Agent Diagnostic

Skills loaded: openshell-cli, create-github-issue

Investigation: Traced the full lint path through three crates:

  1. Profile lint path (crates/openshell-cli/src/run.rs → crates/openshell-server/src/grpc/provider.rs → crates/openshell-providers/src/profiles.rs): The lint command calls validate_profile_set() which delegates endpoint checking to endpoint_is_valid() at profiles.rs:1096. That function only validates host is non-empty and port is in 1–65535. No other endpoint fields (protocol, access, enforcement, rules, deny_rules) are validated.

  2. Runtime validation (crates/openshell-sandbox/src/l7/mod.rs:515): validate_l7_policies() performs comprehensive L7 semantic checks including the rule at line 592: if !protocol.is_empty() && !has_rules && access.is_empty() — this is the check that catches the error at sandbox boot but is unreachable from the lint path.

  3. Dependency chain: openshell-cli → openshell-providers (lint-time validation) cannot reach openshell-sandbox (runtime validation). The L7 validation is trapped in the sandbox crate. openshell-policy (shared by both) has validate_sandbox_policy() but it only checks safety concerns (process identity, filesystem path traversal, TLD wildcards), not L7 semantics.

Conclusion: The lint command has a validation gap — it accepts Provider v2 Profile endpoint configurations that will always fail at sandbox startup. The fix is to add L7 endpoint field validation to validate_profile_set() in openshell-providers.

Description

A Provider v2 Profile bundles credentials, endpoints, and network policy into a single YAML definition. The openshell provider profile lint command is intended to validate these profiles before use, but it does not check L7 endpoint field semantics.

Actual behavior: openshell provider profile lint -f profile.yaml reports success for a profile with an endpoint that has protocol: rest but no access or rules field. When this profile is used to create a sandbox, the sandbox enters the Error phase with:

L7 policy validation failed: _provider_opencode_openrouter_provider.endpoints[0]:
  protocol requires rules or access to define allowed traffic

Expected behavior: The lint command should catch this error and report it as a diagnostic, since the endpoint configuration is invalid and will always fail at sandbox startup.

Reproduction Steps

  1. Create a Provider v2 Profile YAML with an endpoint that sets protocol but omits both access and rules:

    id: opencode-openrouter
    display_name: OpenCode (OpenRouter)
    description: OpenCode agent CLI configured to use OpenRouter.
    category: agent
    inference_capable: true
    
    credentials:
      - name: openrouter_api_key
        description: OpenRouter API Key
        env_vars: [OPENROUTER_API_KEY, OPENAI_API_KEY]
        required: true
        auth_style: bearer
        header_name: authorization
    
    discovery:
      credentials: [openrouter_api_key]
    
    endpoints:
      - host: openrouter.ai
        port: 443
        protocol: rest          # <-- protocol set
        enforcement: enforce
        # access and rules both missing — invalid but lint doesn't catch it
    
      - host: opencode.ai
        port: 443
    
    binaries:
      - /usr/local/bin/opencode
  2. Run lint — it passes:

    openshell provider profile lint -f profile.yaml
  3. Create a provider and sandbox using the profile — sandbox fails:

    openshell provider create --name opencode --type generic --from-profile profile.yaml
    openshell sandbox create --provider opencode
  4. Add access: read-write to the first endpoint and repeat — sandbox starts successfully.

Environment

  • OS: Fedora (Linux 7.0.10-201.fc44.x86_64)
  • OpenShell: built from main branch at commit 1f07bf04

Logs

Gateway logs when the sandbox fails:

[gateway] [INFO ] [openshell_server::compute] Sandbox phase changed
[gateway] [WARN ] [openshell_server::compute] Container exited with code 1

Sandbox container log:

Error: × L7 policy validation failed:
│ _provider_opencode_openrouter_provider.endpoints[0]: protocol requires
│ rules or access to define allowed traffic

Additional Context

The policy schema docs list access as "Required: No", which is correct in isolation — but when protocol is set, either access or rules must be provided. The docs could clarify this conditional requirement.

Other L7 checks also missing from profile lint that validate_l7_policies catches only at sandbox runtime:

  • rules and access are mutually exclusive
  • Unknown protocol values (must be rest/websocket/graphql/sql)
  • deny_rules require protocol to be set
  • deny_rules require either rules or access as a base

Suggested fix

Add the relevant subset of L7 endpoint field validation checks from validate_l7_policies (crates/openshell-sandbox/src/l7/mod.rs) into validate_profile_set (crates/openshell-providers/src/profiles.rs), specifically in the endpoint validation loop at line 1071. This keeps the fix within the openshell-providers crate boundary and doesn't require restructuring the dependency graph.

Activity

  1. TaylorMutch commented on Jul 13, 2026

    @TaylorMutch
    Collaborator

    📋 triage-agent

    Triage Assessment

    Classification: bug-confirmed

    Summary

    Provider profile lint still accepts L7 endpoint configurations that the sandbox runtime deterministically rejects. The validation gap remains on current main; no duplicate or open fix PR was found.

    Investigation

    validate_profile_set() currently delegates endpoint validation to a helper that checks only host and port. Runtime L7 validation additionally enforces protocol/access/rules semantics, including the reported requirement that an inspected non-MCP endpoint define access or non-empty rules, rules/access exclusivity, known protocols, and deny-rule prerequisites. The published policy schema also does not state the conditional requirement clearly.

    Recommendation

    Extract the pure L7 endpoint semantics into the shared policy layer and consume the same validator from provider lint and sandbox runtime, mapping violations into profile diagnostics. Copying only today's subset into providers would drift as protocols evolve. Add lint regression coverage and clarify the conditional protocol requirement in the policy schema documentation.

  2. added theissue type on Jul 13, 2026
  3. added
    area:policyPolicy engine and policy lifecycle work
    and removed
    state:triage-neededOpened without agent diagnostics and needs triage
    on Jul 13, 2026
  4. gracesmith6504 commented on Jul 14, 2026

    @gracesmith6504
    Contributor

    I'd like to work on this

  5. gracesmith6504 commented on Jul 14, 2026

    @gracesmith6504
    Contributor

    @TaylorMutch I've started on the approach that adds L7 checks directly to validate_profile_set() in profiles.rs. The triage
    assessment recommends extracting into the shared policy layer instead. Would the simpler approach be acceptable, or would you
    prefer the shared-layer refactor?

  6. added 9 commits that reference this issue on Jul 14, 2026
    e766b94
    90f7188
    6b3c3ad
    d9510ee
    4f07c2d
    4288256
    73f81c6
    e26f89f
    c422a82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions