Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 16, 2025

Adds support for explicit OCI registry authentication via CLI flags and environment variables, complementing the existing Docker config authentication from Subtask 1.

Changes

CLI Interface

  • Added --registry-user / OCI_REGISTRY_USER for username
  • Added --registry-password / OCI_REGISTRY_PASSWORD for password
  • Added --registry-password-stdin for secure password input without shell history
  • Validates username/password pairing (both required if one provided)

Authentication Priority

Implemented credential resolution with explicit precedence:

  1. Explicit credentials (CLI flags/env vars)
  2. Docker config (~/.docker/config.json)
  3. Anonymous

Implementation

  • OciCredentials struct for passing credentials through the stack
  • get_registry_auth_with_credentials() in oci_auth module
  • Threaded credentials from CLI → LifecycleManager → loader → OCI client
  • handle_load_component_cli_with_credentials() for credential injection

Usage

# Explicit credentials
wassette component load oci://ghcr.io/user/component:latest \
  --registry-user myuser --registry-password mypass

# Secure stdin input
echo "mypassword" | wassette component load oci://ghcr.io/user/component:latest \
  --registry-user myuser --registry-password-stdin

# Environment variables (CI/CD friendly)
export OCI_REGISTRY_USER=myuser OCI_REGISTRY_PASSWORD=mypass
wassette component load oci://ghcr.io/user/component:latest

Testing

  • 4 unit tests for credential precedence logic
  • 2 integration tests for CLI validation and help text
  • Verified existing Docker config fallback remains functional

Part of #559 (Subtask 2/4)

Original prompt

This section details on the original issue you should resolve

<issue_title>[subtask] [Subtask 2/4] Add CLI flags for explicit OCI authentication credentials</issue_title>
<issue_description>Parent Issue: #559

Objective

Add CLI flags to the component load command to support explicit authentication credentials for OCI registries.

Context

Building on Subtask 1 which implemented Docker config authentication, this subtask adds explicit CLI options for users to provide credentials directly via command-line flags or environment variables. This is useful in CI/CD environments or when Docker config is not available.

Implementation Details

Files to Modify

  1. src/commands.rs (line 141-149):

    • Add new optional fields to ComponentCommands::Load:
      Load {
          /// Path to the component ((redacted) or (redacted))
          path: String,
          /// Directory where components are stored
          #[arg(long)]
          component_dir: Option(PathBuf),
          /// Registry username for OCI authentication
          #[arg(long, env = "OCI_REGISTRY_USER")]
          registry_user: Option(String),
          /// Registry password for OCI authentication (use --registry-password-stdin for better security)
          #[arg(long, env = "OCI_REGISTRY_PASSWORD")]
          registry_password: Option(String),
          /// Read registry password from stdin
          #[arg(long, conflicts_with = "registry_password")]
          registry_password_stdin: bool,
      }
  2. src/cli_handlers.rs:

    • Update component load handler to extract auth flags
    • Pass credentials to the lifecycle manager's load function
    • Handle --registry-password-stdin by reading from stdin
  3. crates/mcp-server/src/components.rs (line 44-86):

    • Update handle_load_component() to accept optional credentials
    • Pass credentials through to lifecycle_manager.load_component()
  4. crates/wassette/src/lib.rs (LifecycleManager):

    • Update load_component() signature to accept optional OciCredentials struct
    • Pass credentials to loader functions
  5. crates/wassette/src/oci_auth.rs (from Subtask 1):

    • Add new function: fn get_registry_auth_with_credentials(reference: &Reference, user: Option(String), password: Option(String)) -> Result(RegistryAuth)
    • Priority: explicit credentials > Docker config > Anonymous
    • If both explicit creds and Docker config exist, use explicit creds

Key Implementation Notes

  • Use environment variables (OCI_REGISTRY_USER, OCI_REGISTRY_PASSWORD) for CI/CD friendliness
  • Implement --registry-password-stdin for better security (avoids password in shell history)
  • Validate that username and password are both provided if one is specified
  • Clear error message if credentials are invalid
  • Consider adding --insecure-skip-tls-verify flag for development (optional)

Acceptance Criteria

  • --registry-user and --registry-password flags work for explicit auth
  • --registry-password-stdin reads password securely from stdin
  • Environment variables OCI_REGISTRY_USER and OCI_REGISTRY_PASSWORD work
  • Explicit credentials take priority over Docker config
  • Docker config still works as fallback (from Subtask 1)
  • Clear error message when only username or password provided (not both)
  • Tests added for CLI argument parsing
  • Documentation updated in --help output

Testing Strategy

  1. Unit tests:

    • Test CLI argument parsing with various flag combinations
    • Test precedence: explicit > Docker config > Anonymous
  2. Integration tests:

    • Test loading with explicit username/password
    • Test loading with environment variables
    • Test stdin password reading
    • Test fallback behavior
  3. Manual testing:

    • Verify against a real private registry (e.g., private GHCR repo)
    • Test error messages with invalid credentials

Dependencies

Depends on Subtask 1 being completed (Docker config support and oci_auth.rs module).

Example Usage

# Using flags
wassette component load (redacted) \
  --registry-user myuser \
  --registry-password mypass

