Skip to content

Commit 5bab6eb

Browse files
authored
Merge pull request #263 from ndeloof/env_secret
add support for secret set by environment variable
2 parents b706902 + 51b6b3e commit 5bab6eb

File tree

8 files changed

+74
-13
lines changed

8 files changed

+74
-13
lines changed

loader/full-example.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ configs:
405405
external: true
406406
config4:
407407
name: foo
408+
file: ~/config_data
408409
x-bar: baz
409410
x-foo: bar
410411

@@ -420,6 +421,7 @@ secrets:
420421
external: true
421422
secret4:
422423
name: bar
424+
environment: BAR
423425
x-bar: baz
424426
x-foo: bar
425427
x-bar: baz

loader/full-struct_test.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func fullExampleConfig(workingDir, homeDir string) *types.Config {
3131
Services: services(workingDir, homeDir),
3232
Networks: networks(),
3333
Volumes: volumes(),
34-
Configs: configs(workingDir),
34+
Configs: configs(workingDir, homeDir),
3535
Secrets: secrets(workingDir),
3636
Extensions: map[string]interface{}{
3737
"x-foo": "bar",
@@ -520,7 +520,7 @@ func volumes() map[string]types.VolumeConfig {
520520
}
521521
}
522522

523-
func configs(workingDir string) map[string]types.ConfigObjConfig {
523+
func configs(workingDir string, homeDir string) map[string]types.ConfigObjConfig {
524524
return map[string]types.ConfigObjConfig{
525525
"config1": {
526526
File: filepath.Join(workingDir, "config_data"),
@@ -538,7 +538,7 @@ func configs(workingDir string) map[string]types.ConfigObjConfig {
538538
},
539539
"config4": {
540540
Name: "foo",
541-
File: workingDir,
541+
File: filepath.Join(homeDir, "config_data"),
542542
Extensions: map[string]interface{}{
543543
"x-bar": "baz",
544544
"x-foo": "bar",
@@ -564,8 +564,8 @@ func secrets(workingDir string) map[string]types.SecretConfig {
564564
External: types.External{External: true},
565565
},
566566
"secret4": {
567-
Name: "bar",
568-
File: workingDir,
567+
Name: "bar",
568+
Environment: "BAR",
569569
Extensions: map[string]interface{}{
570570
"x-bar": "baz",
571571
"x-foo": "bar",
@@ -973,7 +973,7 @@ secrets:
973973
external: true
974974
secret4:
975975
name: bar
976-
file: %s
976+
environment: BAR
977977
x-bar: baz
978978
x-foo: bar
979979
configs:
@@ -1003,9 +1003,8 @@ x-nested:
10031003
filepath.Join(homeDir, "configs"),
10041004
filepath.Join(workingDir, "opt"),
10051005
filepath.Join(workingDir, "secret_data"),
1006-
filepath.Join(workingDir),
10071006
filepath.Join(workingDir, "config_data"),
1008-
filepath.Join(workingDir))
1007+
filepath.Join(homeDir, "config_data"))
10091008
}
10101009

10111010
func fullExampleJSON(workingDir, homeDir string) string {
@@ -1096,7 +1095,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
10961095
},
10971096
"secret4": {
10981097
"name": "bar",
1099-
"file": "%s",
1098+
"environment": "BAR",
11001099
"external": false
11011100
}
11021101
},
@@ -1613,10 +1612,9 @@ func fullExampleJSON(workingDir, homeDir string) string {
16131612
}
16141613
}`,
16151614
toPath(workingDir, "config_data"),
1616-
toPath(workingDir),
1615+
toPath(homeDir, "config_data"),
16171616
toPath(workingDir, "secret_data"),
16181617
toPath(workingDir),
1619-
toPath(workingDir),
16201618
toPath(workingDir, "static"),
16211619
toPath(homeDir, "configs"),
16221620
toPath(workingDir, "opt"))

loader/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfi
804804
return obj, errors.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name)
805805
}
806806
default:
807-
if resolvePaths {
807+
if obj.File != "" && resolvePaths {
808808
obj.File = absPath(details.WorkingDir, obj.File)
809809
}
810810
}

loader/loader_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,11 @@ func TestFullExample(t *testing.T) {
917917

918918
homeDir, err := os.UserHomeDir()
919919
assert.NilError(t, err)
920-
env := map[string]string{"HOME": homeDir, "QUX": "qux_from_environment"}
920+
env := map[string]string{
921+
"HOME": homeDir,
922+
"BAR": "this is a secret",
923+
"QUX": "qux_from_environment",
924+
}
921925
config, err := loadYAMLWithEnv(string(b), env)
922926
assert.NilError(t, err)
923927

loader/validate.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,15 @@ func checkConsistency(project *types.Project) error {
6868
}
6969
}
7070
}
71+
72+
for name, secret := range project.Secrets {
73+
if secret.External.External {
74+
continue
75+
}
76+
if secret.File == "" && secret.Environment == "" {
77+
return errors.Wrap(errdefs.ErrInvalid, fmt.Sprintf("secret %q must declare either `file` or `environment`", name))
78+
}
79+
}
80+
7181
return nil
7282
}

loader/validate_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,48 @@ func TestValidateNetworkMode(t *testing.T) {
139139
assert.NilError(t, err)
140140
})
141141
}
142+
143+
func TestValidateSecret(t *testing.T) {
144+
t.Run("secret set by file", func(t *testing.T) {
145+
project := &types.Project{
146+
Secrets: types.Secrets{
147+
"foo": types.SecretConfig{
148+
File: ".secret",
149+
},
150+
},
151+
}
152+
err := checkConsistency(project)
153+
assert.NilError(t, err)
154+
})
155+
t.Run("secret set by environment", func(t *testing.T) {
156+
project := &types.Project{
157+
Secrets: types.Secrets{
158+
"foo": types.SecretConfig{
159+
Environment: "TOKEN",
160+
},
161+
},
162+
}
163+
err := checkConsistency(project)
164+
assert.NilError(t, err)
165+
})
166+
t.Run("external secret", func(t *testing.T) {
167+
project := &types.Project{
168+
Secrets: types.Secrets{
169+
"foo": types.SecretConfig{
170+
External: types.External{External: true},
171+
},
172+
},
173+
}
174+
err := checkConsistency(project)
175+
assert.NilError(t, err)
176+
})
177+
t.Run("uset secret", func(t *testing.T) {
178+
project := &types.Project{
179+
Secrets: types.Secrets{
180+
"foo": types.SecretConfig{},
181+
},
182+
}
183+
err := checkConsistency(project)
184+
assert.Error(t, err, "secret \"foo\" must declare either `file` or `environment`: invalid compose project")
185+
})
186+
}

schema/compose-spec.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@
685685
"type": "object",
686686
"properties": {
687687
"name": {"type": "string"},
688+
"environment": {"type": "string"},
688689
"file": {"type": "string"},
689690
"external": {
690691
"type": ["boolean", "object"],

types/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,7 @@ type CredentialSpecConfig struct {
891891
type FileObjectConfig struct {
892892
Name string `yaml:",omitempty" json:"name,omitempty"`
893893
File string `yaml:",omitempty" json:"file,omitempty"`
894+
Environment string `yaml:",omitempty" json:"environment,omitempty"`
894895
External External `yaml:",omitempty" json:"external,omitempty"`
895896
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
896897
Driver string `yaml:",omitempty" json:"driver,omitempty"`

0 commit comments

Comments
 (0)