feat: add build secrets option ()

* feat: add build secrets option

* make gen and fix tests
This commit is contained in:
Sas Swart 2025-01-16 11:39:38 +02:00 committed by GitHub
parent dabb7f31aa
commit 82c856094e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 50 additions and 12 deletions

View file

@ -25,6 +25,7 @@ The cached image resource can be used to retrieve a cached image produced by env
- `base_image_cache_dir` (String) (Envbuilder option) The path to a directory where the base image can be found. This should be a read-only directory solely mounted for the purpose of caching the base image. - `base_image_cache_dir` (String) (Envbuilder option) The path to a directory where the base image can be found. This should be a read-only directory solely mounted for the purpose of caching the base image.
- `build_context_path` (String) (Envbuilder option) Can be specified when a DockerfilePath is specified outside the base WorkspaceFolder. This path MUST be relative to the WorkspaceFolder path into which the repo is cloned. - `build_context_path` (String) (Envbuilder option) Can be specified when a DockerfilePath is specified outside the base WorkspaceFolder. This path MUST be relative to the WorkspaceFolder path into which the repo is cloned.
- `build_secrets` (Map of String) The secrets to use for the build. This is a map of key-value pairs.
- `cache_ttl_days` (Number) (Envbuilder option) The number of days to use cached layers before expiring them. Defaults to 7 days. - `cache_ttl_days` (Number) (Envbuilder option) The number of days to use cached layers before expiring them. Defaults to 7 days.
- `devcontainer_dir` (String) (Envbuilder option) The path to the folder containing the devcontainer.json file that will be used to build the workspace and can either be an absolute path or a path relative to the workspace folder. If not provided, defaults to `.devcontainer`. - `devcontainer_dir` (String) (Envbuilder option) The path to the folder containing the devcontainer.json file that will be used to build the workspace and can either be an absolute path or a path relative to the workspace folder. If not provided, defaults to `.devcontainer`.
- `devcontainer_json_path` (String) (Envbuilder option) The path to a devcontainer.json file that is either an absolute path or a path relative to DevcontainerDir. This can be used in cases where one wants to substitute an edited devcontainer.json file for the one that exists in the repo. - `devcontainer_json_path` (String) (Envbuilder option) The path to a devcontainer.json file that is either an absolute path or a path relative to DevcontainerDir. This can be used in cases where one wants to substitute an edited devcontainer.json file for the one that exists in the repo.

View file

@ -51,6 +51,7 @@ type CachedImageResourceModel struct {
// Optional "inputs". // Optional "inputs".
BaseImageCacheDir types.String `tfsdk:"base_image_cache_dir"` BaseImageCacheDir types.String `tfsdk:"base_image_cache_dir"`
BuildContextPath types.String `tfsdk:"build_context_path"` BuildContextPath types.String `tfsdk:"build_context_path"`
BuildSecrets types.Map `tfsdk:"build_secrets"`
CacheTTLDays types.Int64 `tfsdk:"cache_ttl_days"` CacheTTLDays types.Int64 `tfsdk:"cache_ttl_days"`
DevcontainerDir types.String `tfsdk:"devcontainer_dir"` DevcontainerDir types.String `tfsdk:"devcontainer_dir"`
DevcontainerJSONPath types.String `tfsdk:"devcontainer_json_path"` DevcontainerJSONPath types.String `tfsdk:"devcontainer_json_path"`
@ -121,6 +122,11 @@ func (r *CachedImageResource) Schema(ctx context.Context, req resource.SchemaReq
MarkdownDescription: "(Envbuilder option) Can be specified when a DockerfilePath is specified outside the base WorkspaceFolder. This path MUST be relative to the WorkspaceFolder path into which the repo is cloned.", MarkdownDescription: "(Envbuilder option) Can be specified when a DockerfilePath is specified outside the base WorkspaceFolder. This path MUST be relative to the WorkspaceFolder path into which the repo is cloned.",
Optional: true, Optional: true,
}, },
"build_secrets": schema.MapAttribute{
MarkdownDescription: "The secrets to use for the build. This is a map of key-value pairs.",
ElementType: types.StringType,
Optional: true,
},
"cache_ttl_days": schema.Int64Attribute{ "cache_ttl_days": schema.Int64Attribute{
MarkdownDescription: "(Envbuilder option) The number of days to use cached layers before expiring them. Defaults to 7 days.", MarkdownDescription: "(Envbuilder option) The number of days to use cached layers before expiring them. Defaults to 7 days.",
Optional: true, Optional: true,

View file

@ -2,6 +2,7 @@ package provider
import ( import (
"fmt" "fmt"
"slices"
"strings" "strings"
eboptions "github.com/coder/envbuilder/options" eboptions "github.com/coder/envbuilder/options"
@ -47,6 +48,22 @@ func optionsFromDataModel(data CachedImageResourceModel) (eboptions.Options, dia
opts.BuildContextPath = data.BuildContextPath.ValueString() opts.BuildContextPath = data.BuildContextPath.ValueString()
} }
if !data.BuildSecrets.IsNull() {
providerOpts["ENVBUILDER_BUILD_SECRETS"] = true
// Depending on use case, users might want to provide build secrets as a map or a list of strings.
// The string list option is supported by extra_env, so we support the map option here. Envbuilder
// expects a list of strings, so we convert the map to a list of strings here.
buildSecretMap := tfutil.TFMapToStringMap(data.BuildSecrets)
buildSecretSlice := make([]string, 0, len(buildSecretMap))
for k, v := range buildSecretMap {
buildSecretSlice = append(buildSecretSlice, fmt.Sprintf("%s=%s", k, v))
}
slices.Sort(buildSecretSlice)
opts.BuildSecrets = buildSecretSlice
}
if !data.CacheTTLDays.IsNull() { if !data.CacheTTLDays.IsNull() {
providerOpts["ENVBUILDER_CACHE_TTL_DAYS"] = true providerOpts["ENVBUILDER_CACHE_TTL_DAYS"] = true
opts.CacheTTLDays = data.CacheTTLDays.ValueInt64() opts.CacheTTLDays = data.CacheTTLDays.ValueInt64()
@ -199,7 +216,7 @@ func overrideOptionsFromExtraEnv(opts *eboptions.Options, extraEnv map[string]st
// XXX: workaround for serpent behaviour where calling Set() on a // XXX: workaround for serpent behaviour where calling Set() on a
// string slice will append instead of replace: set to empty first. // string slice will append instead of replace: set to empty first.
if key == "ENVBUILDER_IGNORE_PATHS" { if _, ok := optsMap[key].(*serpent.StringArray); ok {
_ = optsMap[key].Set("") _ = optsMap[key].Set("")
} }

View file

@ -35,11 +35,15 @@ func Test_optionsFromDataModel(t *testing.T) {
{ {
name: "all options without extra_env", name: "all options without extra_env",
data: CachedImageResourceModel{ data: CachedImageResourceModel{
BuilderImage: basetypes.NewStringValue("envbuilder:latest"), BuilderImage: basetypes.NewStringValue("envbuilder:latest"),
CacheRepo: basetypes.NewStringValue("localhost:5000/cache"), CacheRepo: basetypes.NewStringValue("localhost:5000/cache"),
GitURL: basetypes.NewStringValue("git@git.local/devcontainer.git"), GitURL: basetypes.NewStringValue("git@git.local/devcontainer.git"),
BaseImageCacheDir: basetypes.NewStringValue("/tmp/cache"), BaseImageCacheDir: basetypes.NewStringValue("/tmp/cache"),
BuildContextPath: basetypes.NewStringValue("."), BuildContextPath: basetypes.NewStringValue("."),
BuildSecrets: basetypes.NewMapValueMust(basetypes.StringType{}, map[string]attr.Value{
"FOO": basetypes.NewStringValue("bar"),
"BAZ": basetypes.NewStringValue("qux"),
}),
CacheTTLDays: basetypes.NewInt64Value(7), CacheTTLDays: basetypes.NewInt64Value(7),
DevcontainerDir: basetypes.NewStringValue(".devcontainer"), DevcontainerDir: basetypes.NewStringValue(".devcontainer"),
DevcontainerJSONPath: basetypes.NewStringValue(".devcontainer/devcontainer.json"), DevcontainerJSONPath: basetypes.NewStringValue(".devcontainer/devcontainer.json"),
@ -66,6 +70,7 @@ func Test_optionsFromDataModel(t *testing.T) {
GitURL: "git@git.local/devcontainer.git", GitURL: "git@git.local/devcontainer.git",
BaseImageCacheDir: "/tmp/cache", BaseImageCacheDir: "/tmp/cache",
BuildContextPath: ".", BuildContextPath: ".",
BuildSecrets: []string{"BAZ=qux", "FOO=bar"}, // Sorted
CacheTTLDays: 7, CacheTTLDays: 7,
DevcontainerDir: ".devcontainer", DevcontainerDir: ".devcontainer",
DevcontainerJSONPath: ".devcontainer/devcontainer.json", DevcontainerJSONPath: ".devcontainer/devcontainer.json",
@ -97,9 +102,11 @@ func Test_optionsFromDataModel(t *testing.T) {
"CODER_AGENT_TOKEN", "token", "CODER_AGENT_TOKEN", "token",
"CODER_AGENT_URL", "http://coder", "CODER_AGENT_URL", "http://coder",
"FOO", "bar", "FOO", "bar",
"ENVBUILDER_BUILD_SECRETS", "FOO=bar,BAZ=qux",
), ),
}, },
expectOpts: eboptions.Options{ expectOpts: eboptions.Options{
BuildSecrets: []string{"FOO=bar", "BAZ=qux"},
CacheRepo: "localhost:5000/cache", CacheRepo: "localhost:5000/cache",
GitURL: "git@git.local/devcontainer.git", GitURL: "git@git.local/devcontainer.git",
RemoteRepoBuildMode: true, RemoteRepoBuildMode: true,
@ -110,11 +117,14 @@ func Test_optionsFromDataModel(t *testing.T) {
{ {
name: "extra_env override warnings", name: "extra_env override warnings",
data: CachedImageResourceModel{ data: CachedImageResourceModel{
BuilderImage: basetypes.NewStringValue("envbuilder:latest"), BuilderImage: basetypes.NewStringValue("envbuilder:latest"),
CacheRepo: basetypes.NewStringValue("localhost:5000/cache"), CacheRepo: basetypes.NewStringValue("localhost:5000/cache"),
GitURL: basetypes.NewStringValue("git@git.local/devcontainer.git"), GitURL: basetypes.NewStringValue("git@git.local/devcontainer.git"),
BaseImageCacheDir: basetypes.NewStringValue("/tmp/cache"), BaseImageCacheDir: basetypes.NewStringValue("/tmp/cache"),
BuildContextPath: basetypes.NewStringValue("."), BuildContextPath: basetypes.NewStringValue("."),
BuildSecrets: basetypes.NewMapValueMust(basetypes.StringType{}, map[string]attr.Value{
"FOO": basetypes.NewStringValue("bar"),
}),
CacheTTLDays: basetypes.NewInt64Value(7), CacheTTLDays: basetypes.NewInt64Value(7),
DevcontainerDir: basetypes.NewStringValue(".devcontainer"), DevcontainerDir: basetypes.NewStringValue(".devcontainer"),
DevcontainerJSONPath: basetypes.NewStringValue(".devcontainer/devcontainer.json"), DevcontainerJSONPath: basetypes.NewStringValue(".devcontainer/devcontainer.json"),
@ -136,6 +146,7 @@ func Test_optionsFromDataModel(t *testing.T) {
Verbose: basetypes.NewBoolValue(true), Verbose: basetypes.NewBoolValue(true),
WorkspaceFolder: basetypes.NewStringValue("workspace"), WorkspaceFolder: basetypes.NewStringValue("workspace"),
ExtraEnv: extraEnvMap(t, ExtraEnv: extraEnvMap(t,
"ENVBUILDER_BUILD_SECRETS", "FOO=bar,BAZ=qux",
"ENVBUILDER_CACHE_REPO", "override", "ENVBUILDER_CACHE_REPO", "override",
"ENVBUILDER_GIT_URL", "override", "ENVBUILDER_GIT_URL", "override",
"ENVBUILDER_BASE_IMAGE_CACHE_DIR", "override", "ENVBUILDER_BASE_IMAGE_CACHE_DIR", "override",
@ -169,6 +180,7 @@ func Test_optionsFromDataModel(t *testing.T) {
// overridden // overridden
BaseImageCacheDir: "override", BaseImageCacheDir: "override",
BuildContextPath: "override", BuildContextPath: "override",
BuildSecrets: []string{"FOO=bar", "BAZ=qux"},
CacheTTLDays: 8, CacheTTLDays: 8,
DevcontainerDir: "override", DevcontainerDir: "override",
DevcontainerJSONPath: "override", DevcontainerJSONPath: "override",
@ -189,7 +201,7 @@ func Test_optionsFromDataModel(t *testing.T) {
Verbose: false, Verbose: false,
WorkspaceFolder: "override", WorkspaceFolder: "override",
}, },
expectNumWarningDiags: 23, expectNumWarningDiags: 24,
}, },
{ {
name: "extra_env override errors", name: "extra_env override errors",
@ -295,6 +307,7 @@ func Test_computeEnvFromOptions(t *testing.T) {
BaseImageCacheDir: "string", BaseImageCacheDir: "string",
BinaryPath: "string", BinaryPath: "string",
BuildContextPath: "string", BuildContextPath: "string",
BuildSecrets: []string{"FOO=bar", "BAZ=qux"},
CacheRepo: "string", CacheRepo: "string",
CacheTTLDays: 1, CacheTTLDays: 1,
CoderAgentSubsystem: []string{"one", "two"}, CoderAgentSubsystem: []string{"one", "two"},
@ -339,6 +352,7 @@ func Test_computeEnvFromOptions(t *testing.T) {
"ENVBUILDER_BASE_IMAGE_CACHE_DIR": "string", "ENVBUILDER_BASE_IMAGE_CACHE_DIR": "string",
"ENVBUILDER_BINARY_PATH": "string", "ENVBUILDER_BINARY_PATH": "string",
"ENVBUILDER_BUILD_CONTEXT_PATH": "string", "ENVBUILDER_BUILD_CONTEXT_PATH": "string",
"ENVBUILDER_BUILD_SECRETS": "FOO=bar,BAZ=qux",
"ENVBUILDER_CACHE_REPO": "string", "ENVBUILDER_CACHE_REPO": "string",
"ENVBUILDER_CACHE_TTL_DAYS": "1", "ENVBUILDER_CACHE_TTL_DAYS": "1",
"ENVBUILDER_DEVCONTAINER_DIR": "string", "ENVBUILDER_DEVCONTAINER_DIR": "string",