# Using stdin for password
echo "mypassword" | wassette component load (redacted) \
  --registry-user myuser \
  --registry-password-stdin

# Using environment variables
export OCI_REGISTRY_USER=myuser
export OCI_REGISTRY_PASSWORD=mypass
wassette component load (redacted)

# Fallback to Docker config (Subtask 1)
wassette component load (redacted)

Related to #559

AI generated by Plan for #559</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI self-assigned this Nov 16, 2025
Copilot AI and others added 4 commits November 16, 2025 06:34
- Add --registry-user, --registry-password, and --registry-password-stdin flags to component load command
- Add OciCredentials struct for passing credentials through the stack
- Add get_registry_auth_with_credentials function with priority: explicit > Docker config > Anonymous
- Update LifecycleManager to accept optional credentials
- Update loader to thread credentials through to OCI auth
- Enable clap env feature for environment variable support

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
- Test explicit credentials take precedence over Docker config
- Test fallback to Docker config when no explicit credentials provided
- Test explicit credentials work without Docker config
- Test anonymous auth when no credentials available
- All 9 tests pass successfully

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
- Test validation rejects incomplete credentials (username only or password only)
- Test help text documents all new flags and environment variables
- Both integration tests pass successfully

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Add CLI flags for explicit OCI authentication credentials Add CLI flags for explicit OCI authentication credentials Nov 16, 2025
Copilot AI requested a review from Mossaka November 16, 2025 06:53
@Mossaka Mossaka requested a review from Copilot November 17, 2025 16:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for explicit OCI registry authentication via CLI flags and environment variables, implementing the credential resolution precedence: explicit credentials > Docker config > anonymous. This complements the existing Docker config authentication from Subtask 1.

Key Changes:

  • Added CLI flags --registry-user, --registry-password, and --registry-password-stdin with corresponding environment variables
  • Implemented credential pairing validation and stdin password reading
  • Threaded credentials through the stack from CLI → LifecycleManager → loader → OCI client

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
Cargo.toml Added "env" feature to clap for environment variable support
src/commands.rs Added three new CLI arguments for OCI authentication
src/main.rs Implemented credential validation, stdin reading, and credential object creation
crates/wassette/src/lib.rs Added load_component_with_credentials and credential threading methods
crates/wassette/src/loader.rs Extended Loadable trait with credential-aware methods
crates/wassette/src/oci_auth.rs Added OciCredentials struct and get_registry_auth_with_credentials function
crates/mcp-server/src/components.rs Added handle_load_component_cli_with_credentials function
tests/cli_integration_test.rs Added integration tests for credential validation and help text

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const FILE_EXTENSION: &'static str;
const RESOURCE_TYPE: &'static str;

async fn from_local_file(path: &Path) -> Result<DownloadedResource>;
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The #[allow(dead_code)] attribute suggests this method is now unused. Since from_oci_reference_with_progress_and_credentials is the new implementation and this method is kept as a wrapper, consider whether this attribute is needed. If the method is part of the public Loadable trait API and should remain available for backward compatibility, it's fine to keep it. Otherwise, if it's truly unused, the attribute is appropriate but consider documenting why it's retained.

Suggested change
async fn from_local_file(path: &Path) -> Result<DownloadedResource>;
async fn from_local_file(path: &Path) -> Result<DownloadedResource>;
/// Retained for backward compatibility with existing consumers of the Loadable trait.
/// The preferred method is `from_oci_reference_with_progress_and_credentials`.
/// The `#[allow(dead_code)]` attribute suppresses warnings since this method may not be used internally.

Copilot uses AI. Check for mistakes.
Comment on lines +428 to +433
#[allow(dead_code)]
async fn resolve_component_resource(&self, uri: &str) -> Result<(String, DownloadedResource)> {
self.resolve_component_resource_with_credentials(uri, None)
.await
}

Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the loader.rs case, this private method now has #[allow(dead_code)] because it's been replaced by resolve_component_resource_with_credentials. Since this appears to be a private method (not pub), consider whether it should be removed entirely rather than kept with the dead_code attribute. If it's intentionally kept for potential future use or backward compatibility, add a comment explaining why.

Suggested change
#[allow(dead_code)]
async fn resolve_component_resource(&self, uri: &str) -> Result<(String, DownloadedResource)> {
self.resolve_component_resource_with_credentials(uri, None)
.await
}

Copilot uses AI. Check for mistakes.
Ok(())
}

#[test(tokio::test)]
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test attribute #[test(tokio::test)] is non-standard. The correct tokio test macro is #[tokio::test]. While this appears to be using the test_log crate's wrapper (as seen in the imports), verify this is the intended test attribute format for the project. The pattern #[test(tokio::test)] is consistent with other tests in the file, but ensure it's compatible with the project's test infrastructure.

Copilot uses AI. Check for mistakes.
Ok(())
}

#[test(tokio::test)]
Copy link

Copilot AI Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the previous comment - the test attribute #[test(tokio::test)] should be verified as the correct format. The standard tokio test attribute is #[tokio::test]. This appears to be using the test_log crate's wrapper pattern consistently throughout the file, so if this is the project's standard, it's acceptable, but worth confirming.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants