Skip to content

Commit d734bcd

Browse files
authored
Merge pull request #138 from wallyworld/robust-secret-import
#138 Secrets has fields like "auto-prune", "rotate-policy" which can be empty but which would then cause the import to panic. Imports from 3.1 (which didn't have auto-prune) to 3.4 would fail. This PR adds checks for these fields to avoid the panic, and also defensively does the same for some other similar fields in the attribute map. This will fix the missing "auto-prune" issue and avoid accidental breakage in the future. Even though the checks for the coercion to []interface{} are strictly not needed, being explicit helps readability.
2 parents 448ffa6 + c50de15 commit d734bcd

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

secretremoteconsumers.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ func importSecretRemoteConsumers(source map[string]interface{}, version int) ([]
7979
if !ok {
8080
return nil, errors.NotValidf("version %d", version)
8181
}
82-
sourceList := source["remote-consumers"].([]interface{})
82+
sourceList, ok := source["remote-consumers"].([]interface{})
83+
if !ok {
84+
return nil, nil
85+
}
8386
return importSecretRemoteConsumersList(sourceList, importFunc)
8487
}
8588

secrets.go

+26-9
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,14 @@ type secret struct {
5050
Label_ string `yaml:"label"`
5151
RotatePolicy_ string `yaml:"rotate-policy,omitempty"`
5252
Owner_ string `yaml:"owner"`
53-
AutoPrune_ bool `yaml:"auto-prune"`
53+
AutoPrune_ bool `yaml:"auto-prune,omitempty"`
5454
Created_ time.Time `yaml:"create-time"`
5555
Updated_ time.Time `yaml:"update-time"`
5656
Revisions_ []*secretRevision `yaml:"revisions"`
5757

58-
ACL_ map[string]*secretAccess `yaml:"acl"`
59-
Consumers_ []*secretConsumer `yaml:"consumers"`
60-
RemoteConsumers_ []*secretRemoteConsumer `yaml:"remote-consumers"`
58+
ACL_ map[string]*secretAccess `yaml:"acl,omitempty"`
59+
Consumers_ []*secretConsumer `yaml:"consumers,omitempty"`
60+
RemoteConsumers_ []*secretRemoteConsumer `yaml:"remote-consumers,omitempty"`
6161

6262
NextRotateTime_ *time.Time `yaml:"next-rotate-time,omitempty"`
6363

@@ -352,6 +352,7 @@ func secretV1Fields() (schema.Fields, schema.Defaults) {
352352
"rotate-policy": schema.Omit,
353353
"auto-prune": schema.Omit,
354354
"next-rotate-time": schema.Omit,
355+
"acl": schema.Omit,
355356
"consumers": schema.Omit,
356357
"remote-consumers": schema.Omit,
357358
}
@@ -372,14 +373,21 @@ func importSecret(source map[string]interface{}, importVersion int, fieldFunc fu
372373
Version_: int(valid["secret-version"].(int64)),
373374
Description_: valid["description"].(string),
374375
Label_: valid["label"].(string),
375-
RotatePolicy_: valid["rotate-policy"].(string),
376-
AutoPrune_: valid["auto-prune"].(bool),
377376
Owner_: valid["owner"].(string),
378377
Created_: valid["create-time"].(time.Time).UTC(),
379378
Updated_: valid["update-time"].(time.Time).UTC(),
380379
NextRotateTime_: fieldToTimePtr(valid, "next-rotate-time"),
381380
}
382381

382+
if policy, ok := valid["rotate-policy"].(string); ok {
383+
secret.RotatePolicy_ = policy
384+
}
385+
386+
// This should be in a v2 schema but it's already also in v1.
387+
if autoPrune, ok := valid["auto-prune"].(bool); ok {
388+
secret.AutoPrune_ = autoPrune
389+
}
390+
383391
secretACL, err := importSecretAccess(valid, importVersion)
384392
if err != nil {
385393
return nil, errors.Trace(err)
@@ -456,7 +464,10 @@ func importSecretAccess(source map[string]interface{}, version int) (map[string]
456464
if !ok {
457465
return nil, errors.NotValidf("version %d", version)
458466
}
459-
sourceList := source["acl"].(map[interface{}]interface{})
467+
sourceList, ok := source["acl"].(map[interface{}]interface{})
468+
if !ok {
469+
return nil, nil
470+
}
460471
return importSecretAccessMap(sourceList, importFunc)
461472
}
462473

@@ -571,7 +582,10 @@ func importSecretConsumers(source map[string]interface{}, version int) ([]*secre
571582
if !ok {
572583
return nil, errors.NotValidf("version %d", version)
573584
}
574-
sourceList := source["consumers"].([]interface{})
585+
sourceList, ok := source["consumers"].([]interface{})
586+
if !ok {
587+
return nil, nil
588+
}
575589
return importSecretConsumersList(sourceList, importFunc)
576590
}
577591

@@ -759,7 +773,10 @@ func importSecretRevisions(source map[string]interface{}, version int) ([]*secre
759773
if !ok {
760774
return nil, errors.NotValidf("version %d", version)
761775
}
762-
sourceList := source["revisions"].([]interface{})
776+
sourceList, ok := source["revisions"].([]interface{})
777+
if !ok {
778+
return nil, nil
779+
}
763780
return importSecretRevisionList(sourceList, importFunc)
764781
}
765782

secrets_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,52 @@ func (s *SecretsSerializationSuite) TestParsingSerializedData(c *gc.C) {
251251
secret := s.exportImport(c, original, 1)
252252
c.Assert(secret, jc.DeepEquals, original)
253253
}
254+
255+
type oldSecret struct {
256+
ID_ string `yaml:"id"`
257+
Version_ int `yaml:"secret-version"`
258+
Description_ string `yaml:"description"`
259+
Label_ string `yaml:"label"`
260+
Owner_ string `yaml:"owner"`
261+
Created_ time.Time `yaml:"create-time"`
262+
Updated_ time.Time `yaml:"update-time"`
263+
Revisions_ []*secretRevision `yaml:"revisions"`
264+
}
265+
266+
type oldSecrets struct {
267+
Version int `yaml:"version"`
268+
Secrets_ []*oldSecret `yaml:"secrets"`
269+
}
270+
271+
func (s *SecretsSerializationSuite) TestParsingSerializedDataNoAutoPrune(c *gc.C) {
272+
args := testSecretArgs()
273+
original := &oldSecret{
274+
ID_: args.ID,
275+
Version_: args.Version,
276+
Created_: args.Created.UTC(),
277+
Updated_: args.Updated.UTC(),
278+
}
279+
initial := oldSecrets{
280+
Version: 1,
281+
Secrets_: []*oldSecret{original},
282+
}
283+
284+
bytes, err := yaml.Marshal(initial)
285+
c.Assert(err, jc.ErrorIsNil)
286+
287+
var source map[string]interface{}
288+
err = yaml.Unmarshal(bytes, &source)
289+
c.Assert(err, jc.ErrorIsNil)
290+
291+
secrets, err := importSecrets(source)
292+
c.Assert(err, jc.ErrorIsNil)
293+
c.Assert(secrets, gc.HasLen, 1)
294+
295+
c.Assert(secrets[0], jc.DeepEquals, &secret{
296+
ID_: original.ID_,
297+
Version_: original.Version_,
298+
Owner_: original.Owner_,
299+
Created_: original.Created_,
300+
Updated_: original.Updated_,
301+
})
302+
}

0 commit comments

Comments
 (0)