Skip to content

Proposal: Ability to configure custom adapters #1765

@scmmishra

Description

@scmmishra

The list of supported secrets manager is effectively hardcoded. Currently, adding a new secrets adapter requires either:

  1. Contributing to the Kamal repository and waiting for release
  2. Forking Kamal and maintaining a custom version

I tried setting up secrets using Phase recently, even created a PR to add the adapter for it: #1764
But largely this seems unsustainable. The maintainers cannot be reasonably expected make sure that all the adapters continue to operate correctly as the underlying CLIs and utilities get upgraded. Also, forking Kamal for a lot of folks isn't a pragmatic choice either.

There's two other PRs, one for Proton Pass and other for KeePassXC. And an issue for Dashlane #1761

The proposed solution can remove the need to get those through, and unblocks the users as well

A good middle ground would be allowing users to configure a custom adapter, by loading them from .kamal/adapters/ directory in the project root. The way it works is the following

  1. User creates .kamal/adapters/my_vault.rb in their project
  2. Kamal automatically loads all *.rb files from this directory
  3. Custom adapters are available via --adapter my_vault

Proposed Implementation

Minimal change to lib/kamal/secrets/adapters.rb:

def self.lookup(name)
  # ... existing alias handling ...

  load_custom_adapters  # <- Add this line
  adapter_class(name)
end

def self.load_custom_adapters
  @custom_adapters_loaded ||= begin
    custom_adapters_dir = File.join(Dir.pwd, ".kamal", "adapters")
    if File.directory?(custom_adapters_dir)
      Dir.glob(File.join(custom_adapters_dir, "*.rb")).each do |file|
        require file
      end
    end
    true
  end
end

This is fully backward compatible:

  • If .kamal/adapters/ doesn't exist, behavior is unchanged
  • Built-in adapters take precedence (loaded via Zeitwerk before custom lookup)
  • No changes to existing configuration or CLI

I'd be happy to raise a PR for this if it seems like a good solution.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions