Skip to content

Optional provider builds via Go build tags#1055

Open
vlsi wants to merge 7 commits intohelmfile:mainfrom
vlsi:feature/optional-provider-build-tags
Open

Optional provider builds via Go build tags#1055
vlsi wants to merge 7 commits intohelmfile:mainfrom
vlsi:feature/optional-provider-build-tags

Conversation

@vlsi
Copy link
Copy Markdown

@vlsi vlsi commented Mar 12, 2026

Summary

  • Introduce a provider registry and Go build tags so that heavy providers can be excluded at compile time
  • Make the Yandex Cloud (yclockbox) provider optional as the first candidate — its SDK + transitive deps (gRPC stubs, envoyproxy, etc.) are the largest contributor to binary size
  • Add CI step to verify minimal build keeps compiling

Impact

Build Stripped size Change
Default (all providers) 140 MB
-tags custom_providers 98 MB −42 MB (−30%)

Usage

go build ./cmd/vals                                   # all providers (unchanged)
go build -tags custom_providers ./cmd/vals            # exclude optional providers
go build -tags "custom_providers,yandex" ./cmd/vals   # opt-in yclockbox
go build -tags all_providers ./cmd/vals               # explicitly all

How it works

  • pkg/providers/registry — a simple map-based provider registry with Register() / Get()
  • register_yclockbox.go (//go:build yandex || all_providers || !custom_providers) — registers the provider via init()
  • register_yclockbox_noop.go (//go:build custom_providers && !yandex && !all_providers) — empty stub
  • vals.go — the createProvider switch now falls back to the registry for optional providers
  • The same pattern can be applied to other heavy providers (1Password, K8s, etc.) in follow-up PRs

Test plan

  • go build ./... — full build compiles as before
  • go build -tags custom_providers ./... — minimal build compiles without yclockbox
  • go test ./... — no new test failures in either mode
  • CI step added to verify minimal build on every PR

See also

vlsi and others added 2 commits March 12, 2026 17:29
…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>
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>
@vlsi vlsi force-pushed the feature/optional-provider-build-tags branch from 65dff92 to 1fcb5e3 Compare March 12, 2026 16:50
@yxxhero yxxhero requested a review from Copilot March 13, 2026 09:12
Copy link
Copy Markdown
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 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_*.go files (in package vals) that register providers via init() 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 when registry.GetStringMapProvider(tpe) is false that includes tpe (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 when registry.GetStringProvider(tpe) is false that includes tpe (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
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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.

vlsi and others added 3 commits March 13, 2026 13:03
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>
@vlsi vlsi force-pushed the feature/optional-provider-build-tags branch from 260782e to f308a80 Compare March 13, 2026 10:04
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>
@vlsi vlsi force-pushed the feature/optional-provider-build-tags branch from b78f560 to 3f588c7 Compare March 13, 2026 10:24
@vlsi
Copy link
Copy Markdown
Author

vlsi commented Mar 13, 2026

I've did a couple of changes:

  1. Codex reviewed the initial changes and surfaced that 1fcb5e3 did not support "importing providers directly". In other words, previously, users could import individual providers without importing top-level vals. So I addressed the concern and moved init/registration.
  2. I've added README regarding the build
  3. I've fixed s3 vs ssm which looks like a true bug (it was there before the PR as well)

@vlsi
Copy link
Copy Markdown
Author

vlsi commented Mar 24, 2026

@yxxhero , a gentle ping. Is there anything I could do to help with getting this merged?

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.

Optional provider builds via Go build tags

2 participants