Optional provider builds via Go build tags#1055
Conversation
…box) Introduce a provider registry and Go build tags so that heavy providers can be excluded at compile time. The default build (no tags) still includes everything. Building with `-tags custom_providers` switches to opt-in mode where only explicitly tagged providers are compiled in. This first iteration makes the Yandex Cloud (yclockbox) provider optional. Excluding it reduces the stripped binary from 140 MB to 98 MB (−30%) because the Yandex SDK and its transitive deps (gRPC stubs, envoyproxy, etc.) are no longer linked. Usage: go build ./cmd/vals # all providers (unchanged) go build -tags custom_providers ./cmd/vals # exclude yclockbox go build -tags "custom_providers,yandex" ./cmd/vals # opt-in yclockbox go build -tags all_providers ./cmd/vals # explicitly all Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
Ensure that `go build -tags custom_providers` keeps compiling on every PR, so build-tag-guarded files stay in sync with the rest of the code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
7e41e1f to
aeb00c3
Compare
Move all secret-manager providers (except echo, file, envsubst, exec) to build-tag-guarded registration files. Extend the provider registry to support all three factory types (Provider, StringProvider, StringMapProvider) so that stringprovider and stringmapprovider also use the registry instead of hardcoded switches. Binary size comparison (stripped, darwin/arm64): - All providers (default): 140 MB - Vault + AWS + GCP + Azure only: 49 MB (−65%) - No optional providers: 3 MB (−98%) Available build tags: vault, openbao, aws, gcp, azure, terraform, gitlab, sops, onepassword, doppler, k8s, hcpvaultsecrets, conjur, bitwarden, scaleway, infisical, oci, httpjson, pulumi, secretserver, servercore, keychain, yandex Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
65dff92 to
1fcb5e3
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a provider registry plus Go build tags to make provider inclusion configurable at compile time, enabling smaller vals binaries by excluding provider implementations (and their heavy transitive dependencies) unless explicitly opted in.
Changes:
- Replaced large provider-construction switches with a registry-based lookup (for main providers, string providers, and string-map providers).
- Added build-tagged
register_*.gofiles (in packagevals) that register providers viainit()depending on build tags. - Added a CI step to ensure a minimal build (
-tags custom_providers) compiles.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
vals.go |
Switch-based provider creation reduced to core providers; all others resolved via the new registry. |
register_aws.go |
Build-tagged registration for AWS providers (s3/ssm/awssecrets/awskms) + string/string-map variants. |
register_azure.go |
Build-tagged registration for Azure Key Vault provider + string/string-map variants. |
register_bitwarden.go |
Build-tagged registration for Bitwarden provider. |
register_conjur.go |
Build-tagged registration for Conjur provider + string provider. |
register_doppler.go |
Build-tagged registration for Doppler provider + string/string-map variants. |
register_gcp.go |
Build-tagged registration for GCS/GCP Secret Manager/GKMS/Google Sheets + string/string-map variants. |
register_gitlab.go |
Build-tagged registration for GitLab provider + string provider. |
register_hcpvaultsecrets.go |
Build-tagged registration for HCP Vault Secrets provider + string provider. |
register_httpjson.go |
Build-tagged registration for httpjson provider + string/string-map variants. |
register_infisical.go |
Build-tagged registration for Infisical provider + string/string-map variants. |
register_k8s.go |
Build-tagged registration for Kubernetes provider + string/string-map variants. |
register_keychain.go |
Build-tagged registration for Keychain provider. |
register_oci.go |
Build-tagged registration for OCI provider + string provider. |
register_onepassword.go |
Build-tagged registration for 1Password + 1Password Connect providers + string/string-map variants. |
register_openbao.go |
Build-tagged registration for OpenBao provider. |
register_pulumi.go |
Build-tagged registration for Pulumi State API provider + string provider. |
register_scaleway.go |
Build-tagged registration for Scaleway provider + string/string-map variants. |
register_secretserver.go |
Build-tagged registration for Secret Server provider + string provider. |
register_servercore.go |
Build-tagged registration for Servercore provider. |
register_sops.go |
Build-tagged registration for SOPS provider + string/string-map variants. |
register_terraform.go |
Build-tagged registration for Terraform state providers + string providers. |
register_vault.go |
Build-tagged registration for Vault provider + string/string-map variants. |
register_yclockbox.go |
Build-tagged registration for Yandex Lockbox (yclockbox) provider. |
pkg/stringprovider/stringprovider.go |
String provider factory selection moved to registry lookup (except exec). |
pkg/stringmapprovider/stringmapprovider.go |
String-map provider factory selection moved to registry lookup (except exec). |
pkg/providers/registry/registry.go |
New central provider/string/string-map registry used by core code and build-tagged registration. |
.github/workflows/ci.yaml |
Added a minimal-build compilation check using -tags custom_providers. |
Comments suppressed due to low confidence (2)
pkg/stringmapprovider/stringmapprovider.go:25
- When a string-map provider isn't registered (e.g., excluded via build tags), the function returns the generic error
failed initializing string-map provider from config: ..., which doesn't clearly say the provider name is unknown/unavailable. Consider returning a dedicated error whenregistry.GetStringMapProvider(tpe)is false that includestpe(and possibly hints that it may be excluded at build time).
default:
if factory, ok := registry.GetStringMapProvider(tpe); ok {
return factory(l, provider, awsLogLevel)
}
}
return nil, fmt.Errorf("failed initializing string-map provider from config: %v", provider)
}
pkg/stringprovider/stringprovider.go:25
- When a string provider isn't registered (e.g., because it was excluded via build tags), the function falls through to the generic error
failed initializing string provider from config: ..., which doesn’t clearly indicate that the provider name is unknown/unavailable. Consider returning a dedicated error whenregistry.GetStringProvider(tpe)is false that includestpe(and possibly hints that it may be excluded at build time).
default:
if factory, ok := registry.GetStringProvider(tpe); ok {
return factory(l, provider, awsLogLevel)
}
}
return nil, fmt.Errorf("failed initializing string provider from config: %v", provider)
}
| @@ -0,0 +1,23 @@ | |||
| //go:build vault || all_providers || !custom_providers | |||
There was a problem hiding this comment.
I've added clarification to README regarding the way to build the library.
custom_providers excludes all optional by default, so the ones who want custom builds would use custom_providers,valut,gcp,... and the other required parameters.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
Move RegisterStringProvider and RegisterStringMapProvider calls from root register_*.go files into build-tagged init files within pkg/stringprovider/ and pkg/stringmapprovider/ respectively. This fixes a regression where direct consumers of these subpackages (without importing the root vals package) would lose all provider registrations, since the init() functions in the root package would never execute. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
The gkms provider was present in the original stringmapprovider switch but was missed when creating the build-tagged registration files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
260782e to
f308a80
Compare
Copy-paste bug from eafc4c0 (2020): the "s3" case in stringmapprovider returned ssm.New() instead of s3.New(), routing S3 string-map lookups through SSM GetParametersByPath instead of S3 GetObject. Add regression test that verifies the correct provider is used by inspecting the SDK error message (S3: GetObject vs SSM). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Vladimir Sitnikov <sitnikov.vladimir@gmail.com>
b78f560 to
3f588c7
Compare
|
I've did a couple of changes:
|
|
@yxxhero , a gentle ping. Is there anything I could do to help with getting this merged? |
Summary
yclockbox) provider optional as the first candidate — its SDK + transitive deps (gRPC stubs, envoyproxy, etc.) are the largest contributor to binary sizeImpact
-tags custom_providersUsage
How it works
Test plan
See also
lockbox consumes 40MiB binary size yandex-cloud/go-sdk#42. It would be nice if yclockbox binary size could be reduced as well
Fixes Optional provider builds via Go build tags #1054