Skip to content

feat(providers): support credential-less provider creation for policy-only profiles #1978

Description

@maruiz93

Problem Statement

Provider profiles can define endpoints and binaries without any credentials — the built-in pypi profile is a shipping example. However, openshell provider create requires at least one credential source, making it impossible to create a provider instance from a credential-less profile without the --credential NOOP= workaround.

This is inconvenient for downstream harnesses that use custom provider profiles purely for policy composition (network endpoint allow-lists contributed through provider attachment) without needing credential injection. The --credential NOOP= workaround exists but persists a dummy credential in the provider record, polluting credential state for a provider that has no credential semantics.

The gap exists at two layers:

  1. CLI (crates/openshell-cli/src/main.rs:719): the cred_source clap arg group is required(true), so provider create always demands one of --credential, --from-existing, or --from-gcloud-adc at parse time.

  2. Server (crates/openshell-server/src/grpc/provider.rs:96-101): CreateProvider rejects empty credentials unless provider_type_allows_empty_credentials_for_refresh() returns true — but that function (crates/openshell-providers/src/profiles.rs:323-336) requires at least one gateway-mintable credential. A profile with zero credentials always returns false.

Proposed Design

Allow credential-less provider creation when the provider type's profile declares no required credentials.

CLI changes:

Make the cred_source arg group conditionally required. When no credential flag is provided, the CLI fetches the provider profile (it already does this for the refresh-bootstrap path at run.rs:4556-4559) and proceeds without credentials if the profile has no required credential entries. If the profile has required credentials and none were provided, the existing error is preserved.

Server changes:

Extend the CreateProvider validation (provider.rs:96-101) to also allow empty credentials when the profile exists and declares no required credentials. This can reuse the existing get_provider_type_profile lookup and add a check like:

fn profile_allows_no_credentials(profile: &ProviderTypeProfile) -> bool {
    profile.credentials.iter().all(|c| !c.required)
}

The existing allows_gateway_refresh_bootstrap path remains unchanged for its OAuth use case.

No changes needed to:

  • Policy composition — already works with credential-less providers once they exist
  • Provider attachment — SandboxSpec.providers is name-based, credential-agnostic
  • Effective policy fetch — profile_provider_policy_layers reads endpoints/binaries from the profile regardless of credentials

Alternatives Considered

Add a --no-credential CLI flag. This would work but adds a flag for what should be the default behavior when a profile has no credentials. The profile already declares what credentials it needs — the CLI should respect that.

Keep --credential NOOP= as the documented workaround. This persists a dummy credential in the provider record, which is confusing for operators inspecting provider state and may interact poorly with future credential driver backends (#1931).

Agent Investigation

  • Confirmed pypi built-in profile (providers/pypi.yaml) has no credentials section — only endpoints and binaries.
  • Confirmed CLI arg group cred_source at crates/openshell-cli/src/main.rs:719 is required(true).
  • Confirmed server validation at crates/openshell-server/src/grpc/provider.rs:96-101 rejects empty credentials unless allows_gateway_refresh_bootstrap() returns true.
  • Confirmed allows_gateway_refresh_bootstrap() at crates/openshell-providers/src/profiles.rs:323-336 requires at least one gateway-mintable credential — zero-credential profiles always return false.
  • Confirmed the existing empty-credential test (provider_create_allows_empty_credentials_for_gateway_refresh_profiles at crates/openshell-cli/tests/provider_commands_integration.rs:1102) only covers the OAuth refresh bootstrap case, not the zero-credential profile case.
  • Searched open and closed issues — no existing issue covers this gap.
  • Related: feat: add provider profile registry and policy layer composition foundation #947 (provider profile registry foundation), Enhanced Provider Management #896 (enhanced provider management umbrella).

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions