Skip to content

Write a secret resolver

Prerequisites · You have a placeholder syntax you want DataCoolie to recognise (e.g. vault:path/to/secret). End state · Resolver registered, used automatically during resolve_secrets before dataflows execute.

Minimal resolver

from datacoolie.core.secret_resolver import BaseSecretResolver


class VaultResolver(BaseSecretResolver):
    PREFIX = "vault:"

    def matches(self, value: str) -> bool:
        return isinstance(value, str) and value.startswith(self.PREFIX)

    def resolve(self, value: str, provider) -> str:
        key = value[len(self.PREFIX):]
        # Any concrete BaseSecretProvider subclass works here, including the platform.
        return provider.fetch_secret(source="vault", field=key)

Register

[project.entry-points."datacoolie.resolvers"]
vault = "mypkg.resolvers:VaultResolver"

Usage from metadata

{
  "configure": {"password": "vault:prod/db/customer"}
}

At runtime resolve_secrets scans every string in configure, finds the resolver whose matches() returns True, and replaces the value with the resolver's resolve() output. Fall-through values are untouched.

Provider vs resolver split

  • Resolverparses the placeholder string (e.g. vault:prod/db).
  • Providerfetches the actual secret from a backend.

The built-in EnvResolver is the exception that handles both ends (env:FOO is resolved from os.environ["FOO"] by the resolver itself). For anything more elaborate, have the resolver call into a BaseSecretProvider.

See ADR-0002.