CWL spec -> CWL standards
[arvados.git] / lib / config / export.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package config
6
7 import (
8         "encoding/json"
9         "errors"
10         "fmt"
11         "io"
12         "strings"
13
14         "git.arvados.org/arvados.git/sdk/go/arvados"
15 )
16
17 // ExportJSON writes a JSON object with the safe (non-secret) portions
18 // of the cluster config to w.
19 func ExportJSON(w io.Writer, cluster *arvados.Cluster) error {
20         buf, err := json.Marshal(cluster)
21         if err != nil {
22                 return err
23         }
24         var m map[string]interface{}
25         err = json.Unmarshal(buf, &m)
26         if err != nil {
27                 return err
28         }
29
30         // ClusterID is not marshalled by default (see `json:"-"`).
31         // Add it back here so it is included in the exported config.
32         m["ClusterID"] = cluster.ClusterID
33         err = redactUnsafe(m, "", "")
34         if err != nil {
35                 return err
36         }
37         return json.NewEncoder(w).Encode(m)
38 }
39
40 // whitelist classifies configs as safe/unsafe to reveal to
41 // unauthenticated clients.
42 //
43 // Every config entry must either be listed explicitly here along with
44 // all of its parent keys (e.g., "API" + "API.RequestTimeout"), or
45 // have an ancestor listed as false (e.g.,
46 // "PostgreSQL.Connection.password" has an ancestor
47 // "PostgreSQL.Connection" with a false value). Otherwise, it is a bug
48 // which should be caught by tests.
49 //
50 // Example: API.RequestTimeout is safe because whitelist["API"] == and
51 // whitelist["API.RequestTimeout"] == true.
52 //
53 // Example: PostgreSQL.Connection.password is not safe because
54 // whitelist["PostgreSQL.Connection"] == false.
55 //
56 // Example: PostgreSQL.BadKey would cause an error because
57 // whitelist["PostgreSQL"] isn't false, and neither
58 // whitelist["PostgreSQL.BadKey"] nor whitelist["PostgreSQL.*"]
59 // exists.
60 var whitelist = map[string]bool{
61         // | sort -t'"' -k2,2
62         "ClusterID":                                    true,
63         "API":                                          true,
64         "API.AsyncPermissionsUpdateInterval":           false,
65         "API.DisabledAPIs":                             false,
66         "API.MaxConcurrentRequests":                    false,
67         "API.MaxIndexDatabaseRead":                     false,
68         "API.MaxItemsPerResponse":                      true,
69         "API.MaxKeepBlobBuffers":                       false,
70         "API.MaxRequestAmplification":                  false,
71         "API.MaxRequestSize":                           true,
72         "API.RailsSessionSecretToken":                  false,
73         "API.RequestTimeout":                           true,
74         "API.WebsocketClientEventQueue":                false,
75         "API.SendTimeout":                              true,
76         "API.WebsocketServerEventQueue":                false,
77         "API.KeepServiceRequestTimeout":                false,
78         "AuditLogs":                                    false,
79         "AuditLogs.MaxAge":                             false,
80         "AuditLogs.MaxDeleteBatch":                     false,
81         "AuditLogs.UnloggedAttributes":                 false,
82         "Collections":                                  true,
83         "Collections.BlobSigning":                      true,
84         "Collections.BlobSigningKey":                   false,
85         "Collections.BlobSigningTTL":                   true,
86         "Collections.BlobTrash":                        false,
87         "Collections.BlobTrashLifetime":                false,
88         "Collections.BlobTrashConcurrency":             false,
89         "Collections.BlobTrashCheckInterval":           false,
90         "Collections.BlobDeleteConcurrency":            false,
91         "Collections.BlobReplicateConcurrency":         false,
92         "Collections.CollectionVersioning":             false,
93         "Collections.DefaultReplication":               true,
94         "Collections.DefaultTrashLifetime":             true,
95         "Collections.ForwardSlashNameSubstitution":     true,
96         "Collections.ManagedProperties":                true,
97         "Collections.ManagedProperties.*":              true,
98         "Collections.ManagedProperties.*.*":            true,
99         "Collections.PreserveVersionIfIdle":            true,
100         "Collections.TrashSweepInterval":               false,
101         "Collections.TrustAllContent":                  false,
102         "Collections.WebDAVCache":                      false,
103         "Collections.BalanceCollectionBatch":           false,
104         "Collections.BalancePeriod":                    false,
105         "Collections.BlobMissingReport":                false,
106         "Collections.BalanceCollectionBuffers":         false,
107         "Containers":                                   true,
108         "Containers.CloudVMs":                          false,
109         "Containers.CrunchRunCommand":                  false,
110         "Containers.CrunchRunArgumentsList":            false,
111         "Containers.DefaultKeepCacheRAM":               true,
112         "Containers.DispatchPrivateKey":                false,
113         "Containers.JobsAPI":                           true,
114         "Containers.JobsAPI.Enable":                    true,
115         "Containers.JobsAPI.GitInternalDir":            false,
116         "Containers.Logging":                           false,
117         "Containers.LogReuseDecisions":                 false,
118         "Containers.MaxComputeVMs":                     false,
119         "Containers.MaxDispatchAttempts":               false,
120         "Containers.MaxRetryAttempts":                  true,
121         "Containers.MinRetryPeriod":                    true,
122         "Containers.ReserveExtraRAM":                   true,
123         "Containers.SLURM":                             false,
124         "Containers.StaleLockTimeout":                  false,
125         "Containers.SupportedDockerImageFormats":       true,
126         "Containers.SupportedDockerImageFormats.*":     true,
127         "Containers.UsePreemptibleInstances":           true,
128         "ForceLegacyAPI14":                             false,
129         "Git":                                          false,
130         "InstanceTypes":                                true,
131         "InstanceTypes.*":                              true,
132         "InstanceTypes.*.*":                            true,
133         "Login":                                        true,
134         "Login.GoogleClientID":                         false,
135         "Login.GoogleClientSecret":                     false,
136         "Login.GoogleAlternateEmailAddresses":          false,
137         "Login.PAM":                                    true,
138         "Login.PAMService":                             false,
139         "Login.PAMDefaultEmailDomain":                  false,
140         "Login.ProviderAppID":                          false,
141         "Login.ProviderAppSecret":                      false,
142         "Login.LoginCluster":                           true,
143         "Login.RemoteTokenRefresh":                     true,
144         "Mail":                                         true,
145         "Mail.MailchimpAPIKey":                         false,
146         "Mail.MailchimpListID":                         false,
147         "Mail.SendUserSetupNotificationEmail":          false,
148         "Mail.IssueReporterEmailFrom":                  false,
149         "Mail.IssueReporterEmailTo":                    false,
150         "Mail.SupportEmailAddress":                     true,
151         "Mail.EmailFrom":                               false,
152         "ManagementToken":                              false,
153         "PostgreSQL":                                   false,
154         "RemoteClusters":                               true,
155         "RemoteClusters.*":                             true,
156         "RemoteClusters.*.ActivateUsers":               true,
157         "RemoteClusters.*.Host":                        true,
158         "RemoteClusters.*.Insecure":                    true,
159         "RemoteClusters.*.Proxy":                       true,
160         "RemoteClusters.*.Scheme":                      true,
161         "Services":                                     true,
162         "Services.*":                                   true,
163         "Services.*.ExternalURL":                       true,
164         "Services.*.InternalURLs":                      false,
165         "SystemLogs":                                   false,
166         "SystemRootToken":                              false,
167         "TLS":                                          false,
168         "Users":                                        true,
169         "Users.AnonymousUserToken":                     true,
170         "Users.AdminNotifierEmailFrom":                 false,
171         "Users.AutoAdminFirstUser":                     false,
172         "Users.AutoAdminUserWithEmail":                 false,
173         "Users.AutoSetupNewUsers":                      false,
174         "Users.AutoSetupNewUsersWithRepository":        false,
175         "Users.AutoSetupNewUsersWithVmUUID":            false,
176         "Users.AutoSetupUsernameBlacklist":             false,
177         "Users.EmailSubjectPrefix":                     false,
178         "Users.NewInactiveUserNotificationRecipients":  false,
179         "Users.NewUserNotificationRecipients":          false,
180         "Users.NewUsersAreActive":                      false,
181         "Users.PreferDomainForUsername":                false,
182         "Users.UserNotifierEmailFrom":                  false,
183         "Users.UserProfileNotificationAddress":         false,
184         "Volumes":                                      true,
185         "Volumes.*":                                    true,
186         "Volumes.*.*":                                  false,
187         "Volumes.*.AccessViaHosts":                     true,
188         "Volumes.*.AccessViaHosts.*":                   true,
189         "Volumes.*.AccessViaHosts.*.ReadOnly":          true,
190         "Volumes.*.ReadOnly":                           true,
191         "Volumes.*.Replication":                        true,
192         "Volumes.*.StorageClasses":                     true,
193         "Volumes.*.StorageClasses.*":                   false,
194         "Workbench":                                    true,
195         "Workbench.ActivationContactLink":              false,
196         "Workbench.APIClientConnectTimeout":            true,
197         "Workbench.APIClientReceiveTimeout":            true,
198         "Workbench.APIResponseCompression":             true,
199         "Workbench.ApplicationMimetypesWithViewIcon":   true,
200         "Workbench.ApplicationMimetypesWithViewIcon.*": true,
201         "Workbench.ArvadosDocsite":                     true,
202         "Workbench.ArvadosPublicDataDocURL":            true,
203         "Workbench.DefaultOpenIdPrefix":                false,
204         "Workbench.EnableGettingStartedPopup":          true,
205         "Workbench.EnablePublicProjectsPage":           true,
206         "Workbench.FileViewersConfigURL":               true,
207         "Workbench.LogViewerMaxBytes":                  true,
208         "Workbench.MultiSiteSearch":                    true,
209         "Workbench.ProfilingEnabled":                   true,
210         "Workbench.Repositories":                       false,
211         "Workbench.RepositoryCache":                    false,
212         "Workbench.RunningJobLogRecordsToFetch":        true,
213         "Workbench.SecretKeyBase":                      false,
214         "Workbench.ShowRecentCollectionsOnDashboard":   true,
215         "Workbench.ShowUserAgreementInline":            true,
216         "Workbench.ShowUserNotifications":              true,
217         "Workbench.SiteName":                           true,
218         "Workbench.Theme":                              true,
219         "Workbench.UserProfileFormFields":              true,
220         "Workbench.UserProfileFormFields.*":            true,
221         "Workbench.UserProfileFormFields.*.*":          true,
222         "Workbench.UserProfileFormFields.*.*.*":        true,
223         "Workbench.UserProfileFormMessage":             true,
224         "Workbench.VocabularyURL":                      true,
225         "Workbench.WelcomePageHTML":                    true,
226         "Workbench.InactivePageHTML":                   true,
227         "Workbench.SSHHelpPageHTML":                    true,
228         "Workbench.SSHHelpHostSuffix":                  true,
229 }
230
231 func redactUnsafe(m map[string]interface{}, mPrefix, lookupPrefix string) error {
232         var errs []string
233         for k, v := range m {
234                 lookupKey := k
235                 safe, ok := whitelist[lookupPrefix+k]
236                 if !ok {
237                         lookupKey = "*"
238                         safe, ok = whitelist[lookupPrefix+"*"]
239                 }
240                 if !ok {
241                         errs = append(errs, fmt.Sprintf("config bug: key %q not in whitelist map", lookupPrefix+k))
242                         continue
243                 }
244                 if !safe {
245                         delete(m, k)
246                         continue
247                 }
248                 if v, ok := v.(map[string]interface{}); ok {
249                         err := redactUnsafe(v, mPrefix+k+".", lookupPrefix+lookupKey+".")
250                         if err != nil {
251                                 errs = append(errs, err.Error())
252                         }
253                 }
254         }
255         if len(errs) > 0 {
256                 return errors.New(strings.Join(errs, "\n"))
257         }
258         return nil
259 }