-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgenerator.go
100 lines (85 loc) · 3.12 KB
/
generator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package awsconfigfile
import (
"context"
"fmt"
"regexp"
"strings"
"sync"
"golang.org/x/sync/errgroup"
"gopkg.in/ini.v1"
)
// Sources return AWS profiles to be combined into an AWS config file.
type Source interface {
GetProfiles(ctx context.Context) ([]SSOProfile, error)
}
// Generator generates AWS profiles for ~/.aws/config.
// It reads profiles from sources and merges them with
// an existing ini config file.
type Generator struct {
Sources []Source
Config *ini.File
NoCredentialProcess bool
ProfileNameTemplate string
Prefix string
// PruneStartURLs is a slice of AWS SSO start URLs which profiles are being generated for.
// Existing profiles with these start URLs will be removed if they aren't found in the Profiles field.
PruneStartURLs []string
}
// AddSource adds a new source to load profiles from to the generator.
func (g *Generator) AddSource(source Source) {
g.Sources = append(g.Sources, source)
}
const profileSectionIllegalChars = ` \][;'"`
// regular expression that matches on the characters \][;'" including whitespace, but does not match anything between {{ }} so it does not check inside go templates
// this regex is used as a basic safeguard to help users avoid mistakes in their templates
// for example "{{ .AccountName }} {{ .RoleName }}" this is invalid because it has a whitespace separating the template elements
var profileSectionIllegalCharsRegex = regexp.MustCompile(`(?s)((?:^|[^\{])[\s\][;'"]|[\][;'"][\s]*(?:$|[^\}]))`)
var matchGoTemplateSection = regexp.MustCompile(`\{\{[\s\S]*?\}\}`)
var DefaultProfileNameTemplate = "{{ .AccountName }}/{{ .RoleName }}"
// Generate AWS profiles and merge them with the existing config.
// Writes output to the generator's output.
func (g *Generator) Generate(ctx context.Context) error {
var eg errgroup.Group
var mu sync.Mutex
var profiles []SSOProfile
if strings.ContainsAny(g.Prefix, profileSectionIllegalChars) {
return fmt.Errorf("profile prefix must not contain any of these illegal characters (%s)", profileSectionIllegalChars)
}
// use the default template if it's not provided
if g.ProfileNameTemplate == "" {
g.ProfileNameTemplate = DefaultProfileNameTemplate
}
// check the profile template for any invalid section name characters
if g.ProfileNameTemplate != DefaultProfileNameTemplate {
cleaned := matchGoTemplateSection.ReplaceAllString(g.ProfileNameTemplate, "")
if profileSectionIllegalCharsRegex.MatchString(cleaned) {
return fmt.Errorf("profile template must not contain any of these illegal characters (%s)", profileSectionIllegalChars)
}
}
for _, s := range g.Sources {
scopy := s
eg.Go(func() error {
got, err := scopy.GetProfiles(ctx)
if err != nil {
return err
}
mu.Lock()
defer mu.Unlock()
profiles = append(profiles, got...)
return nil
})
}
err := eg.Wait()
if err != nil {
return err
}
err = Merge(MergeOpts{
Config: g.Config,
SectionNameTemplate: g.ProfileNameTemplate,
Profiles: profiles,
NoCredentialProcess: g.NoCredentialProcess,
Prefix: g.Prefix,
PruneStartURLs: g.PruneStartURLs,
})
return err
}