##// END OF EJS Templates
ssh-support: don't use API calls to fetch the data....
marcink -
r2186:32d56a2c default
parent child Browse files
Show More
@@ -1,728 +1,720 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 use = egg:waitress#main
54 use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 threads = 5
56 threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 max_request_body_size = 107374182400
58 max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 asyncore_use_poll = true
61 asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 #use = egg:gunicorn#main
69 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 #workers = 2
74 #workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
76 ## generally recommended to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 #proc_name = rhodecode
79 #proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = sync
82 #worker_class = sync
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 #max_requests = 1000
87 #max_requests = 1000
88 #max_requests_jitter = 30
88 #max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 #timeout = 21600
91 #timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 # During development the we want to have the debug toolbar enabled
111 # During development the we want to have the debug toolbar enabled
112 pyramid.includes =
112 pyramid.includes =
113 pyramid_debugtoolbar
113 pyramid_debugtoolbar
114 rhodecode.lib.middleware.request_wrapper
114 rhodecode.lib.middleware.request_wrapper
115
115
116 pyramid.reload_templates = true
116 pyramid.reload_templates = true
117
117
118 debugtoolbar.hosts = 0.0.0.0/0
118 debugtoolbar.hosts = 0.0.0.0/0
119 debugtoolbar.exclude_prefixes =
119 debugtoolbar.exclude_prefixes =
120 /css
120 /css
121 /fonts
121 /fonts
122 /images
122 /images
123 /js
123 /js
124
124
125 ## RHODECODE PLUGINS ##
125 ## RHODECODE PLUGINS ##
126 rhodecode.includes =
126 rhodecode.includes =
127 rhodecode.api
127 rhodecode.api
128
128
129
129
130 # api prefix url
130 # api prefix url
131 rhodecode.api.url = /_admin/api
131 rhodecode.api.url = /_admin/api
132
132
133
133
134 ## END RHODECODE PLUGINS ##
134 ## END RHODECODE PLUGINS ##
135
135
136 ## encryption key used to encrypt social plugin tokens,
136 ## encryption key used to encrypt social plugin tokens,
137 ## remote_urls with credentials etc, if not set it defaults to
137 ## remote_urls with credentials etc, if not set it defaults to
138 ## `beaker.session.secret`
138 ## `beaker.session.secret`
139 #rhodecode.encrypted_values.secret =
139 #rhodecode.encrypted_values.secret =
140
140
141 ## decryption strict mode (enabled by default). It controls if decryption raises
141 ## decryption strict mode (enabled by default). It controls if decryption raises
142 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
142 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
143 #rhodecode.encrypted_values.strict = false
143 #rhodecode.encrypted_values.strict = false
144
144
145 ## return gzipped responses from Rhodecode (static files/application)
145 ## return gzipped responses from Rhodecode (static files/application)
146 gzip_responses = false
146 gzip_responses = false
147
147
148 ## autogenerate javascript routes file on startup
148 ## autogenerate javascript routes file on startup
149 generate_js_files = false
149 generate_js_files = false
150
150
151 ## Optional Languages
151 ## Optional Languages
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
152 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
153 lang = en
153 lang = en
154
154
155 ## perform a full repository scan on each server start, this should be
155 ## perform a full repository scan on each server start, this should be
156 ## set to false after first startup, to allow faster server restarts.
156 ## set to false after first startup, to allow faster server restarts.
157 startup.import_repos = false
157 startup.import_repos = false
158
158
159 ## Uncomment and set this path to use archive download cache.
159 ## Uncomment and set this path to use archive download cache.
160 ## Once enabled, generated archives will be cached at this location
160 ## Once enabled, generated archives will be cached at this location
161 ## and served from the cache during subsequent requests for the same archive of
161 ## and served from the cache during subsequent requests for the same archive of
162 ## the repository.
162 ## the repository.
163 #archive_cache_dir = /tmp/tarballcache
163 #archive_cache_dir = /tmp/tarballcache
164
164
165 ## change this to unique ID for security
165 ## change this to unique ID for security
166 app_instance_uuid = rc-production
166 app_instance_uuid = rc-production
167
167
168 ## cut off limit for large diffs (size in bytes). If overall diff size on
168 ## cut off limit for large diffs (size in bytes). If overall diff size on
169 ## commit, or pull request exceeds this limit this diff will be displayed
169 ## commit, or pull request exceeds this limit this diff will be displayed
170 ## partially. E.g 512000 == 512Kb
170 ## partially. E.g 512000 == 512Kb
171 cut_off_limit_diff = 512000
171 cut_off_limit_diff = 512000
172
172
173 ## cut off limit for large files inside diffs (size in bytes). Each individual
173 ## cut off limit for large files inside diffs (size in bytes). Each individual
174 ## file inside diff which exceeds this limit will be displayed partially.
174 ## file inside diff which exceeds this limit will be displayed partially.
175 ## E.g 128000 == 128Kb
175 ## E.g 128000 == 128Kb
176 cut_off_limit_file = 128000
176 cut_off_limit_file = 128000
177
177
178 ## use cache version of scm repo everywhere
178 ## use cache version of scm repo everywhere
179 vcs_full_cache = true
179 vcs_full_cache = true
180
180
181 ## force https in RhodeCode, fixes https redirects, assumes it's always https
181 ## force https in RhodeCode, fixes https redirects, assumes it's always https
182 ## Normally this is controlled by proper http flags sent from http server
182 ## Normally this is controlled by proper http flags sent from http server
183 force_https = false
183 force_https = false
184
184
185 ## use Strict-Transport-Security headers
185 ## use Strict-Transport-Security headers
186 use_htsts = false
186 use_htsts = false
187
187
188 ## number of commits stats will parse on each iteration
188 ## number of commits stats will parse on each iteration
189 commit_parse_limit = 25
189 commit_parse_limit = 25
190
190
191 ## git rev filter option, --all is the default filter, if you need to
191 ## git rev filter option, --all is the default filter, if you need to
192 ## hide all refs in changelog switch this to --branches --tags
192 ## hide all refs in changelog switch this to --branches --tags
193 git_rev_filter = --branches --tags
193 git_rev_filter = --branches --tags
194
194
195 # Set to true if your repos are exposed using the dumb protocol
195 # Set to true if your repos are exposed using the dumb protocol
196 git_update_server_info = false
196 git_update_server_info = false
197
197
198 ## RSS/ATOM feed options
198 ## RSS/ATOM feed options
199 rss_cut_off_limit = 256000
199 rss_cut_off_limit = 256000
200 rss_items_per_page = 10
200 rss_items_per_page = 10
201 rss_include_diff = false
201 rss_include_diff = false
202
202
203 ## gist URL alias, used to create nicer urls for gist. This should be an
203 ## gist URL alias, used to create nicer urls for gist. This should be an
204 ## url that does rewrites to _admin/gists/{gistid}.
204 ## url that does rewrites to _admin/gists/{gistid}.
205 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
205 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
206 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
206 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
207 gist_alias_url =
207 gist_alias_url =
208
208
209 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
209 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
210 ## used for access.
210 ## used for access.
211 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
211 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
212 ## came from the the logged in user who own this authentication token.
212 ## came from the the logged in user who own this authentication token.
213 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
213 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
214 ## authentication token. Such view would be only accessible when used together
214 ## authentication token. Such view would be only accessible when used together
215 ## with this authentication token
215 ## with this authentication token
216 ##
216 ##
217 ## list of all views can be found under `/_admin/permissions/auth_token_access`
217 ## list of all views can be found under `/_admin/permissions/auth_token_access`
218 ## The list should be "," separated and on a single line.
218 ## The list should be "," separated and on a single line.
219 ##
219 ##
220 ## Most common views to enable:
220 ## Most common views to enable:
221 # RepoCommitsView:repo_commit_download
221 # RepoCommitsView:repo_commit_download
222 # RepoCommitsView:repo_commit_patch
222 # RepoCommitsView:repo_commit_patch
223 # RepoCommitsView:repo_commit_raw
223 # RepoCommitsView:repo_commit_raw
224 # RepoCommitsView:repo_commit_raw@TOKEN
224 # RepoCommitsView:repo_commit_raw@TOKEN
225 # RepoFilesView:repo_files_diff
225 # RepoFilesView:repo_files_diff
226 # RepoFilesView:repo_archivefile
226 # RepoFilesView:repo_archivefile
227 # RepoFilesView:repo_file_raw
227 # RepoFilesView:repo_file_raw
228 # GistView:*
228 # GistView:*
229 api_access_controllers_whitelist =
229 api_access_controllers_whitelist =
230
230
231 ## default encoding used to convert from and to unicode
231 ## default encoding used to convert from and to unicode
232 ## can be also a comma separated list of encoding in case of mixed encodings
232 ## can be also a comma separated list of encoding in case of mixed encodings
233 default_encoding = UTF-8
233 default_encoding = UTF-8
234
234
235 ## instance-id prefix
235 ## instance-id prefix
236 ## a prefix key for this instance used for cache invalidation when running
236 ## a prefix key for this instance used for cache invalidation when running
237 ## multiple instances of rhodecode, make sure it's globally unique for
237 ## multiple instances of rhodecode, make sure it's globally unique for
238 ## all running rhodecode instances. Leave empty if you don't use it
238 ## all running rhodecode instances. Leave empty if you don't use it
239 instance_id =
239 instance_id =
240
240
241 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
241 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
242 ## of an authentication plugin also if it is disabled by it's settings.
242 ## of an authentication plugin also if it is disabled by it's settings.
243 ## This could be useful if you are unable to log in to the system due to broken
243 ## This could be useful if you are unable to log in to the system due to broken
244 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
244 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
245 ## module to log in again and fix the settings.
245 ## module to log in again and fix the settings.
246 ##
246 ##
247 ## Available builtin plugin IDs (hash is part of the ID):
247 ## Available builtin plugin IDs (hash is part of the ID):
248 ## egg:rhodecode-enterprise-ce#rhodecode
248 ## egg:rhodecode-enterprise-ce#rhodecode
249 ## egg:rhodecode-enterprise-ce#pam
249 ## egg:rhodecode-enterprise-ce#pam
250 ## egg:rhodecode-enterprise-ce#ldap
250 ## egg:rhodecode-enterprise-ce#ldap
251 ## egg:rhodecode-enterprise-ce#jasig_cas
251 ## egg:rhodecode-enterprise-ce#jasig_cas
252 ## egg:rhodecode-enterprise-ce#headers
252 ## egg:rhodecode-enterprise-ce#headers
253 ## egg:rhodecode-enterprise-ce#crowd
253 ## egg:rhodecode-enterprise-ce#crowd
254 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
254 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
255
255
256 ## alternative return HTTP header for failed authentication. Default HTTP
256 ## alternative return HTTP header for failed authentication. Default HTTP
257 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
257 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
258 ## handling that causing a series of failed authentication calls.
258 ## handling that causing a series of failed authentication calls.
259 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
259 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
260 ## This will be served instead of default 401 on bad authnetication
260 ## This will be served instead of default 401 on bad authnetication
261 auth_ret_code =
261 auth_ret_code =
262
262
263 ## use special detection method when serving auth_ret_code, instead of serving
263 ## use special detection method when serving auth_ret_code, instead of serving
264 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
264 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
265 ## and then serve auth_ret_code to clients
265 ## and then serve auth_ret_code to clients
266 auth_ret_code_detection = false
266 auth_ret_code_detection = false
267
267
268 ## locking return code. When repository is locked return this HTTP code. 2XX
268 ## locking return code. When repository is locked return this HTTP code. 2XX
269 ## codes don't break the transactions while 4XX codes do
269 ## codes don't break the transactions while 4XX codes do
270 lock_ret_code = 423
270 lock_ret_code = 423
271
271
272 ## allows to change the repository location in settings page
272 ## allows to change the repository location in settings page
273 allow_repo_location_change = true
273 allow_repo_location_change = true
274
274
275 ## allows to setup custom hooks in settings page
275 ## allows to setup custom hooks in settings page
276 allow_custom_hooks_settings = true
276 allow_custom_hooks_settings = true
277
277
278 ## generated license token, goto license page in RhodeCode settings to obtain
278 ## generated license token, goto license page in RhodeCode settings to obtain
279 ## new token
279 ## new token
280 license_token =
280 license_token =
281
281
282 ## supervisor connection uri, for managing supervisor and logs.
282 ## supervisor connection uri, for managing supervisor and logs.
283 supervisor.uri =
283 supervisor.uri =
284 ## supervisord group name/id we only want this RC instance to handle
284 ## supervisord group name/id we only want this RC instance to handle
285 supervisor.group_id = dev
285 supervisor.group_id = dev
286
286
287 ## Display extended labs settings
287 ## Display extended labs settings
288 labs_settings_active = true
288 labs_settings_active = true
289
289
290 ####################################
290 ####################################
291 ### CELERY CONFIG ####
291 ### CELERY CONFIG ####
292 ####################################
292 ####################################
293 use_celery = false
293 use_celery = false
294 broker.host = localhost
294 broker.host = localhost
295 broker.vhost = rabbitmqhost
295 broker.vhost = rabbitmqhost
296 broker.port = 5672
296 broker.port = 5672
297 broker.user = rabbitmq
297 broker.user = rabbitmq
298 broker.password = qweqwe
298 broker.password = qweqwe
299
299
300 celery.imports = rhodecode.lib.celerylib.tasks
300 celery.imports = rhodecode.lib.celerylib.tasks
301
301
302 celery.result.backend = amqp
302 celery.result.backend = amqp
303 celery.result.dburi = amqp://
303 celery.result.dburi = amqp://
304 celery.result.serialier = json
304 celery.result.serialier = json
305
305
306 #celery.send.task.error.emails = true
306 #celery.send.task.error.emails = true
307 #celery.amqp.task.result.expires = 18000
307 #celery.amqp.task.result.expires = 18000
308
308
309 celeryd.concurrency = 2
309 celeryd.concurrency = 2
310 #celeryd.log.file = celeryd.log
310 #celeryd.log.file = celeryd.log
311 celeryd.log.level = debug
311 celeryd.log.level = debug
312 celeryd.max.tasks.per.child = 1
312 celeryd.max.tasks.per.child = 1
313
313
314 ## tasks will never be sent to the queue, but executed locally instead.
314 ## tasks will never be sent to the queue, but executed locally instead.
315 celery.always.eager = false
315 celery.always.eager = false
316
316
317 ####################################
317 ####################################
318 ### BEAKER CACHE ####
318 ### BEAKER CACHE ####
319 ####################################
319 ####################################
320 # default cache dir for templates. Putting this into a ramdisk
320 # default cache dir for templates. Putting this into a ramdisk
321 ## can boost performance, eg. %(here)s/data_ramdisk
321 ## can boost performance, eg. %(here)s/data_ramdisk
322 cache_dir = %(here)s/data
322 cache_dir = %(here)s/data
323
323
324 ## locking and default file storage for Beaker. Putting this into a ramdisk
324 ## locking and default file storage for Beaker. Putting this into a ramdisk
325 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
325 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
326 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
326 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
327 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
327 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
328
328
329 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
329 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
330
330
331 beaker.cache.super_short_term.type = memory
331 beaker.cache.super_short_term.type = memory
332 beaker.cache.super_short_term.expire = 10
332 beaker.cache.super_short_term.expire = 10
333 beaker.cache.super_short_term.key_length = 256
333 beaker.cache.super_short_term.key_length = 256
334
334
335 beaker.cache.short_term.type = memory
335 beaker.cache.short_term.type = memory
336 beaker.cache.short_term.expire = 60
336 beaker.cache.short_term.expire = 60
337 beaker.cache.short_term.key_length = 256
337 beaker.cache.short_term.key_length = 256
338
338
339 beaker.cache.long_term.type = memory
339 beaker.cache.long_term.type = memory
340 beaker.cache.long_term.expire = 36000
340 beaker.cache.long_term.expire = 36000
341 beaker.cache.long_term.key_length = 256
341 beaker.cache.long_term.key_length = 256
342
342
343 beaker.cache.sql_cache_short.type = memory
343 beaker.cache.sql_cache_short.type = memory
344 beaker.cache.sql_cache_short.expire = 10
344 beaker.cache.sql_cache_short.expire = 10
345 beaker.cache.sql_cache_short.key_length = 256
345 beaker.cache.sql_cache_short.key_length = 256
346
346
347 ## default is memory cache, configure only if required
347 ## default is memory cache, configure only if required
348 ## using multi-node or multi-worker setup
348 ## using multi-node or multi-worker setup
349 #beaker.cache.auth_plugins.type = ext:database
349 #beaker.cache.auth_plugins.type = ext:database
350 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
350 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
351 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
351 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
352 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
352 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
353 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
353 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
354 #beaker.cache.auth_plugins.sa.pool_size = 10
354 #beaker.cache.auth_plugins.sa.pool_size = 10
355 #beaker.cache.auth_plugins.sa.max_overflow = 0
355 #beaker.cache.auth_plugins.sa.max_overflow = 0
356
356
357 beaker.cache.repo_cache_long.type = memorylru_base
357 beaker.cache.repo_cache_long.type = memorylru_base
358 beaker.cache.repo_cache_long.max_items = 4096
358 beaker.cache.repo_cache_long.max_items = 4096
359 beaker.cache.repo_cache_long.expire = 2592000
359 beaker.cache.repo_cache_long.expire = 2592000
360
360
361 ## default is memorylru_base cache, configure only if required
361 ## default is memorylru_base cache, configure only if required
362 ## using multi-node or multi-worker setup
362 ## using multi-node or multi-worker setup
363 #beaker.cache.repo_cache_long.type = ext:memcached
363 #beaker.cache.repo_cache_long.type = ext:memcached
364 #beaker.cache.repo_cache_long.url = localhost:11211
364 #beaker.cache.repo_cache_long.url = localhost:11211
365 #beaker.cache.repo_cache_long.expire = 1209600
365 #beaker.cache.repo_cache_long.expire = 1209600
366 #beaker.cache.repo_cache_long.key_length = 256
366 #beaker.cache.repo_cache_long.key_length = 256
367
367
368 ####################################
368 ####################################
369 ### BEAKER SESSION ####
369 ### BEAKER SESSION ####
370 ####################################
370 ####################################
371
371
372 ## .session.type is type of storage options for the session, current allowed
372 ## .session.type is type of storage options for the session, current allowed
373 ## types are file, ext:memcached, ext:database, and memory (default).
373 ## types are file, ext:memcached, ext:database, and memory (default).
374 beaker.session.type = file
374 beaker.session.type = file
375 beaker.session.data_dir = %(here)s/data/sessions/data
375 beaker.session.data_dir = %(here)s/data/sessions/data
376
376
377 ## db based session, fast, and allows easy management over logged in users
377 ## db based session, fast, and allows easy management over logged in users
378 #beaker.session.type = ext:database
378 #beaker.session.type = ext:database
379 #beaker.session.table_name = db_session
379 #beaker.session.table_name = db_session
380 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
380 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
381 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
381 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
382 #beaker.session.sa.pool_recycle = 3600
382 #beaker.session.sa.pool_recycle = 3600
383 #beaker.session.sa.echo = false
383 #beaker.session.sa.echo = false
384
384
385 beaker.session.key = rhodecode
385 beaker.session.key = rhodecode
386 beaker.session.secret = develop-rc-uytcxaz
386 beaker.session.secret = develop-rc-uytcxaz
387 beaker.session.lock_dir = %(here)s/data/sessions/lock
387 beaker.session.lock_dir = %(here)s/data/sessions/lock
388
388
389 ## Secure encrypted cookie. Requires AES and AES python libraries
389 ## Secure encrypted cookie. Requires AES and AES python libraries
390 ## you must disable beaker.session.secret to use this
390 ## you must disable beaker.session.secret to use this
391 #beaker.session.encrypt_key = key_for_encryption
391 #beaker.session.encrypt_key = key_for_encryption
392 #beaker.session.validate_key = validation_key
392 #beaker.session.validate_key = validation_key
393
393
394 ## sets session as invalid(also logging out user) if it haven not been
394 ## sets session as invalid(also logging out user) if it haven not been
395 ## accessed for given amount of time in seconds
395 ## accessed for given amount of time in seconds
396 beaker.session.timeout = 2592000
396 beaker.session.timeout = 2592000
397 beaker.session.httponly = true
397 beaker.session.httponly = true
398 ## Path to use for the cookie. Set to prefix if you use prefix middleware
398 ## Path to use for the cookie. Set to prefix if you use prefix middleware
399 #beaker.session.cookie_path = /custom_prefix
399 #beaker.session.cookie_path = /custom_prefix
400
400
401 ## uncomment for https secure cookie
401 ## uncomment for https secure cookie
402 beaker.session.secure = false
402 beaker.session.secure = false
403
403
404 ## auto save the session to not to use .save()
404 ## auto save the session to not to use .save()
405 beaker.session.auto = false
405 beaker.session.auto = false
406
406
407 ## default cookie expiration time in seconds, set to `true` to set expire
407 ## default cookie expiration time in seconds, set to `true` to set expire
408 ## at browser close
408 ## at browser close
409 #beaker.session.cookie_expires = 3600
409 #beaker.session.cookie_expires = 3600
410
410
411 ###################################
411 ###################################
412 ## SEARCH INDEXING CONFIGURATION ##
412 ## SEARCH INDEXING CONFIGURATION ##
413 ###################################
413 ###################################
414 ## Full text search indexer is available in rhodecode-tools under
414 ## Full text search indexer is available in rhodecode-tools under
415 ## `rhodecode-tools index` command
415 ## `rhodecode-tools index` command
416
416
417 ## WHOOSH Backend, doesn't require additional services to run
417 ## WHOOSH Backend, doesn't require additional services to run
418 ## it works good with few dozen repos
418 ## it works good with few dozen repos
419 search.module = rhodecode.lib.index.whoosh
419 search.module = rhodecode.lib.index.whoosh
420 search.location = %(here)s/data/index
420 search.location = %(here)s/data/index
421
421
422 ########################################
422 ########################################
423 ### CHANNELSTREAM CONFIG ####
423 ### CHANNELSTREAM CONFIG ####
424 ########################################
424 ########################################
425 ## channelstream enables persistent connections and live notification
425 ## channelstream enables persistent connections and live notification
426 ## in the system. It's also used by the chat system
426 ## in the system. It's also used by the chat system
427 channelstream.enabled = false
427 channelstream.enabled = false
428
428
429 ## server address for channelstream server on the backend
429 ## server address for channelstream server on the backend
430 channelstream.server = 127.0.0.1:9800
430 channelstream.server = 127.0.0.1:9800
431
431
432 ## location of the channelstream server from outside world
432 ## location of the channelstream server from outside world
433 ## use ws:// for http or wss:// for https. This address needs to be handled
433 ## use ws:// for http or wss:// for https. This address needs to be handled
434 ## by external HTTP server such as Nginx or Apache
434 ## by external HTTP server such as Nginx or Apache
435 ## see nginx/apache configuration examples in our docs
435 ## see nginx/apache configuration examples in our docs
436 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
436 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
437 channelstream.secret = secret
437 channelstream.secret = secret
438 channelstream.history.location = %(here)s/channelstream_history
438 channelstream.history.location = %(here)s/channelstream_history
439
439
440 ## Internal application path that Javascript uses to connect into.
440 ## Internal application path that Javascript uses to connect into.
441 ## If you use proxy-prefix the prefix should be added before /_channelstream
441 ## If you use proxy-prefix the prefix should be added before /_channelstream
442 channelstream.proxy_path = /_channelstream
442 channelstream.proxy_path = /_channelstream
443
443
444
444
445 ###################################
445 ###################################
446 ## APPENLIGHT CONFIG ##
446 ## APPENLIGHT CONFIG ##
447 ###################################
447 ###################################
448
448
449 ## Appenlight is tailored to work with RhodeCode, see
449 ## Appenlight is tailored to work with RhodeCode, see
450 ## http://appenlight.com for details how to obtain an account
450 ## http://appenlight.com for details how to obtain an account
451
451
452 ## appenlight integration enabled
452 ## appenlight integration enabled
453 appenlight = false
453 appenlight = false
454
454
455 appenlight.server_url = https://api.appenlight.com
455 appenlight.server_url = https://api.appenlight.com
456 appenlight.api_key = YOUR_API_KEY
456 appenlight.api_key = YOUR_API_KEY
457 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
457 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
458
458
459 # used for JS client
459 # used for JS client
460 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
460 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
461
461
462 ## TWEAK AMOUNT OF INFO SENT HERE
462 ## TWEAK AMOUNT OF INFO SENT HERE
463
463
464 ## enables 404 error logging (default False)
464 ## enables 404 error logging (default False)
465 appenlight.report_404 = false
465 appenlight.report_404 = false
466
466
467 ## time in seconds after request is considered being slow (default 1)
467 ## time in seconds after request is considered being slow (default 1)
468 appenlight.slow_request_time = 1
468 appenlight.slow_request_time = 1
469
469
470 ## record slow requests in application
470 ## record slow requests in application
471 ## (needs to be enabled for slow datastore recording and time tracking)
471 ## (needs to be enabled for slow datastore recording and time tracking)
472 appenlight.slow_requests = true
472 appenlight.slow_requests = true
473
473
474 ## enable hooking to application loggers
474 ## enable hooking to application loggers
475 appenlight.logging = true
475 appenlight.logging = true
476
476
477 ## minimum log level for log capture
477 ## minimum log level for log capture
478 appenlight.logging.level = WARNING
478 appenlight.logging.level = WARNING
479
479
480 ## send logs only from erroneous/slow requests
480 ## send logs only from erroneous/slow requests
481 ## (saves API quota for intensive logging)
481 ## (saves API quota for intensive logging)
482 appenlight.logging_on_error = false
482 appenlight.logging_on_error = false
483
483
484 ## list of additonal keywords that should be grabbed from environ object
484 ## list of additonal keywords that should be grabbed from environ object
485 ## can be string with comma separated list of words in lowercase
485 ## can be string with comma separated list of words in lowercase
486 ## (by default client will always send following info:
486 ## (by default client will always send following info:
487 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
487 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
488 ## start with HTTP* this list be extended with additional keywords here
488 ## start with HTTP* this list be extended with additional keywords here
489 appenlight.environ_keys_whitelist =
489 appenlight.environ_keys_whitelist =
490
490
491 ## list of keywords that should be blanked from request object
491 ## list of keywords that should be blanked from request object
492 ## can be string with comma separated list of words in lowercase
492 ## can be string with comma separated list of words in lowercase
493 ## (by default client will always blank keys that contain following words
493 ## (by default client will always blank keys that contain following words
494 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
494 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
495 ## this list be extended with additional keywords set here
495 ## this list be extended with additional keywords set here
496 appenlight.request_keys_blacklist =
496 appenlight.request_keys_blacklist =
497
497
498 ## list of namespaces that should be ignores when gathering log entries
498 ## list of namespaces that should be ignores when gathering log entries
499 ## can be string with comma separated list of namespaces
499 ## can be string with comma separated list of namespaces
500 ## (by default the client ignores own entries: appenlight_client.client)
500 ## (by default the client ignores own entries: appenlight_client.client)
501 appenlight.log_namespace_blacklist =
501 appenlight.log_namespace_blacklist =
502
502
503
503
504 ################################################################################
504 ################################################################################
505 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
505 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
506 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
506 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
507 ## execute malicious code after an exception is raised. ##
507 ## execute malicious code after an exception is raised. ##
508 ################################################################################
508 ################################################################################
509 #set debug = false
509 #set debug = false
510
510
511
511
512 ##############
512 ##############
513 ## STYLING ##
513 ## STYLING ##
514 ##############
514 ##############
515 debug_style = true
515 debug_style = true
516
516
517 ###########################################
517 ###########################################
518 ### MAIN RHODECODE DATABASE CONFIG ###
518 ### MAIN RHODECODE DATABASE CONFIG ###
519 ###########################################
519 ###########################################
520 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
520 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
521 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
521 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
522 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
522 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
523 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
523 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
524
524
525 # see sqlalchemy docs for other advanced settings
525 # see sqlalchemy docs for other advanced settings
526
526
527 ## print the sql statements to output
527 ## print the sql statements to output
528 sqlalchemy.db1.echo = false
528 sqlalchemy.db1.echo = false
529 ## recycle the connections after this amount of seconds
529 ## recycle the connections after this amount of seconds
530 sqlalchemy.db1.pool_recycle = 3600
530 sqlalchemy.db1.pool_recycle = 3600
531 sqlalchemy.db1.convert_unicode = true
531 sqlalchemy.db1.convert_unicode = true
532
532
533 ## the number of connections to keep open inside the connection pool.
533 ## the number of connections to keep open inside the connection pool.
534 ## 0 indicates no limit
534 ## 0 indicates no limit
535 #sqlalchemy.db1.pool_size = 5
535 #sqlalchemy.db1.pool_size = 5
536
536
537 ## the number of connections to allow in connection pool "overflow", that is
537 ## the number of connections to allow in connection pool "overflow", that is
538 ## connections that can be opened above and beyond the pool_size setting,
538 ## connections that can be opened above and beyond the pool_size setting,
539 ## which defaults to five.
539 ## which defaults to five.
540 #sqlalchemy.db1.max_overflow = 10
540 #sqlalchemy.db1.max_overflow = 10
541
541
542
542
543 ##################
543 ##################
544 ### VCS CONFIG ###
544 ### VCS CONFIG ###
545 ##################
545 ##################
546 vcs.server.enable = true
546 vcs.server.enable = true
547 vcs.server = localhost:9900
547 vcs.server = localhost:9900
548
548
549 ## Web server connectivity protocol, responsible for web based VCS operatations
549 ## Web server connectivity protocol, responsible for web based VCS operatations
550 ## Available protocols are:
550 ## Available protocols are:
551 ## `http` - use http-rpc backend (default)
551 ## `http` - use http-rpc backend (default)
552 vcs.server.protocol = http
552 vcs.server.protocol = http
553
553
554 ## Push/Pull operations protocol, available options are:
554 ## Push/Pull operations protocol, available options are:
555 ## `http` - use http-rpc backend (default)
555 ## `http` - use http-rpc backend (default)
556 ##
556 ##
557 vcs.scm_app_implementation = http
557 vcs.scm_app_implementation = http
558
558
559 ## Push/Pull operations hooks protocol, available options are:
559 ## Push/Pull operations hooks protocol, available options are:
560 ## `http` - use http-rpc backend (default)
560 ## `http` - use http-rpc backend (default)
561 vcs.hooks.protocol = http
561 vcs.hooks.protocol = http
562
562
563 vcs.server.log_level = debug
563 vcs.server.log_level = debug
564 ## Start VCSServer with this instance as a subprocess, usefull for development
564 ## Start VCSServer with this instance as a subprocess, usefull for development
565 vcs.start_server = true
565 vcs.start_server = true
566
566
567 ## List of enabled VCS backends, available options are:
567 ## List of enabled VCS backends, available options are:
568 ## `hg` - mercurial
568 ## `hg` - mercurial
569 ## `git` - git
569 ## `git` - git
570 ## `svn` - subversion
570 ## `svn` - subversion
571 vcs.backends = hg, git, svn
571 vcs.backends = hg, git, svn
572
572
573 vcs.connection_timeout = 3600
573 vcs.connection_timeout = 3600
574 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
574 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
575 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
575 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
576 #vcs.svn.compatible_version = pre-1.8-compatible
576 #vcs.svn.compatible_version = pre-1.8-compatible
577
577
578
578
579 ############################################################
579 ############################################################
580 ### Subversion proxy support (mod_dav_svn) ###
580 ### Subversion proxy support (mod_dav_svn) ###
581 ### Maps RhodeCode repo groups into SVN paths for Apache ###
581 ### Maps RhodeCode repo groups into SVN paths for Apache ###
582 ############################################################
582 ############################################################
583 ## Enable or disable the config file generation.
583 ## Enable or disable the config file generation.
584 svn.proxy.generate_config = false
584 svn.proxy.generate_config = false
585 ## Generate config file with `SVNListParentPath` set to `On`.
585 ## Generate config file with `SVNListParentPath` set to `On`.
586 svn.proxy.list_parent_path = true
586 svn.proxy.list_parent_path = true
587 ## Set location and file name of generated config file.
587 ## Set location and file name of generated config file.
588 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
588 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
589 ## alternative mod_dav config template. This needs to be a mako template
589 ## alternative mod_dav config template. This needs to be a mako template
590 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
590 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
591 ## Used as a prefix to the `Location` block in the generated config file.
591 ## Used as a prefix to the `Location` block in the generated config file.
592 ## In most cases it should be set to `/`.
592 ## In most cases it should be set to `/`.
593 svn.proxy.location_root = /
593 svn.proxy.location_root = /
594 ## Command to reload the mod dav svn configuration on change.
594 ## Command to reload the mod dav svn configuration on change.
595 ## Example: `/etc/init.d/apache2 reload`
595 ## Example: `/etc/init.d/apache2 reload`
596 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
596 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
597 ## If the timeout expires before the reload command finishes, the command will
597 ## If the timeout expires before the reload command finishes, the command will
598 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
598 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
599 #svn.proxy.reload_timeout = 10
599 #svn.proxy.reload_timeout = 10
600
600
601 ############################################################
601 ############################################################
602 ### SSH Support Settings ###
602 ### SSH Support Settings ###
603 ############################################################
603 ############################################################
604
604
605 ## Defines if a custom authorized_keys file should be created and written on
605 ## Defines if a custom authorized_keys file should be created and written on
606 ## any change user ssh keys. Setting this to false also disables posibility
606 ## any change user ssh keys. Setting this to false also disables posibility
607 ## of adding SSH keys by users from web interface. Super admins can still
607 ## of adding SSH keys by users from web interface. Super admins can still
608 ## manage SSH Keys.
608 ## manage SSH Keys.
609 ssh.generate_authorized_keyfile = false
609 ssh.generate_authorized_keyfile = false
610
610
611 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
611 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
612 # ssh.authorized_keys_ssh_opts =
612 # ssh.authorized_keys_ssh_opts =
613
613
614 ## Path to the authrozied_keys file where the generate entries are placed.
614 ## Path to the authrozied_keys file where the generate entries are placed.
615 ## It is possible to have multiple key files specified in `sshd_config` e.g.
615 ## It is possible to have multiple key files specified in `sshd_config` e.g.
616 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
616 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
617 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
617 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
618
618
619 ## Command to execute the SSH wrapper. The binary is available in the
619 ## Command to execute the SSH wrapper. The binary is available in the
620 ## rhodecode installation directory.
620 ## rhodecode installation directory.
621 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
621 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
622 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
622 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
623
623
624 ## Allow shell when executing the ssh-wrapper command
624 ## Allow shell when executing the ssh-wrapper command
625 ssh.wrapper_cmd_allow_shell = false
625 ssh.wrapper_cmd_allow_shell = false
626
626
627 ## Enables logging, and detailed output send back to the client during SSH
627 ## Enables logging, and detailed output send back to the client during SSH
628 ## operations. Usefull for debugging, shouldn't be used in production.
628 ## operations. Usefull for debugging, shouldn't be used in production.
629 ssh.enable_debug_logging = true
629 ssh.enable_debug_logging = true
630
630
631 ## API KEY for user who has access to fetch other user permission information
632 ## most likely an super-admin account with some IP restrictions.
633 ssh.api_key =
634
635 ## API Host, the server address of RhodeCode instance that the api_key will
636 ## access
637 ssh.api_host = http://localhost
638
639 ## Paths to binary executable, by default they are the names, but we can
631 ## Paths to binary executable, by default they are the names, but we can
640 ## override them if we want to use a custom one
632 ## override them if we want to use a custom one
641 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
633 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
642 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
634 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
643 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
635 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
644
636
645
637
646 ## Dummy marker to add new entries after.
638 ## Dummy marker to add new entries after.
647 ## Add any custom entries below. Please don't remove.
639 ## Add any custom entries below. Please don't remove.
648 custom.conf = 1
640 custom.conf = 1
649
641
650
642
651 ################################
643 ################################
652 ### LOGGING CONFIGURATION ####
644 ### LOGGING CONFIGURATION ####
653 ################################
645 ################################
654 [loggers]
646 [loggers]
655 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
647 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
656
648
657 [handlers]
649 [handlers]
658 keys = console, console_sql
650 keys = console, console_sql
659
651
660 [formatters]
652 [formatters]
661 keys = generic, color_formatter, color_formatter_sql
653 keys = generic, color_formatter, color_formatter_sql
662
654
663 #############
655 #############
664 ## LOGGERS ##
656 ## LOGGERS ##
665 #############
657 #############
666 [logger_root]
658 [logger_root]
667 level = NOTSET
659 level = NOTSET
668 handlers = console
660 handlers = console
669
661
670 [logger_sqlalchemy]
662 [logger_sqlalchemy]
671 level = INFO
663 level = INFO
672 handlers = console_sql
664 handlers = console_sql
673 qualname = sqlalchemy.engine
665 qualname = sqlalchemy.engine
674 propagate = 0
666 propagate = 0
675
667
676 [logger_beaker]
668 [logger_beaker]
677 level = DEBUG
669 level = DEBUG
678 handlers =
670 handlers =
679 qualname = beaker.container
671 qualname = beaker.container
680 propagate = 1
672 propagate = 1
681
673
682 [logger_rhodecode]
674 [logger_rhodecode]
683 level = DEBUG
675 level = DEBUG
684 handlers =
676 handlers =
685 qualname = rhodecode
677 qualname = rhodecode
686 propagate = 1
678 propagate = 1
687
679
688 [logger_ssh_wrapper]
680 [logger_ssh_wrapper]
689 level = DEBUG
681 level = DEBUG
690 handlers =
682 handlers =
691 qualname = ssh_wrapper
683 qualname = ssh_wrapper
692 propagate = 1
684 propagate = 1
693
685
694
686
695 ##############
687 ##############
696 ## HANDLERS ##
688 ## HANDLERS ##
697 ##############
689 ##############
698
690
699 [handler_console]
691 [handler_console]
700 class = StreamHandler
692 class = StreamHandler
701 args = (sys.stderr, )
693 args = (sys.stderr, )
702 level = DEBUG
694 level = DEBUG
703 formatter = color_formatter
695 formatter = color_formatter
704
696
705 [handler_console_sql]
697 [handler_console_sql]
706 class = StreamHandler
698 class = StreamHandler
707 args = (sys.stderr, )
699 args = (sys.stderr, )
708 level = DEBUG
700 level = DEBUG
709 formatter = color_formatter_sql
701 formatter = color_formatter_sql
710
702
711 ################
703 ################
712 ## FORMATTERS ##
704 ## FORMATTERS ##
713 ################
705 ################
714
706
715 [formatter_generic]
707 [formatter_generic]
716 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
708 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
717 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
709 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
718 datefmt = %Y-%m-%d %H:%M:%S
710 datefmt = %Y-%m-%d %H:%M:%S
719
711
720 [formatter_color_formatter]
712 [formatter_color_formatter]
721 class = rhodecode.lib.logging_formatter.ColorFormatter
713 class = rhodecode.lib.logging_formatter.ColorFormatter
722 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
714 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
723 datefmt = %Y-%m-%d %H:%M:%S
715 datefmt = %Y-%m-%d %H:%M:%S
724
716
725 [formatter_color_formatter_sql]
717 [formatter_color_formatter_sql]
726 class = rhodecode.lib.logging_formatter.ColorFormatterSql
718 class = rhodecode.lib.logging_formatter.ColorFormatterSql
727 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
719 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
728 datefmt = %Y-%m-%d %H:%M:%S
720 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,698 +1,690 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 127.0.0.1
46 host = 127.0.0.1
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 #use = egg:waitress#main
54 #use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 #threads = 5
56 #threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 #max_request_body_size = 107374182400
58 #max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 #asyncore_use_poll = true
61 #asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 use = egg:gunicorn#main
69 use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 workers = 2
74 workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommended to be at 1
76 ## generally recommended to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 proc_name = rhodecode
79 proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 worker_class = sync
82 worker_class = sync
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 max_requests = 1000
87 max_requests = 1000
88 max_requests_jitter = 30
88 max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 timeout = 21600
91 timeout = 21600
92
92
93
93
94 ## prefix middleware for RhodeCode.
94 ## prefix middleware for RhodeCode.
95 ## recommended when using proxy setup.
95 ## recommended when using proxy setup.
96 ## allows to set RhodeCode under a prefix in server.
96 ## allows to set RhodeCode under a prefix in server.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
97 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
98 ## And set your prefix like: `prefix = /custom_prefix`
98 ## And set your prefix like: `prefix = /custom_prefix`
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
99 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
100 ## to make your cookies only work on prefix url
100 ## to make your cookies only work on prefix url
101 [filter:proxy-prefix]
101 [filter:proxy-prefix]
102 use = egg:PasteDeploy#prefix
102 use = egg:PasteDeploy#prefix
103 prefix = /
103 prefix = /
104
104
105 [app:main]
105 [app:main]
106 use = egg:rhodecode-enterprise-ce
106 use = egg:rhodecode-enterprise-ce
107
107
108 ## enable proxy prefix middleware, defined above
108 ## enable proxy prefix middleware, defined above
109 #filter-with = proxy-prefix
109 #filter-with = proxy-prefix
110
110
111 ## encryption key used to encrypt social plugin tokens,
111 ## encryption key used to encrypt social plugin tokens,
112 ## remote_urls with credentials etc, if not set it defaults to
112 ## remote_urls with credentials etc, if not set it defaults to
113 ## `beaker.session.secret`
113 ## `beaker.session.secret`
114 #rhodecode.encrypted_values.secret =
114 #rhodecode.encrypted_values.secret =
115
115
116 ## decryption strict mode (enabled by default). It controls if decryption raises
116 ## decryption strict mode (enabled by default). It controls if decryption raises
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
117 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
118 #rhodecode.encrypted_values.strict = false
118 #rhodecode.encrypted_values.strict = false
119
119
120 ## return gzipped responses from Rhodecode (static files/application)
120 ## return gzipped responses from Rhodecode (static files/application)
121 gzip_responses = false
121 gzip_responses = false
122
122
123 ## autogenerate javascript routes file on startup
123 ## autogenerate javascript routes file on startup
124 generate_js_files = false
124 generate_js_files = false
125
125
126 ## Optional Languages
126 ## Optional Languages
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
127 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
128 lang = en
128 lang = en
129
129
130 ## perform a full repository scan on each server start, this should be
130 ## perform a full repository scan on each server start, this should be
131 ## set to false after first startup, to allow faster server restarts.
131 ## set to false after first startup, to allow faster server restarts.
132 startup.import_repos = false
132 startup.import_repos = false
133
133
134 ## Uncomment and set this path to use archive download cache.
134 ## Uncomment and set this path to use archive download cache.
135 ## Once enabled, generated archives will be cached at this location
135 ## Once enabled, generated archives will be cached at this location
136 ## and served from the cache during subsequent requests for the same archive of
136 ## and served from the cache during subsequent requests for the same archive of
137 ## the repository.
137 ## the repository.
138 #archive_cache_dir = /tmp/tarballcache
138 #archive_cache_dir = /tmp/tarballcache
139
139
140 ## change this to unique ID for security
140 ## change this to unique ID for security
141 app_instance_uuid = rc-production
141 app_instance_uuid = rc-production
142
142
143 ## cut off limit for large diffs (size in bytes). If overall diff size on
143 ## cut off limit for large diffs (size in bytes). If overall diff size on
144 ## commit, or pull request exceeds this limit this diff will be displayed
144 ## commit, or pull request exceeds this limit this diff will be displayed
145 ## partially. E.g 512000 == 512Kb
145 ## partially. E.g 512000 == 512Kb
146 cut_off_limit_diff = 512000
146 cut_off_limit_diff = 512000
147
147
148 ## cut off limit for large files inside diffs (size in bytes). Each individual
148 ## cut off limit for large files inside diffs (size in bytes). Each individual
149 ## file inside diff which exceeds this limit will be displayed partially.
149 ## file inside diff which exceeds this limit will be displayed partially.
150 ## E.g 128000 == 128Kb
150 ## E.g 128000 == 128Kb
151 cut_off_limit_file = 128000
151 cut_off_limit_file = 128000
152
152
153 ## use cache version of scm repo everywhere
153 ## use cache version of scm repo everywhere
154 vcs_full_cache = true
154 vcs_full_cache = true
155
155
156 ## force https in RhodeCode, fixes https redirects, assumes it's always https
156 ## force https in RhodeCode, fixes https redirects, assumes it's always https
157 ## Normally this is controlled by proper http flags sent from http server
157 ## Normally this is controlled by proper http flags sent from http server
158 force_https = false
158 force_https = false
159
159
160 ## use Strict-Transport-Security headers
160 ## use Strict-Transport-Security headers
161 use_htsts = false
161 use_htsts = false
162
162
163 ## number of commits stats will parse on each iteration
163 ## number of commits stats will parse on each iteration
164 commit_parse_limit = 25
164 commit_parse_limit = 25
165
165
166 ## git rev filter option, --all is the default filter, if you need to
166 ## git rev filter option, --all is the default filter, if you need to
167 ## hide all refs in changelog switch this to --branches --tags
167 ## hide all refs in changelog switch this to --branches --tags
168 git_rev_filter = --branches --tags
168 git_rev_filter = --branches --tags
169
169
170 # Set to true if your repos are exposed using the dumb protocol
170 # Set to true if your repos are exposed using the dumb protocol
171 git_update_server_info = false
171 git_update_server_info = false
172
172
173 ## RSS/ATOM feed options
173 ## RSS/ATOM feed options
174 rss_cut_off_limit = 256000
174 rss_cut_off_limit = 256000
175 rss_items_per_page = 10
175 rss_items_per_page = 10
176 rss_include_diff = false
176 rss_include_diff = false
177
177
178 ## gist URL alias, used to create nicer urls for gist. This should be an
178 ## gist URL alias, used to create nicer urls for gist. This should be an
179 ## url that does rewrites to _admin/gists/{gistid}.
179 ## url that does rewrites to _admin/gists/{gistid}.
180 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
180 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
181 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
181 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
182 gist_alias_url =
182 gist_alias_url =
183
183
184 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
184 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
185 ## used for access.
185 ## used for access.
186 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
186 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
187 ## came from the the logged in user who own this authentication token.
187 ## came from the the logged in user who own this authentication token.
188 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
188 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
189 ## authentication token. Such view would be only accessible when used together
189 ## authentication token. Such view would be only accessible when used together
190 ## with this authentication token
190 ## with this authentication token
191 ##
191 ##
192 ## list of all views can be found under `/_admin/permissions/auth_token_access`
192 ## list of all views can be found under `/_admin/permissions/auth_token_access`
193 ## The list should be "," separated and on a single line.
193 ## The list should be "," separated and on a single line.
194 ##
194 ##
195 ## Most common views to enable:
195 ## Most common views to enable:
196 # RepoCommitsView:repo_commit_download
196 # RepoCommitsView:repo_commit_download
197 # RepoCommitsView:repo_commit_patch
197 # RepoCommitsView:repo_commit_patch
198 # RepoCommitsView:repo_commit_raw
198 # RepoCommitsView:repo_commit_raw
199 # RepoCommitsView:repo_commit_raw@TOKEN
199 # RepoCommitsView:repo_commit_raw@TOKEN
200 # RepoFilesView:repo_files_diff
200 # RepoFilesView:repo_files_diff
201 # RepoFilesView:repo_archivefile
201 # RepoFilesView:repo_archivefile
202 # RepoFilesView:repo_file_raw
202 # RepoFilesView:repo_file_raw
203 # GistView:*
203 # GistView:*
204 api_access_controllers_whitelist =
204 api_access_controllers_whitelist =
205
205
206 ## default encoding used to convert from and to unicode
206 ## default encoding used to convert from and to unicode
207 ## can be also a comma separated list of encoding in case of mixed encodings
207 ## can be also a comma separated list of encoding in case of mixed encodings
208 default_encoding = UTF-8
208 default_encoding = UTF-8
209
209
210 ## instance-id prefix
210 ## instance-id prefix
211 ## a prefix key for this instance used for cache invalidation when running
211 ## a prefix key for this instance used for cache invalidation when running
212 ## multiple instances of rhodecode, make sure it's globally unique for
212 ## multiple instances of rhodecode, make sure it's globally unique for
213 ## all running rhodecode instances. Leave empty if you don't use it
213 ## all running rhodecode instances. Leave empty if you don't use it
214 instance_id =
214 instance_id =
215
215
216 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
216 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
217 ## of an authentication plugin also if it is disabled by it's settings.
217 ## of an authentication plugin also if it is disabled by it's settings.
218 ## This could be useful if you are unable to log in to the system due to broken
218 ## This could be useful if you are unable to log in to the system due to broken
219 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
219 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
220 ## module to log in again and fix the settings.
220 ## module to log in again and fix the settings.
221 ##
221 ##
222 ## Available builtin plugin IDs (hash is part of the ID):
222 ## Available builtin plugin IDs (hash is part of the ID):
223 ## egg:rhodecode-enterprise-ce#rhodecode
223 ## egg:rhodecode-enterprise-ce#rhodecode
224 ## egg:rhodecode-enterprise-ce#pam
224 ## egg:rhodecode-enterprise-ce#pam
225 ## egg:rhodecode-enterprise-ce#ldap
225 ## egg:rhodecode-enterprise-ce#ldap
226 ## egg:rhodecode-enterprise-ce#jasig_cas
226 ## egg:rhodecode-enterprise-ce#jasig_cas
227 ## egg:rhodecode-enterprise-ce#headers
227 ## egg:rhodecode-enterprise-ce#headers
228 ## egg:rhodecode-enterprise-ce#crowd
228 ## egg:rhodecode-enterprise-ce#crowd
229 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
229 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
230
230
231 ## alternative return HTTP header for failed authentication. Default HTTP
231 ## alternative return HTTP header for failed authentication. Default HTTP
232 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
232 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
233 ## handling that causing a series of failed authentication calls.
233 ## handling that causing a series of failed authentication calls.
234 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
234 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
235 ## This will be served instead of default 401 on bad authnetication
235 ## This will be served instead of default 401 on bad authnetication
236 auth_ret_code =
236 auth_ret_code =
237
237
238 ## use special detection method when serving auth_ret_code, instead of serving
238 ## use special detection method when serving auth_ret_code, instead of serving
239 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
239 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
240 ## and then serve auth_ret_code to clients
240 ## and then serve auth_ret_code to clients
241 auth_ret_code_detection = false
241 auth_ret_code_detection = false
242
242
243 ## locking return code. When repository is locked return this HTTP code. 2XX
243 ## locking return code. When repository is locked return this HTTP code. 2XX
244 ## codes don't break the transactions while 4XX codes do
244 ## codes don't break the transactions while 4XX codes do
245 lock_ret_code = 423
245 lock_ret_code = 423
246
246
247 ## allows to change the repository location in settings page
247 ## allows to change the repository location in settings page
248 allow_repo_location_change = true
248 allow_repo_location_change = true
249
249
250 ## allows to setup custom hooks in settings page
250 ## allows to setup custom hooks in settings page
251 allow_custom_hooks_settings = true
251 allow_custom_hooks_settings = true
252
252
253 ## generated license token, goto license page in RhodeCode settings to obtain
253 ## generated license token, goto license page in RhodeCode settings to obtain
254 ## new token
254 ## new token
255 license_token =
255 license_token =
256
256
257 ## supervisor connection uri, for managing supervisor and logs.
257 ## supervisor connection uri, for managing supervisor and logs.
258 supervisor.uri =
258 supervisor.uri =
259 ## supervisord group name/id we only want this RC instance to handle
259 ## supervisord group name/id we only want this RC instance to handle
260 supervisor.group_id = prod
260 supervisor.group_id = prod
261
261
262 ## Display extended labs settings
262 ## Display extended labs settings
263 labs_settings_active = true
263 labs_settings_active = true
264
264
265 ####################################
265 ####################################
266 ### CELERY CONFIG ####
266 ### CELERY CONFIG ####
267 ####################################
267 ####################################
268 use_celery = false
268 use_celery = false
269 broker.host = localhost
269 broker.host = localhost
270 broker.vhost = rabbitmqhost
270 broker.vhost = rabbitmqhost
271 broker.port = 5672
271 broker.port = 5672
272 broker.user = rabbitmq
272 broker.user = rabbitmq
273 broker.password = qweqwe
273 broker.password = qweqwe
274
274
275 celery.imports = rhodecode.lib.celerylib.tasks
275 celery.imports = rhodecode.lib.celerylib.tasks
276
276
277 celery.result.backend = amqp
277 celery.result.backend = amqp
278 celery.result.dburi = amqp://
278 celery.result.dburi = amqp://
279 celery.result.serialier = json
279 celery.result.serialier = json
280
280
281 #celery.send.task.error.emails = true
281 #celery.send.task.error.emails = true
282 #celery.amqp.task.result.expires = 18000
282 #celery.amqp.task.result.expires = 18000
283
283
284 celeryd.concurrency = 2
284 celeryd.concurrency = 2
285 #celeryd.log.file = celeryd.log
285 #celeryd.log.file = celeryd.log
286 celeryd.log.level = debug
286 celeryd.log.level = debug
287 celeryd.max.tasks.per.child = 1
287 celeryd.max.tasks.per.child = 1
288
288
289 ## tasks will never be sent to the queue, but executed locally instead.
289 ## tasks will never be sent to the queue, but executed locally instead.
290 celery.always.eager = false
290 celery.always.eager = false
291
291
292 ####################################
292 ####################################
293 ### BEAKER CACHE ####
293 ### BEAKER CACHE ####
294 ####################################
294 ####################################
295 # default cache dir for templates. Putting this into a ramdisk
295 # default cache dir for templates. Putting this into a ramdisk
296 ## can boost performance, eg. %(here)s/data_ramdisk
296 ## can boost performance, eg. %(here)s/data_ramdisk
297 cache_dir = %(here)s/data
297 cache_dir = %(here)s/data
298
298
299 ## locking and default file storage for Beaker. Putting this into a ramdisk
299 ## locking and default file storage for Beaker. Putting this into a ramdisk
300 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
300 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
301 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
301 beaker.cache.data_dir = %(here)s/data/cache/beaker_data
302 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
302 beaker.cache.lock_dir = %(here)s/data/cache/beaker_lock
303
303
304 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
304 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
305
305
306 beaker.cache.super_short_term.type = memory
306 beaker.cache.super_short_term.type = memory
307 beaker.cache.super_short_term.expire = 10
307 beaker.cache.super_short_term.expire = 10
308 beaker.cache.super_short_term.key_length = 256
308 beaker.cache.super_short_term.key_length = 256
309
309
310 beaker.cache.short_term.type = memory
310 beaker.cache.short_term.type = memory
311 beaker.cache.short_term.expire = 60
311 beaker.cache.short_term.expire = 60
312 beaker.cache.short_term.key_length = 256
312 beaker.cache.short_term.key_length = 256
313
313
314 beaker.cache.long_term.type = memory
314 beaker.cache.long_term.type = memory
315 beaker.cache.long_term.expire = 36000
315 beaker.cache.long_term.expire = 36000
316 beaker.cache.long_term.key_length = 256
316 beaker.cache.long_term.key_length = 256
317
317
318 beaker.cache.sql_cache_short.type = memory
318 beaker.cache.sql_cache_short.type = memory
319 beaker.cache.sql_cache_short.expire = 10
319 beaker.cache.sql_cache_short.expire = 10
320 beaker.cache.sql_cache_short.key_length = 256
320 beaker.cache.sql_cache_short.key_length = 256
321
321
322 ## default is memory cache, configure only if required
322 ## default is memory cache, configure only if required
323 ## using multi-node or multi-worker setup
323 ## using multi-node or multi-worker setup
324 #beaker.cache.auth_plugins.type = ext:database
324 #beaker.cache.auth_plugins.type = ext:database
325 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
325 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
326 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
326 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
327 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
327 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
328 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
328 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
329 #beaker.cache.auth_plugins.sa.pool_size = 10
329 #beaker.cache.auth_plugins.sa.pool_size = 10
330 #beaker.cache.auth_plugins.sa.max_overflow = 0
330 #beaker.cache.auth_plugins.sa.max_overflow = 0
331
331
332 beaker.cache.repo_cache_long.type = memorylru_base
332 beaker.cache.repo_cache_long.type = memorylru_base
333 beaker.cache.repo_cache_long.max_items = 4096
333 beaker.cache.repo_cache_long.max_items = 4096
334 beaker.cache.repo_cache_long.expire = 2592000
334 beaker.cache.repo_cache_long.expire = 2592000
335
335
336 ## default is memorylru_base cache, configure only if required
336 ## default is memorylru_base cache, configure only if required
337 ## using multi-node or multi-worker setup
337 ## using multi-node or multi-worker setup
338 #beaker.cache.repo_cache_long.type = ext:memcached
338 #beaker.cache.repo_cache_long.type = ext:memcached
339 #beaker.cache.repo_cache_long.url = localhost:11211
339 #beaker.cache.repo_cache_long.url = localhost:11211
340 #beaker.cache.repo_cache_long.expire = 1209600
340 #beaker.cache.repo_cache_long.expire = 1209600
341 #beaker.cache.repo_cache_long.key_length = 256
341 #beaker.cache.repo_cache_long.key_length = 256
342
342
343 ####################################
343 ####################################
344 ### BEAKER SESSION ####
344 ### BEAKER SESSION ####
345 ####################################
345 ####################################
346
346
347 ## .session.type is type of storage options for the session, current allowed
347 ## .session.type is type of storage options for the session, current allowed
348 ## types are file, ext:memcached, ext:database, and memory (default).
348 ## types are file, ext:memcached, ext:database, and memory (default).
349 beaker.session.type = file
349 beaker.session.type = file
350 beaker.session.data_dir = %(here)s/data/sessions/data
350 beaker.session.data_dir = %(here)s/data/sessions/data
351
351
352 ## db based session, fast, and allows easy management over logged in users
352 ## db based session, fast, and allows easy management over logged in users
353 #beaker.session.type = ext:database
353 #beaker.session.type = ext:database
354 #beaker.session.table_name = db_session
354 #beaker.session.table_name = db_session
355 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
355 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
356 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
356 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
357 #beaker.session.sa.pool_recycle = 3600
357 #beaker.session.sa.pool_recycle = 3600
358 #beaker.session.sa.echo = false
358 #beaker.session.sa.echo = false
359
359
360 beaker.session.key = rhodecode
360 beaker.session.key = rhodecode
361 beaker.session.secret = production-rc-uytcxaz
361 beaker.session.secret = production-rc-uytcxaz
362 beaker.session.lock_dir = %(here)s/data/sessions/lock
362 beaker.session.lock_dir = %(here)s/data/sessions/lock
363
363
364 ## Secure encrypted cookie. Requires AES and AES python libraries
364 ## Secure encrypted cookie. Requires AES and AES python libraries
365 ## you must disable beaker.session.secret to use this
365 ## you must disable beaker.session.secret to use this
366 #beaker.session.encrypt_key = key_for_encryption
366 #beaker.session.encrypt_key = key_for_encryption
367 #beaker.session.validate_key = validation_key
367 #beaker.session.validate_key = validation_key
368
368
369 ## sets session as invalid(also logging out user) if it haven not been
369 ## sets session as invalid(also logging out user) if it haven not been
370 ## accessed for given amount of time in seconds
370 ## accessed for given amount of time in seconds
371 beaker.session.timeout = 2592000
371 beaker.session.timeout = 2592000
372 beaker.session.httponly = true
372 beaker.session.httponly = true
373 ## Path to use for the cookie. Set to prefix if you use prefix middleware
373 ## Path to use for the cookie. Set to prefix if you use prefix middleware
374 #beaker.session.cookie_path = /custom_prefix
374 #beaker.session.cookie_path = /custom_prefix
375
375
376 ## uncomment for https secure cookie
376 ## uncomment for https secure cookie
377 beaker.session.secure = false
377 beaker.session.secure = false
378
378
379 ## auto save the session to not to use .save()
379 ## auto save the session to not to use .save()
380 beaker.session.auto = false
380 beaker.session.auto = false
381
381
382 ## default cookie expiration time in seconds, set to `true` to set expire
382 ## default cookie expiration time in seconds, set to `true` to set expire
383 ## at browser close
383 ## at browser close
384 #beaker.session.cookie_expires = 3600
384 #beaker.session.cookie_expires = 3600
385
385
386 ###################################
386 ###################################
387 ## SEARCH INDEXING CONFIGURATION ##
387 ## SEARCH INDEXING CONFIGURATION ##
388 ###################################
388 ###################################
389 ## Full text search indexer is available in rhodecode-tools under
389 ## Full text search indexer is available in rhodecode-tools under
390 ## `rhodecode-tools index` command
390 ## `rhodecode-tools index` command
391
391
392 ## WHOOSH Backend, doesn't require additional services to run
392 ## WHOOSH Backend, doesn't require additional services to run
393 ## it works good with few dozen repos
393 ## it works good with few dozen repos
394 search.module = rhodecode.lib.index.whoosh
394 search.module = rhodecode.lib.index.whoosh
395 search.location = %(here)s/data/index
395 search.location = %(here)s/data/index
396
396
397 ########################################
397 ########################################
398 ### CHANNELSTREAM CONFIG ####
398 ### CHANNELSTREAM CONFIG ####
399 ########################################
399 ########################################
400 ## channelstream enables persistent connections and live notification
400 ## channelstream enables persistent connections and live notification
401 ## in the system. It's also used by the chat system
401 ## in the system. It's also used by the chat system
402 channelstream.enabled = false
402 channelstream.enabled = false
403
403
404 ## server address for channelstream server on the backend
404 ## server address for channelstream server on the backend
405 channelstream.server = 127.0.0.1:9800
405 channelstream.server = 127.0.0.1:9800
406
406
407 ## location of the channelstream server from outside world
407 ## location of the channelstream server from outside world
408 ## use ws:// for http or wss:// for https. This address needs to be handled
408 ## use ws:// for http or wss:// for https. This address needs to be handled
409 ## by external HTTP server such as Nginx or Apache
409 ## by external HTTP server such as Nginx or Apache
410 ## see nginx/apache configuration examples in our docs
410 ## see nginx/apache configuration examples in our docs
411 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
411 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
412 channelstream.secret = secret
412 channelstream.secret = secret
413 channelstream.history.location = %(here)s/channelstream_history
413 channelstream.history.location = %(here)s/channelstream_history
414
414
415 ## Internal application path that Javascript uses to connect into.
415 ## Internal application path that Javascript uses to connect into.
416 ## If you use proxy-prefix the prefix should be added before /_channelstream
416 ## If you use proxy-prefix the prefix should be added before /_channelstream
417 channelstream.proxy_path = /_channelstream
417 channelstream.proxy_path = /_channelstream
418
418
419
419
420 ###################################
420 ###################################
421 ## APPENLIGHT CONFIG ##
421 ## APPENLIGHT CONFIG ##
422 ###################################
422 ###################################
423
423
424 ## Appenlight is tailored to work with RhodeCode, see
424 ## Appenlight is tailored to work with RhodeCode, see
425 ## http://appenlight.com for details how to obtain an account
425 ## http://appenlight.com for details how to obtain an account
426
426
427 ## appenlight integration enabled
427 ## appenlight integration enabled
428 appenlight = false
428 appenlight = false
429
429
430 appenlight.server_url = https://api.appenlight.com
430 appenlight.server_url = https://api.appenlight.com
431 appenlight.api_key = YOUR_API_KEY
431 appenlight.api_key = YOUR_API_KEY
432 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
432 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
433
433
434 # used for JS client
434 # used for JS client
435 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
435 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
436
436
437 ## TWEAK AMOUNT OF INFO SENT HERE
437 ## TWEAK AMOUNT OF INFO SENT HERE
438
438
439 ## enables 404 error logging (default False)
439 ## enables 404 error logging (default False)
440 appenlight.report_404 = false
440 appenlight.report_404 = false
441
441
442 ## time in seconds after request is considered being slow (default 1)
442 ## time in seconds after request is considered being slow (default 1)
443 appenlight.slow_request_time = 1
443 appenlight.slow_request_time = 1
444
444
445 ## record slow requests in application
445 ## record slow requests in application
446 ## (needs to be enabled for slow datastore recording and time tracking)
446 ## (needs to be enabled for slow datastore recording and time tracking)
447 appenlight.slow_requests = true
447 appenlight.slow_requests = true
448
448
449 ## enable hooking to application loggers
449 ## enable hooking to application loggers
450 appenlight.logging = true
450 appenlight.logging = true
451
451
452 ## minimum log level for log capture
452 ## minimum log level for log capture
453 appenlight.logging.level = WARNING
453 appenlight.logging.level = WARNING
454
454
455 ## send logs only from erroneous/slow requests
455 ## send logs only from erroneous/slow requests
456 ## (saves API quota for intensive logging)
456 ## (saves API quota for intensive logging)
457 appenlight.logging_on_error = false
457 appenlight.logging_on_error = false
458
458
459 ## list of additonal keywords that should be grabbed from environ object
459 ## list of additonal keywords that should be grabbed from environ object
460 ## can be string with comma separated list of words in lowercase
460 ## can be string with comma separated list of words in lowercase
461 ## (by default client will always send following info:
461 ## (by default client will always send following info:
462 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
462 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
463 ## start with HTTP* this list be extended with additional keywords here
463 ## start with HTTP* this list be extended with additional keywords here
464 appenlight.environ_keys_whitelist =
464 appenlight.environ_keys_whitelist =
465
465
466 ## list of keywords that should be blanked from request object
466 ## list of keywords that should be blanked from request object
467 ## can be string with comma separated list of words in lowercase
467 ## can be string with comma separated list of words in lowercase
468 ## (by default client will always blank keys that contain following words
468 ## (by default client will always blank keys that contain following words
469 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
469 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
470 ## this list be extended with additional keywords set here
470 ## this list be extended with additional keywords set here
471 appenlight.request_keys_blacklist =
471 appenlight.request_keys_blacklist =
472
472
473 ## list of namespaces that should be ignores when gathering log entries
473 ## list of namespaces that should be ignores when gathering log entries
474 ## can be string with comma separated list of namespaces
474 ## can be string with comma separated list of namespaces
475 ## (by default the client ignores own entries: appenlight_client.client)
475 ## (by default the client ignores own entries: appenlight_client.client)
476 appenlight.log_namespace_blacklist =
476 appenlight.log_namespace_blacklist =
477
477
478
478
479 ################################################################################
479 ################################################################################
480 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
480 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
481 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
481 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
482 ## execute malicious code after an exception is raised. ##
482 ## execute malicious code after an exception is raised. ##
483 ################################################################################
483 ################################################################################
484 set debug = false
484 set debug = false
485
485
486
486
487 ###########################################
487 ###########################################
488 ### MAIN RHODECODE DATABASE CONFIG ###
488 ### MAIN RHODECODE DATABASE CONFIG ###
489 ###########################################
489 ###########################################
490 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
490 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
491 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
491 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
492 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
492 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
493 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
493 sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
494
494
495 # see sqlalchemy docs for other advanced settings
495 # see sqlalchemy docs for other advanced settings
496
496
497 ## print the sql statements to output
497 ## print the sql statements to output
498 sqlalchemy.db1.echo = false
498 sqlalchemy.db1.echo = false
499 ## recycle the connections after this amount of seconds
499 ## recycle the connections after this amount of seconds
500 sqlalchemy.db1.pool_recycle = 3600
500 sqlalchemy.db1.pool_recycle = 3600
501 sqlalchemy.db1.convert_unicode = true
501 sqlalchemy.db1.convert_unicode = true
502
502
503 ## the number of connections to keep open inside the connection pool.
503 ## the number of connections to keep open inside the connection pool.
504 ## 0 indicates no limit
504 ## 0 indicates no limit
505 #sqlalchemy.db1.pool_size = 5
505 #sqlalchemy.db1.pool_size = 5
506
506
507 ## the number of connections to allow in connection pool "overflow", that is
507 ## the number of connections to allow in connection pool "overflow", that is
508 ## connections that can be opened above and beyond the pool_size setting,
508 ## connections that can be opened above and beyond the pool_size setting,
509 ## which defaults to five.
509 ## which defaults to five.
510 #sqlalchemy.db1.max_overflow = 10
510 #sqlalchemy.db1.max_overflow = 10
511
511
512
512
513 ##################
513 ##################
514 ### VCS CONFIG ###
514 ### VCS CONFIG ###
515 ##################
515 ##################
516 vcs.server.enable = true
516 vcs.server.enable = true
517 vcs.server = localhost:9900
517 vcs.server = localhost:9900
518
518
519 ## Web server connectivity protocol, responsible for web based VCS operatations
519 ## Web server connectivity protocol, responsible for web based VCS operatations
520 ## Available protocols are:
520 ## Available protocols are:
521 ## `http` - use http-rpc backend (default)
521 ## `http` - use http-rpc backend (default)
522 vcs.server.protocol = http
522 vcs.server.protocol = http
523
523
524 ## Push/Pull operations protocol, available options are:
524 ## Push/Pull operations protocol, available options are:
525 ## `http` - use http-rpc backend (default)
525 ## `http` - use http-rpc backend (default)
526 ##
526 ##
527 vcs.scm_app_implementation = http
527 vcs.scm_app_implementation = http
528
528
529 ## Push/Pull operations hooks protocol, available options are:
529 ## Push/Pull operations hooks protocol, available options are:
530 ## `http` - use http-rpc backend (default)
530 ## `http` - use http-rpc backend (default)
531 vcs.hooks.protocol = http
531 vcs.hooks.protocol = http
532
532
533 vcs.server.log_level = info
533 vcs.server.log_level = info
534 ## Start VCSServer with this instance as a subprocess, usefull for development
534 ## Start VCSServer with this instance as a subprocess, usefull for development
535 vcs.start_server = false
535 vcs.start_server = false
536
536
537 ## List of enabled VCS backends, available options are:
537 ## List of enabled VCS backends, available options are:
538 ## `hg` - mercurial
538 ## `hg` - mercurial
539 ## `git` - git
539 ## `git` - git
540 ## `svn` - subversion
540 ## `svn` - subversion
541 vcs.backends = hg, git, svn
541 vcs.backends = hg, git, svn
542
542
543 vcs.connection_timeout = 3600
543 vcs.connection_timeout = 3600
544 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
544 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
545 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
545 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
546 #vcs.svn.compatible_version = pre-1.8-compatible
546 #vcs.svn.compatible_version = pre-1.8-compatible
547
547
548
548
549 ############################################################
549 ############################################################
550 ### Subversion proxy support (mod_dav_svn) ###
550 ### Subversion proxy support (mod_dav_svn) ###
551 ### Maps RhodeCode repo groups into SVN paths for Apache ###
551 ### Maps RhodeCode repo groups into SVN paths for Apache ###
552 ############################################################
552 ############################################################
553 ## Enable or disable the config file generation.
553 ## Enable or disable the config file generation.
554 svn.proxy.generate_config = false
554 svn.proxy.generate_config = false
555 ## Generate config file with `SVNListParentPath` set to `On`.
555 ## Generate config file with `SVNListParentPath` set to `On`.
556 svn.proxy.list_parent_path = true
556 svn.proxy.list_parent_path = true
557 ## Set location and file name of generated config file.
557 ## Set location and file name of generated config file.
558 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
558 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
559 ## alternative mod_dav config template. This needs to be a mako template
559 ## alternative mod_dav config template. This needs to be a mako template
560 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
560 #svn.proxy.config_template = ~/.rccontrol/enterprise-1/custom_svn_conf.mako
561 ## Used as a prefix to the `Location` block in the generated config file.
561 ## Used as a prefix to the `Location` block in the generated config file.
562 ## In most cases it should be set to `/`.
562 ## In most cases it should be set to `/`.
563 svn.proxy.location_root = /
563 svn.proxy.location_root = /
564 ## Command to reload the mod dav svn configuration on change.
564 ## Command to reload the mod dav svn configuration on change.
565 ## Example: `/etc/init.d/apache2 reload`
565 ## Example: `/etc/init.d/apache2 reload`
566 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
566 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
567 ## If the timeout expires before the reload command finishes, the command will
567 ## If the timeout expires before the reload command finishes, the command will
568 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
568 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
569 #svn.proxy.reload_timeout = 10
569 #svn.proxy.reload_timeout = 10
570
570
571 ############################################################
571 ############################################################
572 ### SSH Support Settings ###
572 ### SSH Support Settings ###
573 ############################################################
573 ############################################################
574
574
575 ## Defines if a custom authorized_keys file should be created and written on
575 ## Defines if a custom authorized_keys file should be created and written on
576 ## any change user ssh keys. Setting this to false also disables posibility
576 ## any change user ssh keys. Setting this to false also disables posibility
577 ## of adding SSH keys by users from web interface. Super admins can still
577 ## of adding SSH keys by users from web interface. Super admins can still
578 ## manage SSH Keys.
578 ## manage SSH Keys.
579 ssh.generate_authorized_keyfile = false
579 ssh.generate_authorized_keyfile = false
580
580
581 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
581 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
582 # ssh.authorized_keys_ssh_opts =
582 # ssh.authorized_keys_ssh_opts =
583
583
584 ## Path to the authrozied_keys file where the generate entries are placed.
584 ## Path to the authrozied_keys file where the generate entries are placed.
585 ## It is possible to have multiple key files specified in `sshd_config` e.g.
585 ## It is possible to have multiple key files specified in `sshd_config` e.g.
586 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
586 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
587 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
587 ssh.authorized_keys_file_path = ~/.ssh/authorized_keys_rhodecode
588
588
589 ## Command to execute the SSH wrapper. The binary is available in the
589 ## Command to execute the SSH wrapper. The binary is available in the
590 ## rhodecode installation directory.
590 ## rhodecode installation directory.
591 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
591 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
592 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
592 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
593
593
594 ## Allow shell when executing the ssh-wrapper command
594 ## Allow shell when executing the ssh-wrapper command
595 ssh.wrapper_cmd_allow_shell = false
595 ssh.wrapper_cmd_allow_shell = false
596
596
597 ## Enables logging, and detailed output send back to the client during SSH
597 ## Enables logging, and detailed output send back to the client during SSH
598 ## operations. Usefull for debugging, shouldn't be used in production.
598 ## operations. Usefull for debugging, shouldn't be used in production.
599 ssh.enable_debug_logging = false
599 ssh.enable_debug_logging = false
600
600
601 ## API KEY for user who has access to fetch other user permission information
602 ## most likely an super-admin account with some IP restrictions.
603 ssh.api_key =
604
605 ## API Host, the server address of RhodeCode instance that the api_key will
606 ## access
607 ssh.api_host = http://localhost
608
609 ## Paths to binary executable, by default they are the names, but we can
601 ## Paths to binary executable, by default they are the names, but we can
610 ## override them if we want to use a custom one
602 ## override them if we want to use a custom one
611 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
603 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
612 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
604 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
613 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
605 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
614
606
615
607
616 ## Dummy marker to add new entries after.
608 ## Dummy marker to add new entries after.
617 ## Add any custom entries below. Please don't remove.
609 ## Add any custom entries below. Please don't remove.
618 custom.conf = 1
610 custom.conf = 1
619
611
620
612
621 ################################
613 ################################
622 ### LOGGING CONFIGURATION ####
614 ### LOGGING CONFIGURATION ####
623 ################################
615 ################################
624 [loggers]
616 [loggers]
625 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
617 keys = root, sqlalchemy, beaker, rhodecode, ssh_wrapper
626
618
627 [handlers]
619 [handlers]
628 keys = console, console_sql
620 keys = console, console_sql
629
621
630 [formatters]
622 [formatters]
631 keys = generic, color_formatter, color_formatter_sql
623 keys = generic, color_formatter, color_formatter_sql
632
624
633 #############
625 #############
634 ## LOGGERS ##
626 ## LOGGERS ##
635 #############
627 #############
636 [logger_root]
628 [logger_root]
637 level = NOTSET
629 level = NOTSET
638 handlers = console
630 handlers = console
639
631
640 [logger_sqlalchemy]
632 [logger_sqlalchemy]
641 level = INFO
633 level = INFO
642 handlers = console_sql
634 handlers = console_sql
643 qualname = sqlalchemy.engine
635 qualname = sqlalchemy.engine
644 propagate = 0
636 propagate = 0
645
637
646 [logger_beaker]
638 [logger_beaker]
647 level = DEBUG
639 level = DEBUG
648 handlers =
640 handlers =
649 qualname = beaker.container
641 qualname = beaker.container
650 propagate = 1
642 propagate = 1
651
643
652 [logger_rhodecode]
644 [logger_rhodecode]
653 level = DEBUG
645 level = DEBUG
654 handlers =
646 handlers =
655 qualname = rhodecode
647 qualname = rhodecode
656 propagate = 1
648 propagate = 1
657
649
658 [logger_ssh_wrapper]
650 [logger_ssh_wrapper]
659 level = DEBUG
651 level = DEBUG
660 handlers =
652 handlers =
661 qualname = ssh_wrapper
653 qualname = ssh_wrapper
662 propagate = 1
654 propagate = 1
663
655
664
656
665 ##############
657 ##############
666 ## HANDLERS ##
658 ## HANDLERS ##
667 ##############
659 ##############
668
660
669 [handler_console]
661 [handler_console]
670 class = StreamHandler
662 class = StreamHandler
671 args = (sys.stderr, )
663 args = (sys.stderr, )
672 level = INFO
664 level = INFO
673 formatter = generic
665 formatter = generic
674
666
675 [handler_console_sql]
667 [handler_console_sql]
676 class = StreamHandler
668 class = StreamHandler
677 args = (sys.stderr, )
669 args = (sys.stderr, )
678 level = WARN
670 level = WARN
679 formatter = generic
671 formatter = generic
680
672
681 ################
673 ################
682 ## FORMATTERS ##
674 ## FORMATTERS ##
683 ################
675 ################
684
676
685 [formatter_generic]
677 [formatter_generic]
686 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
678 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
687 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
679 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
688 datefmt = %Y-%m-%d %H:%M:%S
680 datefmt = %Y-%m-%d %H:%M:%S
689
681
690 [formatter_color_formatter]
682 [formatter_color_formatter]
691 class = rhodecode.lib.logging_formatter.ColorFormatter
683 class = rhodecode.lib.logging_formatter.ColorFormatter
692 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
684 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
693 datefmt = %Y-%m-%d %H:%M:%S
685 datefmt = %Y-%m-%d %H:%M:%S
694
686
695 [formatter_color_formatter_sql]
687 [formatter_color_formatter_sql]
696 class = rhodecode.lib.logging_formatter.ColorFormatterSql
688 class = rhodecode.lib.logging_formatter.ColorFormatterSql
697 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
689 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
698 datefmt = %Y-%m-%d %H:%M:%S
690 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,70 +1,66 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from . import config_keys
23 from . import config_keys
24 from .events import SshKeyFileChangeEvent
24 from .events import SshKeyFileChangeEvent
25 from .subscribers import generate_ssh_authorized_keys_file_subscriber
25 from .subscribers import generate_ssh_authorized_keys_file_subscriber
26
26
27 from rhodecode.config.middleware import _bool_setting, _string_setting
27 from rhodecode.config.middleware import _bool_setting, _string_setting
28
28
29 log = logging.getLogger(__name__)
29 log = logging.getLogger(__name__)
30
30
31
31
32 def _sanitize_settings_and_apply_defaults(settings):
32 def _sanitize_settings_and_apply_defaults(settings):
33 """
33 """
34 Set defaults, convert to python types and validate settings.
34 Set defaults, convert to python types and validate settings.
35 """
35 """
36 _bool_setting(settings, config_keys.generate_authorized_keyfile, 'false')
36 _bool_setting(settings, config_keys.generate_authorized_keyfile, 'false')
37 _bool_setting(settings, config_keys.wrapper_allow_shell, 'false')
37 _bool_setting(settings, config_keys.wrapper_allow_shell, 'false')
38 _bool_setting(settings, config_keys.enable_debug_logging, 'false')
38 _bool_setting(settings, config_keys.enable_debug_logging, 'false')
39
39
40 _string_setting(settings, config_keys.authorized_keys_file_path,
40 _string_setting(settings, config_keys.authorized_keys_file_path,
41 '~/.ssh/authorized_keys_rhodecode',
41 '~/.ssh/authorized_keys_rhodecode',
42 lower=False)
42 lower=False)
43 _string_setting(settings, config_keys.wrapper_cmd, '',
43 _string_setting(settings, config_keys.wrapper_cmd, '',
44 lower=False)
44 lower=False)
45 _string_setting(settings, config_keys.authorized_keys_line_ssh_opts, '',
45 _string_setting(settings, config_keys.authorized_keys_line_ssh_opts, '',
46 lower=False)
46 lower=False)
47
47
48 _string_setting(settings, config_keys.ssh_api_key, '',
49 lower=False)
50 _string_setting(settings, config_keys.ssh_api_host, '',
51 lower=False)
52 _string_setting(settings, config_keys.ssh_hg_bin,
48 _string_setting(settings, config_keys.ssh_hg_bin,
53 '~/.rccontrol/vcsserver-1/profile/bin/hg',
49 '~/.rccontrol/vcsserver-1/profile/bin/hg',
54 lower=False)
50 lower=False)
55 _string_setting(settings, config_keys.ssh_git_bin,
51 _string_setting(settings, config_keys.ssh_git_bin,
56 '~/.rccontrol/vcsserver-1/profile/bin/git',
52 '~/.rccontrol/vcsserver-1/profile/bin/git',
57 lower=False)
53 lower=False)
58 _string_setting(settings, config_keys.ssh_svn_bin,
54 _string_setting(settings, config_keys.ssh_svn_bin,
59 '~/.rccontrol/vcsserver-1/profile/bin/svnserve',
55 '~/.rccontrol/vcsserver-1/profile/bin/svnserve',
60 lower=False)
56 lower=False)
61
57
62
58
63 def includeme(config):
59 def includeme(config):
64 settings = config.registry.settings
60 settings = config.registry.settings
65 _sanitize_settings_and_apply_defaults(settings)
61 _sanitize_settings_and_apply_defaults(settings)
66
62
67 # if we have enable generation of file, subscribe to event
63 # if we have enable generation of file, subscribe to event
68 if settings[config_keys.generate_authorized_keyfile]:
64 if settings[config_keys.generate_authorized_keyfile]:
69 config.add_subscriber(
65 config.add_subscriber(
70 generate_ssh_authorized_keys_file_subscriber, SshKeyFileChangeEvent)
66 generate_ssh_authorized_keys_file_subscriber, SshKeyFileChangeEvent)
@@ -1,36 +1,33 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 # Definition of setting keys used to configure this module. Defined here to
22 # Definition of setting keys used to configure this module. Defined here to
23 # avoid repetition of keys throughout the module.
23 # avoid repetition of keys throughout the module.
24 generate_authorized_keyfile = 'ssh.generate_authorized_keyfile'
24 generate_authorized_keyfile = 'ssh.generate_authorized_keyfile'
25 authorized_keys_file_path = 'ssh.authorized_keys_file_path'
25 authorized_keys_file_path = 'ssh.authorized_keys_file_path'
26 authorized_keys_line_ssh_opts = 'ssh.authorized_keys_ssh_opts'
26 authorized_keys_line_ssh_opts = 'ssh.authorized_keys_ssh_opts'
27 wrapper_cmd = 'ssh.wrapper_cmd'
27 wrapper_cmd = 'ssh.wrapper_cmd'
28 wrapper_allow_shell = 'ssh.wrapper_cmd_allow_shell'
28 wrapper_allow_shell = 'ssh.wrapper_cmd_allow_shell'
29 enable_debug_logging = 'ssh.enable_debug_logging'
29 enable_debug_logging = 'ssh.enable_debug_logging'
30
30
31 ssh_api_key = 'ssh.api_key'
32 ssh_api_host = 'ssh.api_host'
33
34 ssh_hg_bin = 'ssh.executable.hg'
31 ssh_hg_bin = 'ssh.executable.hg'
35 ssh_git_bin = 'ssh.executable.git'
32 ssh_git_bin = 'ssh.executable.git'
36 ssh_svn_bin = 'ssh.executable.svn'
33 ssh_svn_bin = 'ssh.executable.svn'
This diff has been collapsed as it changes many lines, (568 lines changed) Show them Hide them
@@ -1,607 +1,81 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import re
23 import sys
22 import sys
24 import json
25 import logging
23 import logging
26 import random
27 import signal
28 import tempfile
29 from subprocess import Popen, PIPE, check_output, CalledProcessError
30 import ConfigParser
31 import urllib2
32 import urlparse
33
24
34 import click
25 import click
35 import pyramid.paster
36
26
27 from pyramid.paster import bootstrap, setup_logging
28 from pyramid.request import Request
29
30 from .backends import SshWrapper
37
31
38 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
39
33
40
34
41 def setup_logging(ini_path, debug):
35 def setup_custom_logging(ini_path, debug):
42 if debug:
36 if debug:
43 # enabled rhodecode.ini controlled logging setup
37 # enabled rhodecode.ini controlled logging setup
44 pyramid.paster.setup_logging(ini_path)
38 setup_logging(ini_path)
45 else:
39 else:
46 # configure logging in a mode that doesn't print anything.
40 # configure logging in a mode that doesn't print anything.
47 # in case of regularly configured logging it gets printed out back
41 # in case of regularly configured logging it gets printed out back
48 # to the client doing an SSH command.
42 # to the client doing an SSH command.
49 logger = logging.getLogger('')
43 logger = logging.getLogger('')
50 null = logging.NullHandler()
44 null = logging.NullHandler()
51 # add the handler to the root logger
45 # add the handler to the root logger
52 logger.handlers = [null]
46 logger.handlers = [null]
53
47
54
48
55 class SubversionTunnelWrapper(object):
56 process = None
57
58 def __init__(self, timeout, repositories_root=None, svn_path=None):
59 self.timeout = timeout
60 self.stdin = sys.stdin
61 self.repositories_root = repositories_root
62 self.svn_path = svn_path or 'svnserve'
63 self.svn_conf_fd, self.svn_conf_path = tempfile.mkstemp()
64 self.hooks_env_fd, self.hooks_env_path = tempfile.mkstemp()
65 self.read_only = False
66 self.create_svn_config()
67
68 def create_svn_config(self):
69 content = (
70 '[general]\n'
71 'hooks-env = {}\n').format(self.hooks_env_path)
72 with os.fdopen(self.svn_conf_fd, 'w') as config_file:
73 config_file.write(content)
74
75 def create_hooks_env(self):
76 content = (
77 '[default]\n'
78 'LANG = en_US.UTF-8\n')
79 if self.read_only:
80 content += 'SSH_READ_ONLY = 1\n'
81 with os.fdopen(self.hooks_env_fd, 'w') as hooks_env_file:
82 hooks_env_file.write(content)
83
84 def remove_configs(self):
85 os.remove(self.svn_conf_path)
86 os.remove(self.hooks_env_path)
87
88 def start(self):
89 config = ['--config-file', self.svn_conf_path]
90 command = [self.svn_path, '-t'] + config
91 if self.repositories_root:
92 command.extend(['-r', self.repositories_root])
93 self.process = Popen(command, stdin=PIPE)
94
95 def sync(self):
96 while self.process.poll() is None:
97 next_byte = self.stdin.read(1)
98 if not next_byte:
99 break
100 self.process.stdin.write(next_byte)
101 self.remove_configs()
102
103 @property
104 def return_code(self):
105 return self.process.returncode
106
107 def get_first_client_response(self):
108 signal.signal(signal.SIGALRM, self.interrupt)
109 signal.alarm(self.timeout)
110 first_response = self._read_first_client_response()
111 signal.alarm(0)
112 return (
113 self._parse_first_client_response(first_response)
114 if first_response else None)
115
116 def patch_first_client_response(self, response, **kwargs):
117 self.create_hooks_env()
118 data = response.copy()
119 data.update(kwargs)
120 data['url'] = self._svn_string(data['url'])
121 data['ra_client'] = self._svn_string(data['ra_client'])
122 data['client'] = data['client'] or ''
123 buffer_ = (
124 "( {version} ( {capabilities} ) {url}{ra_client}"
125 "( {client}) ) ".format(**data))
126 self.process.stdin.write(buffer_)
127
128 def fail(self, message):
129 print(
130 "( failure ( ( 210005 {message} 0: 0 ) ) )".format(
131 message=self._svn_string(message)))
132 self.remove_configs()
133 self.process.kill()
134
135 def interrupt(self, signum, frame):
136 self.fail("Exited by timeout")
137
138 def _svn_string(self, str_):
139 if not str_:
140 return ''
141 return '{length}:{string} '.format(length=len(str_), string=str_)
142
143 def _read_first_client_response(self):
144 buffer_ = ""
145 brackets_stack = []
146 while True:
147 next_byte = self.stdin.read(1)
148 buffer_ += next_byte
149 if next_byte == "(":
150 brackets_stack.append(next_byte)
151 elif next_byte == ")":
152 brackets_stack.pop()
153 elif next_byte == " " and not brackets_stack:
154 break
155 return buffer_
156
157 def _parse_first_client_response(self, buffer_):
158 """
159 According to the Subversion RA protocol, the first request
160 should look like:
161
162 ( version:number ( cap:word ... ) url:string ? ra-client:string
163 ( ? client:string ) )
164
165 Please check https://svn.apache.org/repos/asf/subversion/trunk/
166 subversion/libsvn_ra_svn/protocol
167 """
168 version_re = r'(?P<version>\d+)'
169 capabilities_re = r'\(\s(?P<capabilities>[\w\d\-\ ]+)\s\)'
170 url_re = r'\d+\:(?P<url>[\W\w]+)'
171 ra_client_re = r'(\d+\:(?P<ra_client>[\W\w]+)\s)'
172 client_re = r'(\d+\:(?P<client>[\W\w]+)\s)*'
173 regex = re.compile(
174 r'^\(\s{version}\s{capabilities}\s{url}\s{ra_client}'
175 r'\(\s{client}\)\s\)\s*$'.format(
176 version=version_re, capabilities=capabilities_re,
177 url=url_re, ra_client=ra_client_re, client=client_re))
178 matcher = regex.match(buffer_)
179 return matcher.groupdict() if matcher else None
180
181
182 class RhodeCodeApiClient(object):
183 def __init__(self, api_key, api_host):
184 self.api_key = api_key
185 self.api_host = api_host
186
187 if not api_host:
188 raise ValueError('api_key:{} not defined'.format(api_key))
189 if not api_host:
190 raise ValueError('api_host:{} not defined '.format(api_host))
191
192 def request(self, method, args):
193 id_ = random.randrange(1, 9999)
194 args = {
195 'id': id_,
196 'api_key': self.api_key,
197 'method': method,
198 'args': args
199 }
200 host = '{host}/_admin/api'.format(host=self.api_host)
201
202 log.debug('Doing API call to %s method:%s', host, method)
203 req = urllib2.Request(
204 host,
205 data=json.dumps(args),
206 headers={'content-type': 'text/plain'})
207 ret = urllib2.urlopen(req)
208 raw_json = ret.read()
209 json_data = json.loads(raw_json)
210 id_ret = json_data['id']
211
212 if id_ret != id_:
213 raise Exception('something went wrong. '
214 'ID mismatch got %s, expected %s | %s'
215 % (id_ret, id_, raw_json))
216
217 result = json_data['result']
218 error = json_data['error']
219 return result, error
220
221 def get_user_permissions(self, user, user_id):
222 result, error = self.request('get_user', {'userid': int(user_id)})
223 if result is None and error:
224 raise Exception(
225 'User "%s" not found or another error happened: %s!' % (
226 user, error))
227 log.debug(
228 'Given User: `%s` Fetched User: `%s`', user, result.get('username'))
229 return result.get('permissions').get('repositories')
230
231 def invalidate_cache(self, repo_name):
232 log.debug('Invalidate cache for repo:%s', repo_name)
233 return self.request('invalidate_cache', {'repoid': repo_name})
234
235 def get_repo_store(self):
236 result, error = self.request('get_repo_store', {})
237 return result
238
239
240 class VcsServer(object):
241
242 def __init__(self, user, user_permissions, config):
243 self.user = user
244 self.user_permissions = user_permissions
245 self.config = config
246 self.repo_name = None
247 self.repo_mode = None
248 self.store = {}
249 self.ini_path = ''
250
251 def run(self):
252 raise NotImplementedError()
253
254 def get_root_store(self):
255 root_store = self.store['path']
256 if not root_store.endswith('/'):
257 # always append trailing slash
258 root_store = root_store + '/'
259 return root_store
260
261
262 class MercurialServer(VcsServer):
263 read_only = False
264
265 def __init__(self, store, ini_path, repo_name,
266 user, user_permissions, config):
267 super(MercurialServer, self).__init__(user, user_permissions, config)
268 self.store = store
269 self.repo_name = repo_name
270 self.ini_path = ini_path
271 self.hg_path = config.get('app:main', 'ssh.executable.hg')
272
273 def run(self):
274 if not self._check_permissions():
275 return 2, False
276
277 tip_before = self.tip()
278 exit_code = os.system(self.command)
279 tip_after = self.tip()
280 return exit_code, tip_before != tip_after
281
282 def tip(self):
283 root = self.get_root_store()
284 command = (
285 'cd {root}; {hg_path} -R {root}{repo_name} tip --template "{{node}}\n"'
286 ''.format(
287 root=root, hg_path=self.hg_path, repo_name=self.repo_name))
288 try:
289 tip = check_output(command, shell=True).strip()
290 except CalledProcessError:
291 tip = None
292 return tip
293
294 @property
295 def command(self):
296 root = self.get_root_store()
297 arguments = (
298 '--config hooks.pretxnchangegroup=\"false\"'
299 if self.read_only else '')
300
301 command = (
302 "cd {root}; {hg_path} -R {root}{repo_name} serve --stdio"
303 " {arguments}".format(
304 root=root, hg_path=self.hg_path, repo_name=self.repo_name,
305 arguments=arguments))
306 log.debug("Final CMD: %s", command)
307 return command
308
309 def _check_permissions(self):
310 permission = self.user_permissions.get(self.repo_name)
311 if permission is None or permission == 'repository.none':
312 log.error('repo not found or no permissions')
313 return False
314
315 elif permission in ['repository.admin', 'repository.write']:
316 log.info(
317 'Write Permissions for User "%s" granted to repo "%s"!' % (
318 self.user, self.repo_name))
319 else:
320 self.read_only = True
321 log.info(
322 'Only Read Only access for User "%s" granted to repo "%s"!',
323 self.user, self.repo_name)
324 return True
325
326
327 class GitServer(VcsServer):
328 def __init__(self, store, ini_path, repo_name, repo_mode,
329 user, user_permissions, config):
330 super(GitServer, self).__init__(user, user_permissions, config)
331 self.store = store
332 self.ini_path = ini_path
333 self.repo_name = repo_name
334 self.repo_mode = repo_mode
335 self.git_path = config.get('app:main', 'ssh.executable.git')
336
337 def run(self):
338 exit_code = self._check_permissions()
339 if exit_code:
340 return exit_code, False
341
342 self._update_environment()
343 exit_code = os.system(self.command)
344 return exit_code, self.repo_mode == "receive-pack"
345
346 @property
347 def command(self):
348 root = self.get_root_store()
349 command = "cd {root}; {git_path}-{mode} '{root}{repo_name}'".format(
350 root=root, git_path=self.git_path, mode=self.repo_mode,
351 repo_name=self.repo_name)
352 log.debug("Final CMD: %s", command)
353 return command
354
355 def _update_environment(self):
356 action = "push" if self.repo_mode == "receive-pack" else "pull",
357 scm_data = {
358 "ip": os.environ["SSH_CLIENT"].split()[0],
359 "username": self.user,
360 "action": action,
361 "repository": self.repo_name,
362 "scm": "git",
363 "config": self.ini_path,
364 "make_lock": None,
365 "locked_by": [None, None]
366 }
367 os.putenv("RC_SCM_DATA", json.dumps(scm_data))
368
369 def _check_permissions(self):
370 permission = self.user_permissions.get(self.repo_name)
371 log.debug(
372 'permission for %s on %s are: %s',
373 self.user, self.repo_name, permission)
374
375 if permission is None or permission == 'repository.none':
376 log.error('repo not found or no permissions')
377 return 2
378 elif permission in ['repository.admin', 'repository.write']:
379 log.info(
380 'Write Permissions for User "%s" granted to repo "%s"!',
381 self.user, self.repo_name)
382 elif (permission == 'repository.read' and
383 self.repo_mode == 'upload-pack'):
384 log.info(
385 'Only Read Only access for User "%s" granted to repo "%s"!',
386 self.user, self.repo_name)
387 elif (permission == 'repository.read'
388 and self.repo_mode == 'receive-pack'):
389 log.error(
390 'Only Read Only access for User "%s" granted to repo "%s"!'
391 ' Failing!', self.user, self.repo_name)
392 return -3
393 else:
394 log.error('Cannot properly fetch user permission. '
395 'Return value is: %s', permission)
396 return -2
397
398
399 class SubversionServer(VcsServer):
400
401 def __init__(self, store, ini_path,
402 user, user_permissions, config):
403 super(SubversionServer, self).__init__(user, user_permissions, config)
404 self.store = store
405 self.ini_path = ini_path
406 # this is set in .run() from input stream
407 self.repo_name = None
408 self.svn_path = config.get('app:main', 'ssh.executable.svn')
409
410 def run(self):
411 root = self.get_root_store()
412 log.debug("Using subversion binaries from '%s'", self.svn_path)
413
414 self.tunnel = SubversionTunnelWrapper(
415 timeout=self.timeout, repositories_root=root, svn_path=self.svn_path)
416 self.tunnel.start()
417 first_response = self.tunnel.get_first_client_response()
418 if not first_response:
419 self.tunnel.fail("Repository name cannot be extracted")
420 return 1, False
421
422 url_parts = urlparse.urlparse(first_response['url'])
423 self.repo_name = url_parts.path.strip('/')
424 if not self._check_permissions():
425 self.tunnel.fail("Not enough permissions")
426 return 1, False
427
428 self.tunnel.patch_first_client_response(first_response)
429 self.tunnel.sync()
430 return self.tunnel.return_code, False
431
432 @property
433 def timeout(self):
434 timeout = 30
435 return timeout
436
437 def _check_permissions(self):
438 permission = self.user_permissions.get(self.repo_name)
439
440 if permission in ['repository.admin', 'repository.write']:
441 self.tunnel.read_only = False
442 return True
443
444 elif permission == 'repository.read':
445 self.tunnel.read_only = True
446 return True
447
448 else:
449 self.tunnel.fail("Not enough permissions for repository {}".format(
450 self.repo_name))
451 return False
452
453
454 class SshWrapper(object):
455
456 def __init__(self, command, mode, user, user_id, shell, ini_path):
457 self.command = command
458 self.mode = mode
459 self.user = user
460 self.user_id = user_id
461 self.shell = shell
462 self.ini_path = ini_path
463
464 self.config = self.parse_config(ini_path)
465 api_key = self.config.get('app:main', 'ssh.api_key')
466 api_host = self.config.get('app:main', 'ssh.api_host')
467 self.api = RhodeCodeApiClient(api_key, api_host)
468
469 def parse_config(self, config):
470 parser = ConfigParser.ConfigParser()
471 parser.read(config)
472 return parser
473
474 def get_repo_details(self, mode):
475 type_ = mode if mode in ['svn', 'hg', 'git'] else None
476 mode = mode
477 name = None
478
479 hg_pattern = r'^hg\s+\-R\s+(\S+)\s+serve\s+\-\-stdio$'
480 hg_match = re.match(hg_pattern, self.command)
481 if hg_match is not None:
482 type_ = 'hg'
483 name = hg_match.group(1).strip('/')
484 return type_, name, mode
485
486 git_pattern = (
487 r'^git-(receive-pack|upload-pack)\s\'[/]?(\S+?)(|\.git)\'$')
488 git_match = re.match(git_pattern, self.command)
489 if git_match is not None:
490 type_ = 'git'
491 name = git_match.group(2).strip('/')
492 mode = git_match.group(1)
493 return type_, name, mode
494
495 svn_pattern = r'^svnserve -t'
496 svn_match = re.match(svn_pattern, self.command)
497 if svn_match is not None:
498 type_ = 'svn'
499 # Repo name should be extracted from the input stream
500 return type_, name, mode
501
502 return type_, name, mode
503
504 def serve(self, vcs, repo, mode, user, permissions):
505 store = self.api.get_repo_store()
506
507 log.debug(
508 'VCS detected:`%s` mode: `%s` repo: %s', vcs, mode, repo)
509
510 if vcs == 'hg':
511 server = MercurialServer(
512 store=store, ini_path=self.ini_path,
513 repo_name=repo, user=user,
514 user_permissions=permissions, config=self.config)
515 return server.run()
516
517 elif vcs == 'git':
518 server = GitServer(
519 store=store, ini_path=self.ini_path,
520 repo_name=repo, repo_mode=mode, user=user,
521 user_permissions=permissions, config=self.config)
522 return server.run()
523
524 elif vcs == 'svn':
525 server = SubversionServer(
526 store=store, ini_path=self.ini_path,
527 user=user,
528 user_permissions=permissions, config=self.config)
529 return server.run()
530
531 else:
532 raise Exception('Unrecognised VCS: {}'.format(vcs))
533
534 def wrap(self):
535 mode = self.mode
536 user = self.user
537 user_id = self.user_id
538 shell = self.shell
539
540 scm_detected, scm_repo, scm_mode = self.get_repo_details(mode)
541 log.debug(
542 'Mode: `%s` User: `%s:%s` Shell: `%s` SSH Command: `\"%s\"` '
543 'SCM_DETECTED: `%s` SCM Mode: `%s` SCM Repo: `%s`',
544 mode, user, user_id, shell, self.command,
545 scm_detected, scm_mode, scm_repo)
546
547 try:
548 permissions = self.api.get_user_permissions(user, user_id)
549 except Exception as e:
550 log.exception('Failed to fetch user permissions')
551 return 1
552
553 if shell and self.command is None:
554 log.info(
555 'Dropping to shell, no command given and shell is allowed')
556 os.execl('/bin/bash', '-l')
557 exit_code = 1
558
559 elif scm_detected:
560 try:
561 exit_code, is_updated = self.serve(
562 scm_detected, scm_repo, scm_mode, user, permissions)
563 if exit_code == 0 and is_updated:
564 self.api.invalidate_cache(scm_repo)
565 except Exception:
566 log.exception('Error occurred during execution of SshWrapper')
567 exit_code = -1
568
569 elif self.command is None and shell is False:
570 log.error('No Command given.')
571 exit_code = -1
572
573 else:
574 log.error(
575 'Unhandled Command: "%s" Aborting.', self.command)
576 exit_code = -1
577
578 return exit_code
579
580
581 @click.command()
49 @click.command()
582 @click.argument('ini_path', type=click.Path(exists=True))
50 @click.argument('ini_path', type=click.Path(exists=True))
583 @click.option(
51 @click.option(
584 '--mode', '-m', required=False, default='auto',
52 '--mode', '-m', required=False, default='auto',
585 type=click.Choice(['auto', 'vcs', 'git', 'hg', 'svn', 'test']),
53 type=click.Choice(['auto', 'vcs', 'git', 'hg', 'svn', 'test']),
586 help='mode of operation')
54 help='mode of operation')
587 @click.option('--user', help='Username for which the command will be executed')
55 @click.option('--user', help='Username for which the command will be executed')
588 @click.option('--user-id', help='User ID for which the command will be executed')
56 @click.option('--user-id', help='User ID for which the command will be executed')
57 @click.option('--key-id', help='ID of the key from the database')
589 @click.option('--shell', '-s', is_flag=True, help='Allow Shell')
58 @click.option('--shell', '-s', is_flag=True, help='Allow Shell')
590 @click.option('--debug', is_flag=True, help='Enabled detailed output logging')
59 @click.option('--debug', is_flag=True, help='Enabled detailed output logging')
591 def main(ini_path, mode, user, user_id, shell, debug):
60 def main(ini_path, mode, user, user_id, key_id, shell, debug):
592 setup_logging(ini_path, debug)
61 setup_custom_logging(ini_path, debug)
593
62
594 command = os.environ.get('SSH_ORIGINAL_COMMAND', '')
63 command = os.environ.get('SSH_ORIGINAL_COMMAND', '')
595 if not command and mode not in ['test']:
64 if not command and mode not in ['test']:
596 raise ValueError(
65 raise ValueError(
597 'Unable to fetch SSH_ORIGINAL_COMMAND from environment.'
66 'Unable to fetch SSH_ORIGINAL_COMMAND from environment.'
598 'Please make sure this is set and available during execution '
67 'Please make sure this is set and available during execution '
599 'of this script.')
68 'of this script.')
69 connection_info = os.environ.get('SSH_CONNECTION', '')
70 request = Request.blank('/', base_url='http://rhodecode-ssh-wrapper/')
71 with bootstrap(ini_path, request=request) as env:
72 try:
73 ssh_wrapper = SshWrapper(
74 command, connection_info, mode,
75 user, user_id, key_id, shell, ini_path)
76 except Exception:
77 log.exception('Failed to execute SshWrapper')
78 sys.exit(-5)
600
79
601 try:
80 return_code = ssh_wrapper.wrap()
602 ssh_wrapper = SshWrapper(command, mode, user, user_id, shell, ini_path)
81 sys.exit(return_code)
603 except Exception:
604 log.exception('Failed to execute SshWrapper')
605 sys.exit(-5)
606
607 sys.exit(ssh_wrapper.wrap()) No newline at end of file
@@ -1,196 +1,196 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import json
21 import json
22
22
23 import pytest
23 import pytest
24 from mock import Mock, patch, call
24 from mock import Mock, patch
25
25
26 from rhodecode.apps.ssh_support.lib.ssh_wrapper import GitServer
26 from rhodecode.apps.ssh_support.lib.backends.git import GitServer
27
27
28
28
29 @pytest.fixture
29 @pytest.fixture
30 def git_server():
30 def git_server():
31 return GitServerCreator()
31 return GitServerCreator()
32
32
33
33
34 class GitServerCreator(object):
34 class GitServerCreator(object):
35 root = '/tmp/repo/path/'
35 root = '/tmp/repo/path/'
36 git_path = '/usr/local/bin/'
36 git_path = '/usr/local/bin/'
37 config_data = {
37 config_data = {
38 'app:main': {
38 'app:main': {
39 'ssh.executable.git': git_path
39 'ssh.executable.git': git_path
40 }
40 }
41 }
41 }
42 repo_name = 'test_git'
42 repo_name = 'test_git'
43 repo_mode = 'receive-pack'
43 repo_mode = 'receive-pack'
44 user = 'vcs'
44 user = 'vcs'
45
45
46 def __init__(self):
46 def __init__(self):
47 def config_get(part, key):
47 def config_get(part, key):
48 return self.config_data.get(part, {}).get(key)
48 return self.config_data.get(part, {}).get(key)
49 self.config_mock = Mock()
49 self.config_mock = Mock()
50 self.config_mock.get = Mock(side_effect=config_get)
50 self.config_mock.get = Mock(side_effect=config_get)
51
51
52 def create(self, **kwargs):
52 def create(self, **kwargs):
53 parameters = {
53 parameters = {
54 'store': {'path': self.root},
54 'store': {'path': self.root},
55 'ini_path': '',
55 'ini_path': '',
56 'user': self.user,
56 'user': self.user,
57 'repo_name': self.repo_name,
57 'repo_name': self.repo_name,
58 'repo_mode': self.repo_mode,
58 'repo_mode': self.repo_mode,
59 'user_permissions': {
59 'user_permissions': {
60 self.repo_name: 'repo_admin'
60 self.repo_name: 'repo_admin'
61 },
61 },
62 'config': self.config_mock,
62 'config': self.config_mock,
63 }
63 }
64 parameters.update(kwargs)
64 parameters.update(kwargs)
65 server = GitServer(**parameters)
65 server = GitServer(**parameters)
66 return server
66 return server
67
67
68
68
69 class TestGitServer(object):
69 class TestGitServer(object):
70 def test_command(self, git_server):
70 def test_command(self, git_server):
71 server = git_server.create()
71 server = git_server.create()
72 server.read_only = False
72 server.read_only = False
73 expected_command = (
73 expected_command = (
74 'cd {root}; {git_path}-{repo_mode}'
74 'cd {root}; {git_path}-{repo_mode}'
75 ' \'{root}{repo_name}\''.format(
75 ' \'{root}{repo_name}\''.format(
76 root=git_server.root, git_path=git_server.git_path,
76 root=git_server.root, git_path=git_server.git_path,
77 repo_mode=git_server.repo_mode, repo_name=git_server.repo_name)
77 repo_mode=git_server.repo_mode, repo_name=git_server.repo_name)
78 )
78 )
79 assert expected_command == server.command
79 assert expected_command == server.command
80
80
81 def test_run_returns_exit_code_2_when_no_permissions(self, git_server, caplog):
81 def test_run_returns_exit_code_2_when_no_permissions(self, git_server, caplog):
82 server = git_server.create()
82 server = git_server.create()
83 with patch.object(server, '_check_permissions') as permissions_mock:
83 with patch.object(server, '_check_permissions') as permissions_mock:
84 with patch.object(server, '_update_environment'):
84 with patch.object(server, '_update_environment'):
85 permissions_mock.return_value = 2
85 permissions_mock.return_value = 2
86 exit_code = server.run()
86 exit_code = server.run()
87
87
88 assert exit_code == (2, False)
88 assert exit_code == (2, False)
89
89
90 def test_run_returns_executes_command(self, git_server, caplog):
90 def test_run_returns_executes_command(self, git_server, caplog):
91 server = git_server.create()
91 server = git_server.create()
92 with patch.object(server, '_check_permissions') as permissions_mock:
92 with patch.object(server, '_check_permissions') as permissions_mock:
93 with patch('os.system') as system_mock:
93 with patch('os.system') as system_mock:
94 with patch.object(server, '_update_environment') as (
94 with patch.object(server, '_update_environment') as (
95 update_mock):
95 update_mock):
96 permissions_mock.return_value = 0
96 permissions_mock.return_value = 0
97 system_mock.return_value = 0
97 system_mock.return_value = 0
98 exit_code = server.run()
98 exit_code = server.run()
99
99
100 system_mock.assert_called_once_with(server.command)
100 system_mock.assert_called_once_with(server.command)
101 update_mock.assert_called_once_with()
101 update_mock.assert_called_once_with()
102
102
103 assert exit_code == (0, True)
103 assert exit_code == (0, True)
104
104
105 @pytest.mark.parametrize(
105 @pytest.mark.parametrize(
106 'repo_mode, action', [
106 'repo_mode, action', [
107 ['receive-pack', 'push'],
107 ['receive-pack', 'push'],
108 ['upload-pack', 'pull']
108 ['upload-pack', 'pull']
109 ])
109 ])
110 def test_update_environment(self, git_server, repo_mode, action):
110 def test_update_environment(self, git_server, repo_mode, action):
111 server = git_server.create(repo_mode=repo_mode)
111 server = git_server.create(repo_mode=repo_mode)
112 with patch('os.environ', {'SSH_CLIENT': '10.10.10.10 b'}):
112 with patch('os.environ', {'SSH_CLIENT': '10.10.10.10 b'}):
113 with patch('os.putenv') as putenv_mock:
113 with patch('os.putenv') as putenv_mock:
114 server._update_environment()
114 server._update_environment()
115
115
116 expected_data = {
116 expected_data = {
117 "username": git_server.user,
117 "username": git_server.user,
118 "scm": "git",
118 "scm": "git",
119 "repository": git_server.repo_name,
119 "repository": git_server.repo_name,
120 "make_lock": None,
120 "make_lock": None,
121 "action": [action],
121 "action": [action],
122 "ip": "10.10.10.10",
122 "ip": "10.10.10.10",
123 "locked_by": [None, None],
123 "locked_by": [None, None],
124 "config": ""
124 "config": ""
125 }
125 }
126 args, kwargs = putenv_mock.call_args
126 args, kwargs = putenv_mock.call_args
127 assert json.loads(args[1]) == expected_data
127 assert json.loads(args[1]) == expected_data
128
128
129
129
130 class TestGitServerCheckPermissions(object):
130 class TestGitServerCheckPermissions(object):
131 def test_returns_2_when_no_permissions_found(self, git_server, caplog):
131 def test_returns_2_when_no_permissions_found(self, git_server, caplog):
132 user_permissions = {}
132 user_permissions = {}
133 server = git_server.create(user_permissions=user_permissions)
133 server = git_server.create(user_permissions=user_permissions)
134 result = server._check_permissions()
134 result = server._check_permissions()
135 assert result == 2
135 assert result == 2
136
136
137 log_msg = 'permission for vcs on test_git are: None'
137 log_msg = 'permission for vcs on test_git are: None'
138 assert log_msg in [t[2] for t in caplog.record_tuples]
138 assert log_msg in [t[2] for t in caplog.record_tuples]
139
139
140 def test_returns_2_when_no_permissions(self, git_server, caplog):
140 def test_returns_2_when_no_permissions(self, git_server, caplog):
141 user_permissions = {git_server.repo_name: 'repository.none'}
141 user_permissions = {git_server.repo_name: 'repository.none'}
142 server = git_server.create(user_permissions=user_permissions)
142 server = git_server.create(user_permissions=user_permissions)
143 result = server._check_permissions()
143 result = server._check_permissions()
144 assert result == 2
144 assert result == 2
145
145
146 log_msg = 'repo not found or no permissions'
146 log_msg = 'repo not found or no permissions'
147 assert log_msg in [t[2] for t in caplog.record_tuples]
147 assert log_msg in [t[2] for t in caplog.record_tuples]
148
148
149 @pytest.mark.parametrize(
149 @pytest.mark.parametrize(
150 'permission', ['repository.admin', 'repository.write'])
150 'permission', ['repository.admin', 'repository.write'])
151 def test_access_allowed_when_user_has_write_permissions(
151 def test_access_allowed_when_user_has_write_permissions(
152 self, git_server, permission, caplog):
152 self, git_server, permission, caplog):
153 user_permissions = {git_server.repo_name: permission}
153 user_permissions = {git_server.repo_name: permission}
154 server = git_server.create(user_permissions=user_permissions)
154 server = git_server.create(user_permissions=user_permissions)
155 result = server._check_permissions()
155 result = server._check_permissions()
156 assert result is None
156 assert result is None
157
157
158 log_msg = 'Write Permissions for User "%s" granted to repo "%s"!' % (
158 log_msg = 'Write Permissions for User "%s" granted to repo "%s"!' % (
159 git_server.user, git_server.repo_name)
159 git_server.user, git_server.repo_name)
160 assert log_msg in [t[2] for t in caplog.record_tuples]
160 assert log_msg in [t[2] for t in caplog.record_tuples]
161
161
162 def test_write_access_is_not_allowed_when_user_has_read_permission(
162 def test_write_access_is_not_allowed_when_user_has_read_permission(
163 self, git_server, caplog):
163 self, git_server, caplog):
164 user_permissions = {git_server.repo_name: 'repository.read'}
164 user_permissions = {git_server.repo_name: 'repository.read'}
165 server = git_server.create(
165 server = git_server.create(
166 user_permissions=user_permissions, repo_mode='receive-pack')
166 user_permissions=user_permissions, repo_mode='receive-pack')
167 result = server._check_permissions()
167 result = server._check_permissions()
168 assert result == -3
168 assert result == -3
169
169
170 log_msg = 'Only Read Only access for User "%s" granted to repo "%s"! Failing!' % (
170 log_msg = 'Only Read Only access for User "%s" granted to repo "%s"! Failing!' % (
171 git_server.user, git_server.repo_name)
171 git_server.user, git_server.repo_name)
172 assert log_msg in [t[2] for t in caplog.record_tuples]
172 assert log_msg in [t[2] for t in caplog.record_tuples]
173
173
174 def test_read_access_allowed_when_user_has_read_permission(
174 def test_read_access_allowed_when_user_has_read_permission(
175 self, git_server, caplog):
175 self, git_server, caplog):
176 user_permissions = {git_server.repo_name: 'repository.read'}
176 user_permissions = {git_server.repo_name: 'repository.read'}
177 server = git_server.create(
177 server = git_server.create(
178 user_permissions=user_permissions, repo_mode='upload-pack')
178 user_permissions=user_permissions, repo_mode='upload-pack')
179 result = server._check_permissions()
179 result = server._check_permissions()
180 assert result is None
180 assert result is None
181
181
182 log_msg = 'Only Read Only access for User "%s" granted to repo "%s"!' % (
182 log_msg = 'Only Read Only access for User "%s" granted to repo "%s"!' % (
183 git_server.user, git_server.repo_name)
183 git_server.user, git_server.repo_name)
184 assert log_msg in [t[2] for t in caplog.record_tuples]
184 assert log_msg in [t[2] for t in caplog.record_tuples]
185
185
186 def test_returns_error_when_permission_not_recognised(
186 def test_returns_error_when_permission_not_recognised(
187 self, git_server, caplog):
187 self, git_server, caplog):
188 user_permissions = {git_server.repo_name: 'repository.whatever'}
188 user_permissions = {git_server.repo_name: 'repository.whatever'}
189 server = git_server.create(
189 server = git_server.create(
190 user_permissions=user_permissions, repo_mode='upload-pack')
190 user_permissions=user_permissions, repo_mode='upload-pack')
191 result = server._check_permissions()
191 result = server._check_permissions()
192 assert result == -2
192 assert result == -2
193
193
194 log_msg = 'Cannot properly fetch user permission. ' \
194 log_msg = 'Cannot properly fetch user permission. ' \
195 'Return value is: repository.whatever'
195 'Return value is: repository.whatever'
196 assert log_msg in [t[2] for t in caplog.record_tuples] No newline at end of file
196 assert log_msg in [t[2] for t in caplog.record_tuples]
@@ -1,146 +1,146 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22 from mock import Mock, patch, call
22 from mock import Mock, patch
23
23
24 from rhodecode.apps.ssh_support.lib.ssh_wrapper import MercurialServer
24 from rhodecode.apps.ssh_support.lib.backends.hg import MercurialServer
25
25
26
26
27 @pytest.fixture
27 @pytest.fixture
28 def hg_server():
28 def hg_server():
29 return MercurialServerCreator()
29 return MercurialServerCreator()
30
30
31
31
32 class MercurialServerCreator(object):
32 class MercurialServerCreator(object):
33 root = '/tmp/repo/path/'
33 root = '/tmp/repo/path/'
34 hg_path = '/usr/local/bin/hg'
34 hg_path = '/usr/local/bin/hg'
35
35
36 config_data = {
36 config_data = {
37 'app:main': {
37 'app:main': {
38 'ssh.executable.hg': hg_path
38 'ssh.executable.hg': hg_path
39 }
39 }
40 }
40 }
41 repo_name = 'test_hg'
41 repo_name = 'test_hg'
42 user = 'vcs'
42 user = 'vcs'
43
43
44 def __init__(self):
44 def __init__(self):
45 def config_get(part, key):
45 def config_get(part, key):
46 return self.config_data.get(part, {}).get(key)
46 return self.config_data.get(part, {}).get(key)
47 self.config_mock = Mock()
47 self.config_mock = Mock()
48 self.config_mock.get = Mock(side_effect=config_get)
48 self.config_mock.get = Mock(side_effect=config_get)
49
49
50 def create(self, **kwargs):
50 def create(self, **kwargs):
51 parameters = {
51 parameters = {
52 'store': {'path': self.root},
52 'store': {'path': self.root},
53 'ini_path': '',
53 'ini_path': '',
54 'user': self.user,
54 'user': self.user,
55 'repo_name': self.repo_name,
55 'repo_name': self.repo_name,
56 'user_permissions': {
56 'user_permissions': {
57 'test_hg': 'repo_admin'
57 'test_hg': 'repo_admin'
58 },
58 },
59 'config': self.config_mock,
59 'config': self.config_mock,
60 }
60 }
61 parameters.update(kwargs)
61 parameters.update(kwargs)
62 server = MercurialServer(**parameters)
62 server = MercurialServer(**parameters)
63 return server
63 return server
64
64
65
65
66 class TestMercurialServer(object):
66 class TestMercurialServer(object):
67 def test_read_only_command(self, hg_server):
67 def test_read_only_command(self, hg_server):
68 server = hg_server.create()
68 server = hg_server.create()
69 server.read_only = True
69 server.read_only = True
70 expected_command = (
70 expected_command = (
71 'cd {root}; {hg_path} -R {root}{repo_name} serve --stdio'
71 'cd {root}; {hg_path} -R {root}{repo_name} serve --stdio'
72 ' --config hooks.pretxnchangegroup="false"'.format(
72 ' --config hooks.pretxnchangegroup="false"'.format(
73 root=hg_server.root, hg_path=hg_server.hg_path,
73 root=hg_server.root, hg_path=hg_server.hg_path,
74 repo_name=hg_server.repo_name)
74 repo_name=hg_server.repo_name)
75 )
75 )
76 assert expected_command == server.command
76 assert expected_command == server.command
77
77
78 def test_normal_command(self, hg_server):
78 def test_normal_command(self, hg_server):
79 server = hg_server.create()
79 server = hg_server.create()
80 server.read_only = False
80 server.read_only = False
81 expected_command = (
81 expected_command = (
82 'cd {root}; {hg_path} -R {root}{repo_name} serve --stdio '.format(
82 'cd {root}; {hg_path} -R {root}{repo_name} serve --stdio '.format(
83 root=hg_server.root, hg_path=hg_server.hg_path,
83 root=hg_server.root, hg_path=hg_server.hg_path,
84 repo_name=hg_server.repo_name)
84 repo_name=hg_server.repo_name)
85 )
85 )
86 assert expected_command == server.command
86 assert expected_command == server.command
87
87
88 def test_access_rejected_when_permissions_are_not_found(self, hg_server, caplog):
88 def test_access_rejected_when_permissions_are_not_found(self, hg_server, caplog):
89 user_permissions = {}
89 user_permissions = {}
90 server = hg_server.create(user_permissions=user_permissions)
90 server = hg_server.create(user_permissions=user_permissions)
91 result = server._check_permissions()
91 result = server._check_permissions()
92 assert result is False
92 assert result is False
93
93
94 log_msg = 'repo not found or no permissions'
94 log_msg = 'repo not found or no permissions'
95 assert log_msg in [t[2] for t in caplog.record_tuples]
95 assert log_msg in [t[2] for t in caplog.record_tuples]
96
96
97 def test_access_rejected_when_no_permissions(self, hg_server, caplog):
97 def test_access_rejected_when_no_permissions(self, hg_server, caplog):
98 user_permissions = {hg_server.repo_name: 'repository.none'}
98 user_permissions = {hg_server.repo_name: 'repository.none'}
99 server = hg_server.create(user_permissions=user_permissions)
99 server = hg_server.create(user_permissions=user_permissions)
100 result = server._check_permissions()
100 result = server._check_permissions()
101 assert result is False
101 assert result is False
102
102
103 log_msg = 'repo not found or no permissions'
103 log_msg = 'repo not found or no permissions'
104 assert log_msg in [t[2] for t in caplog.record_tuples]
104 assert log_msg in [t[2] for t in caplog.record_tuples]
105
105
106 @pytest.mark.parametrize(
106 @pytest.mark.parametrize(
107 'permission', ['repository.admin', 'repository.write'])
107 'permission', ['repository.admin', 'repository.write'])
108 def test_access_allowed_when_user_has_write_permissions(
108 def test_access_allowed_when_user_has_write_permissions(
109 self, hg_server, permission, caplog):
109 self, hg_server, permission, caplog):
110 user_permissions = {hg_server.repo_name: permission}
110 user_permissions = {hg_server.repo_name: permission}
111 server = hg_server.create(user_permissions=user_permissions)
111 server = hg_server.create(user_permissions=user_permissions)
112 result = server._check_permissions()
112 result = server._check_permissions()
113 assert result is True
113 assert result is True
114
114
115 assert server.read_only is False
115 assert server.read_only is False
116 log_msg = 'Write Permissions for User "vcs" granted to repo "test_hg"!'
116 log_msg = 'Write Permissions for User "vcs" granted to repo "test_hg"!'
117 assert log_msg in [t[2] for t in caplog.record_tuples]
117 assert log_msg in [t[2] for t in caplog.record_tuples]
118
118
119 def test_access_allowed_when_user_has_read_permissions(self, hg_server, caplog):
119 def test_access_allowed_when_user_has_read_permissions(self, hg_server, caplog):
120 user_permissions = {hg_server.repo_name: 'repository.read'}
120 user_permissions = {hg_server.repo_name: 'repository.read'}
121 server = hg_server.create(user_permissions=user_permissions)
121 server = hg_server.create(user_permissions=user_permissions)
122 result = server._check_permissions()
122 result = server._check_permissions()
123 assert result is True
123 assert result is True
124
124
125 assert server.read_only is True
125 assert server.read_only is True
126 log_msg = 'Only Read Only access for User "%s" granted to repo "%s"!' % (
126 log_msg = 'Only Read Only access for User "%s" granted to repo "%s"!' % (
127 hg_server.user, hg_server.repo_name)
127 hg_server.user, hg_server.repo_name)
128 assert log_msg in [t[2] for t in caplog.record_tuples]
128 assert log_msg in [t[2] for t in caplog.record_tuples]
129
129
130 def test_run_returns_exit_code_2_when_no_permissions(self, hg_server, caplog):
130 def test_run_returns_exit_code_2_when_no_permissions(self, hg_server, caplog):
131 server = hg_server.create()
131 server = hg_server.create()
132 with patch.object(server, '_check_permissions') as permissions_mock:
132 with patch.object(server, '_check_permissions') as permissions_mock:
133 permissions_mock.return_value = False
133 permissions_mock.return_value = False
134 exit_code = server.run()
134 exit_code = server.run()
135 assert exit_code == (2, False)
135 assert exit_code == (2, False)
136
136
137 def test_run_returns_executes_command(self, hg_server, caplog):
137 def test_run_returns_executes_command(self, hg_server, caplog):
138 server = hg_server.create()
138 server = hg_server.create()
139 with patch.object(server, '_check_permissions') as permissions_mock:
139 with patch.object(server, '_check_permissions') as permissions_mock:
140 with patch('os.system') as system_mock:
140 with patch('os.system') as system_mock:
141 permissions_mock.return_value = True
141 permissions_mock.return_value = True
142 system_mock.return_value = 0
142 system_mock.return_value = 0
143 exit_code = server.run()
143 exit_code = server.run()
144
144
145 system_mock.assert_called_once_with(server.command)
145 system_mock.assert_called_once_with(server.command)
146 assert exit_code == (0, False)
146 assert exit_code == (0, False)
@@ -1,136 +1,136 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22 from mock import Mock, patch, call
22 from mock import Mock, patch
23
23
24 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SubversionServer
24 from rhodecode.apps.ssh_support.lib.backends.svn import SubversionServer
25
25
26
26
27 @pytest.fixture
27 @pytest.fixture
28 def svn_server():
28 def svn_server():
29 return SubversionServerCreator()
29 return SubversionServerCreator()
30
30
31
31
32 class SubversionServerCreator(object):
32 class SubversionServerCreator(object):
33 root = '/tmp/repo/path/'
33 root = '/tmp/repo/path/'
34 svn_path = '/usr/local/bin/svnserve'
34 svn_path = '/usr/local/bin/svnserve'
35 config_data = {
35 config_data = {
36 'app:main': {
36 'app:main': {
37 'ssh.executable.svn': svn_path
37 'ssh.executable.svn': svn_path
38 }
38 }
39 }
39 }
40 repo_name = 'test-svn'
40 repo_name = 'test-svn'
41 user = 'vcs'
41 user = 'vcs'
42
42
43 def __init__(self):
43 def __init__(self):
44 def config_get(part, key):
44 def config_get(part, key):
45 return self.config_data.get(part, {}).get(key)
45 return self.config_data.get(part, {}).get(key)
46 self.config_mock = Mock()
46 self.config_mock = Mock()
47 self.config_mock.get = Mock(side_effect=config_get)
47 self.config_mock.get = Mock(side_effect=config_get)
48
48
49 def create(self, **kwargs):
49 def create(self, **kwargs):
50 parameters = {
50 parameters = {
51 'store': {'path': self.root},
51 'store': {'path': self.root},
52 'ini_path': '',
52 'ini_path': '',
53 'user': self.user,
53 'user': self.user,
54 'user_permissions': {
54 'user_permissions': {
55 self.repo_name: 'repo_admin'
55 self.repo_name: 'repo_admin'
56 },
56 },
57 'config': self.config_mock,
57 'config': self.config_mock,
58 }
58 }
59 parameters.update(kwargs)
59 parameters.update(kwargs)
60 server = SubversionServer(**parameters)
60 server = SubversionServer(**parameters)
61 return server
61 return server
62
62
63
63
64 class TestSubversionServer(object):
64 class TestSubversionServer(object):
65 def test_timeout_returns_value_from_config(self, svn_server):
65 def test_timeout_returns_value_from_config(self, svn_server):
66 server = svn_server.create()
66 server = svn_server.create()
67 assert server.timeout == 30
67 assert server.timeout == 30
68
68
69 @pytest.mark.parametrize(
69 @pytest.mark.parametrize(
70 'permission', ['repository.admin', 'repository.write'])
70 'permission', ['repository.admin', 'repository.write'])
71 def test_check_permissions_with_write_permissions(
71 def test_check_permissions_with_write_permissions(
72 self, svn_server, permission):
72 self, svn_server, permission):
73 user_permissions = {svn_server.repo_name: permission}
73 user_permissions = {svn_server.repo_name: permission}
74 server = svn_server.create(user_permissions=user_permissions)
74 server = svn_server.create(user_permissions=user_permissions)
75 server.tunnel = Mock()
75 server.tunnel = Mock()
76 server.repo_name = svn_server.repo_name
76 server.repo_name = svn_server.repo_name
77 result = server._check_permissions()
77 result = server._check_permissions()
78 assert result is True
78 assert result is True
79 assert server.tunnel.read_only is False
79 assert server.tunnel.read_only is False
80
80
81 def test_check_permissions_with_read_permissions(self, svn_server):
81 def test_check_permissions_with_read_permissions(self, svn_server):
82 user_permissions = {svn_server.repo_name: 'repository.read'}
82 user_permissions = {svn_server.repo_name: 'repository.read'}
83 server = svn_server.create(user_permissions=user_permissions)
83 server = svn_server.create(user_permissions=user_permissions)
84 server.tunnel = Mock()
84 server.tunnel = Mock()
85 server.repo_name = svn_server.repo_name
85 server.repo_name = svn_server.repo_name
86 result = server._check_permissions()
86 result = server._check_permissions()
87 assert result is True
87 assert result is True
88 assert server.tunnel.read_only is True
88 assert server.tunnel.read_only is True
89
89
90 def test_check_permissions_with_no_permissions(self, svn_server, caplog):
90 def test_check_permissions_with_no_permissions(self, svn_server, caplog):
91 tunnel_mock = Mock()
91 tunnel_mock = Mock()
92 user_permissions = {}
92 user_permissions = {}
93 server = svn_server.create(user_permissions=user_permissions)
93 server = svn_server.create(user_permissions=user_permissions)
94 server.tunnel = tunnel_mock
94 server.tunnel = tunnel_mock
95 server.repo_name = svn_server.repo_name
95 server.repo_name = svn_server.repo_name
96 result = server._check_permissions()
96 result = server._check_permissions()
97 assert result is False
97 assert result is False
98 tunnel_mock.fail.assert_called_once_with(
98 tunnel_mock.fail.assert_called_once_with(
99 "Not enough permissions for repository {}".format(
99 "Not enough permissions for repository {}".format(
100 svn_server.repo_name))
100 svn_server.repo_name))
101
101
102 def test_run_returns_1_when_repository_name_cannot_be_extracted(
102 def test_run_returns_1_when_repository_name_cannot_be_extracted(
103 self, svn_server):
103 self, svn_server):
104 server = svn_server.create()
104 server = svn_server.create()
105 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.SubversionTunnelWrapper') as tunnel_mock:
105 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.SubversionTunnelWrapper') as tunnel_mock:
106 tunnel_mock().get_first_client_response.return_value = None
106 tunnel_mock().get_first_client_response.return_value = None
107 exit_code = server.run()
107 exit_code = server.run()
108 assert exit_code == (1, False)
108 assert exit_code == (1, False)
109 tunnel_mock().fail.assert_called_once_with(
109 tunnel_mock().fail.assert_called_once_with(
110 'Repository name cannot be extracted')
110 'Repository name cannot be extracted')
111
111
112 def test_run_returns_tunnel_return_code(self, svn_server, caplog):
112 def test_run_returns_tunnel_return_code(self, svn_server, caplog):
113 server = svn_server.create()
113 server = svn_server.create()
114 fake_response = {
114 fake_response = {
115 'url': 'ssh+svn://test@example.com/test-svn/'
115 'url': 'ssh+svn://test@example.com/test-svn/'
116 }
116 }
117 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.SubversionTunnelWrapper') as tunnel_mock:
117 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.SubversionTunnelWrapper') as tunnel_mock:
118 with patch.object(server, '_check_permissions') as (
118 with patch.object(server, '_check_permissions') as (
119 permissions_mock):
119 permissions_mock):
120 permissions_mock.return_value = True
120 permissions_mock.return_value = True
121 tunnel = tunnel_mock()
121 tunnel = tunnel_mock()
122 tunnel.get_first_client_response.return_value = fake_response
122 tunnel.get_first_client_response.return_value = fake_response
123 tunnel.return_code = 0
123 tunnel.return_code = 0
124 exit_code = server.run()
124 exit_code = server.run()
125 permissions_mock.assert_called_once_with()
125 permissions_mock.assert_called_once_with()
126
126
127 expected_log_calls = sorted([
127 expected_log_calls = sorted([
128 "Using subversion binaries from '%s'" % svn_server.svn_path
128 "Using subversion binaries from '%s'" % svn_server.svn_path
129 ])
129 ])
130
130
131 assert expected_log_calls == [t[2] for t in caplog.record_tuples]
131 assert expected_log_calls == [t[2] for t in caplog.record_tuples]
132
132
133 assert exit_code == (0, False)
133 assert exit_code == (0, False)
134 tunnel.patch_first_client_response.assert_called_once_with(
134 tunnel.patch_first_client_response.assert_called_once_with(
135 fake_response)
135 fake_response)
136 tunnel.sync.assert_called_once_with()
136 tunnel.sync.assert_called_once_with()
@@ -1,73 +1,71 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
22
23 import os
21 import os
24 import pytest
22 import pytest
25 import mock
23 import mock
26
24
27 from rhodecode.apps.ssh_support import utils
25 from rhodecode.apps.ssh_support import utils
28 from rhodecode.lib.utils2 import AttributeDict
26 from rhodecode.lib.utils2 import AttributeDict
29
27
30
28
31 class TestSshKeyFileGeneration(object):
29 class TestSshKeyFileGeneration(object):
32 @pytest.mark.parametrize('ssh_wrapper_cmd', ['/tmp/sshwrapper.py'])
30 @pytest.mark.parametrize('ssh_wrapper_cmd', ['/tmp/sshwrapper.py'])
33 @pytest.mark.parametrize('allow_shell', [True, False])
31 @pytest.mark.parametrize('allow_shell', [True, False])
34 @pytest.mark.parametrize('debug', [True, False])
32 @pytest.mark.parametrize('debug', [True, False])
35 @pytest.mark.parametrize('ssh_opts', [None, 'mycustom,option'])
33 @pytest.mark.parametrize('ssh_opts', [None, 'mycustom,option'])
36 def test_write_keyfile(self, tmpdir, ssh_wrapper_cmd, allow_shell, debug, ssh_opts):
34 def test_write_keyfile(self, tmpdir, ssh_wrapper_cmd, allow_shell, debug, ssh_opts):
37
35
38 authorized_keys_file_path = os.path.join(str(tmpdir), 'authorized_keys')
36 authorized_keys_file_path = os.path.join(str(tmpdir), 'authorized_keys')
39
37
40 def keys():
38 def keys():
41 return [
39 return [
42 AttributeDict({'user': AttributeDict(username='admin'),
40 AttributeDict({'user': AttributeDict(username='admin'),
43 'ssh_key_data': 'ssh-rsa ADMIN_KEY'}),
41 'ssh_key_data': 'ssh-rsa ADMIN_KEY'}),
44 AttributeDict({'user': AttributeDict(username='user'),
42 AttributeDict({'user': AttributeDict(username='user'),
45 'ssh_key_data': 'ssh-rsa USER_KEY'}),
43 'ssh_key_data': 'ssh-rsa USER_KEY'}),
46 ]
44 ]
47 with mock.patch('rhodecode.apps.ssh_support.utils.get_all_active_keys',
45 with mock.patch('rhodecode.apps.ssh_support.utils.get_all_active_keys',
48 return_value=keys()):
46 return_value=keys()):
49 with mock.patch.dict('rhodecode.CONFIG', {'__file__': '/tmp/file.ini'}):
47 with mock.patch.dict('rhodecode.CONFIG', {'__file__': '/tmp/file.ini'}):
50 utils._generate_ssh_authorized_keys_file(
48 utils._generate_ssh_authorized_keys_file(
51 authorized_keys_file_path, ssh_wrapper_cmd,
49 authorized_keys_file_path, ssh_wrapper_cmd,
52 allow_shell, ssh_opts, debug
50 allow_shell, ssh_opts, debug
53 )
51 )
54
52
55 assert os.path.isfile(authorized_keys_file_path)
53 assert os.path.isfile(authorized_keys_file_path)
56 with open(authorized_keys_file_path) as f:
54 with open(authorized_keys_file_path) as f:
57 content = f.read()
55 content = f.read()
58
56
59 assert 'command="/tmp/sshwrapper.py' in content
57 assert 'command="/tmp/sshwrapper.py' in content
60 assert 'This file is managed by RhodeCode, ' \
58 assert 'This file is managed by RhodeCode, ' \
61 'please do not edit it manually.' in content
59 'please do not edit it manually.' in content
62
60
63 if allow_shell:
61 if allow_shell:
64 assert '--shell' in content
62 assert '--shell' in content
65
63
66 if debug:
64 if debug:
67 assert '--debug' in content
65 assert '--debug' in content
68
66
69 assert '--user' in content
67 assert '--user' in content
70 assert '--user-id' in content
68 assert '--user-id' in content
71
69
72 if ssh_opts:
70 if ssh_opts:
73 assert ssh_opts in content
71 assert ssh_opts in content
@@ -1,204 +1,201 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 import os
20 import os
21 import mock
21 import mock
22 import pytest
22 import pytest
23 import ConfigParser
23 import ConfigParser
24
24
25 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SshWrapper
25 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SshWrapper
26
26
27
27
28 @pytest.fixture
28 @pytest.fixture
29 def dummy_conf(tmpdir):
29 def dummy_conf(tmpdir):
30 conf = ConfigParser.ConfigParser()
30 conf = ConfigParser.ConfigParser()
31 conf.add_section('app:main')
31 conf.add_section('app:main')
32 conf.set('app:main', 'ssh.executable.hg', '/usr/bin/hg')
32 conf.set('app:main', 'ssh.executable.hg', '/usr/bin/hg')
33 conf.set('app:main', 'ssh.executable.git', '/usr/bin/git')
33 conf.set('app:main', 'ssh.executable.git', '/usr/bin/git')
34 conf.set('app:main', 'ssh.executable.svn', '/usr/bin/svnserve')
34 conf.set('app:main', 'ssh.executable.svn', '/usr/bin/svnserve')
35
35
36 conf.set('app:main', 'ssh.api_key', 'xxx')
37 conf.set('app:main', 'ssh.api_host', 'http://localhost')
38
39 f_path = os.path.join(str(tmpdir), 'ssh_wrapper_test.ini')
36 f_path = os.path.join(str(tmpdir), 'ssh_wrapper_test.ini')
40 with open(f_path, 'wb') as f:
37 with open(f_path, 'wb') as f:
41 conf.write(f)
38 conf.write(f)
42
39
43 return os.path.join(f_path)
40 return os.path.join(f_path)
44
41
45
42
46 class TestGetRepoDetails(object):
43 class TestGetRepoDetails(object):
47 @pytest.mark.parametrize(
44 @pytest.mark.parametrize(
48 'command', [
45 'command', [
49 'hg -R test-repo serve --stdio',
46 'hg -R test-repo serve --stdio',
50 'hg -R test-repo serve --stdio'
47 'hg -R test-repo serve --stdio'
51 ])
48 ])
52 def test_hg_command_matched(self, command, dummy_conf):
49 def test_hg_command_matched(self, command, dummy_conf):
53 wrapper = SshWrapper(command, 'auto', 'admin', '3', 'False', dummy_conf)
50 wrapper = SshWrapper(command, 'auto', 'admin', '3', 'False', dummy_conf)
54 type_, name, mode = wrapper.get_repo_details('auto')
51 type_, name, mode = wrapper.get_repo_details('auto')
55 assert type_ == 'hg'
52 assert type_ == 'hg'
56 assert name == 'test-repo'
53 assert name == 'test-repo'
57 assert mode is 'auto'
54 assert mode is 'auto'
58
55
59 @pytest.mark.parametrize(
56 @pytest.mark.parametrize(
60 'command', [
57 'command', [
61 'hg test-repo serve --stdio',
58 'hg test-repo serve --stdio',
62 'hg -R test-repo serve',
59 'hg -R test-repo serve',
63 'hg serve --stdio',
60 'hg serve --stdio',
64 'hg serve -R test-repo'
61 'hg serve -R test-repo'
65 ])
62 ])
66 def test_hg_command_not_matched(self, command, dummy_conf):
63 def test_hg_command_not_matched(self, command, dummy_conf):
67 wrapper = SshWrapper(command, 'auto', 'admin', '3', 'False', dummy_conf)
64 wrapper = SshWrapper(command, 'auto', 'admin', '3', 'False', dummy_conf)
68 type_, name, mode = wrapper.get_repo_details('auto')
65 type_, name, mode = wrapper.get_repo_details('auto')
69 assert type_ is None
66 assert type_ is None
70 assert name is None
67 assert name is None
71 assert mode is 'auto'
68 assert mode is 'auto'
72
69
73
70
74 class TestServe(object):
71 class TestServe(object):
75 def test_serve_raises_an_exception_when_vcs_is_not_recognized(self, dummy_conf):
72 def test_serve_raises_an_exception_when_vcs_is_not_recognized(self, dummy_conf):
76 with mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store'):
73 with mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store'):
77 wrapper = SshWrapper('random command', 'auto', 'admin', '3', 'False', dummy_conf)
74 wrapper = SshWrapper('random command', 'auto', 'admin', '3', 'False', dummy_conf)
78
75
79 with pytest.raises(Exception) as exc_info:
76 with pytest.raises(Exception) as exc_info:
80 wrapper.serve(
77 wrapper.serve(
81 vcs='microsoft-tfs', repo='test-repo', mode=None, user='test',
78 vcs='microsoft-tfs', repo='test-repo', mode=None, user='test',
82 permissions={})
79 permissions={})
83 assert exc_info.value.message == 'Unrecognised VCS: microsoft-tfs'
80 assert exc_info.value.message == 'Unrecognised VCS: microsoft-tfs'
84
81
85
82
86 class TestServeHg(object):
83 class TestServeHg(object):
87
84
88 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
85 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
89 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
86 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
90 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
87 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
91 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.MercurialServer.run')
88 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.MercurialServer.run')
92 def test_serve_creates_hg_instance(
89 def test_serve_creates_hg_instance(
93 self, mercurial_run_mock, get_repo_store_mock, get_user_mock,
90 self, mercurial_run_mock, get_repo_store_mock, get_user_mock,
94 invalidate_cache_mock, dummy_conf):
91 invalidate_cache_mock, dummy_conf):
95
92
96 repo_name = None
93 repo_name = None
97 mercurial_run_mock.return_value = 0, True
94 mercurial_run_mock.return_value = 0, True
98 get_user_mock.return_value = {repo_name: 'repository.admin'}
95 get_user_mock.return_value = {repo_name: 'repository.admin'}
99 get_repo_store_mock.return_value = {'path': '/tmp'}
96 get_repo_store_mock.return_value = {'path': '/tmp'}
100
97
101 wrapper = SshWrapper('date', 'hg', 'admin', '3', 'False',
98 wrapper = SshWrapper('date', 'hg', 'admin', '3', 'False',
102 dummy_conf)
99 dummy_conf)
103 exit_code = wrapper.wrap()
100 exit_code = wrapper.wrap()
104 assert exit_code == 0
101 assert exit_code == 0
105 assert mercurial_run_mock.called
102 assert mercurial_run_mock.called
106
103
107 assert get_repo_store_mock.called
104 assert get_repo_store_mock.called
108 assert get_user_mock.called
105 assert get_user_mock.called
109 invalidate_cache_mock.assert_called_once_with(repo_name)
106 invalidate_cache_mock.assert_called_once_with(repo_name)
110
107
111 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
108 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
112 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
109 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
113 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
110 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
114 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.MercurialServer.run')
111 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.MercurialServer.run')
115 def test_serve_hg_invalidates_cache(
112 def test_serve_hg_invalidates_cache(
116 self, mercurial_run_mock, get_repo_store_mock, get_user_mock,
113 self, mercurial_run_mock, get_repo_store_mock, get_user_mock,
117 invalidate_cache_mock, dummy_conf):
114 invalidate_cache_mock, dummy_conf):
118
115
119 repo_name = None
116 repo_name = None
120 mercurial_run_mock.return_value = 0, True
117 mercurial_run_mock.return_value = 0, True
121 get_user_mock.return_value = {repo_name: 'repository.admin'}
118 get_user_mock.return_value = {repo_name: 'repository.admin'}
122 get_repo_store_mock.return_value = {'path': '/tmp'}
119 get_repo_store_mock.return_value = {'path': '/tmp'}
123
120
124 wrapper = SshWrapper('date', 'hg', 'admin', '3', 'False',
121 wrapper = SshWrapper('date', 'hg', 'admin', '3', 'False',
125 dummy_conf)
122 dummy_conf)
126 exit_code = wrapper.wrap()
123 exit_code = wrapper.wrap()
127 assert exit_code == 0
124 assert exit_code == 0
128 assert mercurial_run_mock.called
125 assert mercurial_run_mock.called
129
126
130 assert get_repo_store_mock.called
127 assert get_repo_store_mock.called
131 assert get_user_mock.called
128 assert get_user_mock.called
132 invalidate_cache_mock.assert_called_once_with(repo_name)
129 invalidate_cache_mock.assert_called_once_with(repo_name)
133
130
134
131
135 class TestServeGit(object):
132 class TestServeGit(object):
136
133
137 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
134 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
138 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
135 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
139 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
136 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
140 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.GitServer.run')
137 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.GitServer.run')
141 def test_serve_creates_git_instance(self, git_run_mock, get_repo_store_mock, get_user_mock,
138 def test_serve_creates_git_instance(self, git_run_mock, get_repo_store_mock, get_user_mock,
142 invalidate_cache_mock, dummy_conf):
139 invalidate_cache_mock, dummy_conf):
143 repo_name = None
140 repo_name = None
144 git_run_mock.return_value = 0, True
141 git_run_mock.return_value = 0, True
145 get_user_mock.return_value = {repo_name: 'repository.admin'}
142 get_user_mock.return_value = {repo_name: 'repository.admin'}
146 get_repo_store_mock.return_value = {'path': '/tmp'}
143 get_repo_store_mock.return_value = {'path': '/tmp'}
147
144
148 wrapper = SshWrapper('date', 'git', 'admin', '3', 'False',
145 wrapper = SshWrapper('date', 'git', 'admin', '3', 'False',
149 dummy_conf)
146 dummy_conf)
150
147
151 exit_code = wrapper.wrap()
148 exit_code = wrapper.wrap()
152 assert exit_code == 0
149 assert exit_code == 0
153 assert git_run_mock.called
150 assert git_run_mock.called
154 assert get_repo_store_mock.called
151 assert get_repo_store_mock.called
155 assert get_user_mock.called
152 assert get_user_mock.called
156 invalidate_cache_mock.assert_called_once_with(repo_name)
153 invalidate_cache_mock.assert_called_once_with(repo_name)
157
154
158 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
155 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
159 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
156 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
160 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
157 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
161 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.GitServer.run')
158 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.GitServer.run')
162 def test_serve_git_invalidates_cache(
159 def test_serve_git_invalidates_cache(
163 self, git_run_mock, get_repo_store_mock, get_user_mock,
160 self, git_run_mock, get_repo_store_mock, get_user_mock,
164 invalidate_cache_mock, dummy_conf):
161 invalidate_cache_mock, dummy_conf):
165 repo_name = None
162 repo_name = None
166 git_run_mock.return_value = 0, True
163 git_run_mock.return_value = 0, True
167 get_user_mock.return_value = {repo_name: 'repository.admin'}
164 get_user_mock.return_value = {repo_name: 'repository.admin'}
168 get_repo_store_mock.return_value = {'path': '/tmp'}
165 get_repo_store_mock.return_value = {'path': '/tmp'}
169
166
170 wrapper = SshWrapper('date', 'git', 'admin', '3', 'False', dummy_conf)
167 wrapper = SshWrapper('date', 'git', 'admin', '3', 'False', dummy_conf)
171
168
172 exit_code = wrapper.wrap()
169 exit_code = wrapper.wrap()
173 assert exit_code == 0
170 assert exit_code == 0
174 assert git_run_mock.called
171 assert git_run_mock.called
175
172
176 assert get_repo_store_mock.called
173 assert get_repo_store_mock.called
177 assert get_user_mock.called
174 assert get_user_mock.called
178 invalidate_cache_mock.assert_called_once_with(repo_name)
175 invalidate_cache_mock.assert_called_once_with(repo_name)
179
176
180
177
181 class TestServeSvn(object):
178 class TestServeSvn(object):
182
179
183 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
180 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.invalidate_cache')
184 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
181 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_user_permissions')
185 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
182 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.RhodeCodeApiClient.get_repo_store')
186 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.SubversionServer.run')
183 @mock.patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.SubversionServer.run')
187 def test_serve_creates_svn_instance(
184 def test_serve_creates_svn_instance(
188 self, svn_run_mock, get_repo_store_mock, get_user_mock,
185 self, svn_run_mock, get_repo_store_mock, get_user_mock,
189 invalidate_cache_mock, dummy_conf):
186 invalidate_cache_mock, dummy_conf):
190
187
191 repo_name = None
188 repo_name = None
192 svn_run_mock.return_value = 0, True
189 svn_run_mock.return_value = 0, True
193 get_user_mock.return_value = {repo_name: 'repository.admin'}
190 get_user_mock.return_value = {repo_name: 'repository.admin'}
194 get_repo_store_mock.return_value = {'path': '/tmp'}
191 get_repo_store_mock.return_value = {'path': '/tmp'}
195
192
196 wrapper = SshWrapper('date', 'svn', 'admin', '3', 'False', dummy_conf)
193 wrapper = SshWrapper('date', 'svn', 'admin', '3', 'False', dummy_conf)
197
194
198 exit_code = wrapper.wrap()
195 exit_code = wrapper.wrap()
199 assert exit_code == 0
196 assert exit_code == 0
200 assert svn_run_mock.called
197 assert svn_run_mock.called
201
198
202 assert get_repo_store_mock.called
199 assert get_repo_store_mock.called
203 assert get_user_mock.called
200 assert get_user_mock.called
204 invalidate_cache_mock.assert_called_once_with(repo_name)
201 invalidate_cache_mock.assert_called_once_with(repo_name)
@@ -1,285 +1,285 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import subprocess
22 import subprocess
23 from io import BytesIO
23 from io import BytesIO
24 from time import sleep
24 from time import sleep
25
25
26 import pytest
26 import pytest
27 from mock import patch, Mock, MagicMock, call
27 from mock import patch, Mock, MagicMock, call
28
28
29 from rhodecode.apps.ssh_support.lib.ssh_wrapper import SubversionTunnelWrapper
29 from rhodecode.apps.ssh_support.lib.backends.svn import SubversionTunnelWrapper
30 from rhodecode.tests import no_newline_id_generator
30 from rhodecode.tests import no_newline_id_generator
31
31
32
32
33 class TestSubversionTunnelWrapper(object):
33 class TestSubversionTunnelWrapper(object):
34 @pytest.mark.parametrize(
34 @pytest.mark.parametrize(
35 'input_string, output_string', [
35 'input_string, output_string', [
36 [None, ''],
36 [None, ''],
37 ['abcde', '5:abcde '],
37 ['abcde', '5:abcde '],
38 ['abcdefghijk', '11:abcdefghijk ']
38 ['abcdefghijk', '11:abcdefghijk ']
39 ])
39 ])
40 def test_svn_string(self, input_string, output_string):
40 def test_svn_string(self, input_string, output_string):
41 wrapper = SubversionTunnelWrapper(timeout=5)
41 wrapper = SubversionTunnelWrapper(timeout=5)
42 assert wrapper._svn_string(input_string) == output_string
42 assert wrapper._svn_string(input_string) == output_string
43
43
44 def test_read_first_client_response(self):
44 def test_read_first_client_response(self):
45 wrapper = SubversionTunnelWrapper(timeout=5)
45 wrapper = SubversionTunnelWrapper(timeout=5)
46 buffer_ = '( abcd ( efg hij ) ) '
46 buffer_ = '( abcd ( efg hij ) ) '
47 wrapper.stdin = BytesIO(buffer_)
47 wrapper.stdin = BytesIO(buffer_)
48 result = wrapper._read_first_client_response()
48 result = wrapper._read_first_client_response()
49 assert result == buffer_
49 assert result == buffer_
50
50
51 def test_parse_first_client_response_returns_dict(self):
51 def test_parse_first_client_response_returns_dict(self):
52 response = (
52 response = (
53 '( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo'
53 '( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo'
54 ' log-revprops ) 26:svn+ssh://vcs@vm/hello-svn 38:SVN/1.8.11'
54 ' log-revprops ) 26:svn+ssh://vcs@vm/hello-svn 38:SVN/1.8.11'
55 ' (x86_64-apple-darwin14.1.0) ( ) ) ')
55 ' (x86_64-apple-darwin14.1.0) ( ) ) ')
56 wrapper = SubversionTunnelWrapper(timeout=5)
56 wrapper = SubversionTunnelWrapper(timeout=5)
57 result = wrapper._parse_first_client_response(response)
57 result = wrapper._parse_first_client_response(response)
58 assert result['version'] == '2'
58 assert result['version'] == '2'
59 assert (
59 assert (
60 result['capabilities'] ==
60 result['capabilities'] ==
61 'edit-pipeline svndiff1 absent-entries depth mergeinfo'
61 'edit-pipeline svndiff1 absent-entries depth mergeinfo'
62 ' log-revprops')
62 ' log-revprops')
63 assert result['url'] == 'svn+ssh://vcs@vm/hello-svn'
63 assert result['url'] == 'svn+ssh://vcs@vm/hello-svn'
64 assert result['ra_client'] == 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)'
64 assert result['ra_client'] == 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)'
65 assert result['client'] is None
65 assert result['client'] is None
66
66
67 def test_parse_first_client_response_returns_none_when_not_matched(self):
67 def test_parse_first_client_response_returns_none_when_not_matched(self):
68 response = (
68 response = (
69 '( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo'
69 '( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo'
70 ' log-revprops ) ) ')
70 ' log-revprops ) ) ')
71 wrapper = SubversionTunnelWrapper(timeout=5)
71 wrapper = SubversionTunnelWrapper(timeout=5)
72 result = wrapper._parse_first_client_response(response)
72 result = wrapper._parse_first_client_response(response)
73 assert result is None
73 assert result is None
74
74
75 def test_interrupt(self):
75 def test_interrupt(self):
76 wrapper = SubversionTunnelWrapper(timeout=5)
76 wrapper = SubversionTunnelWrapper(timeout=5)
77 with patch.object(wrapper, 'fail') as fail_mock:
77 with patch.object(wrapper, 'fail') as fail_mock:
78 wrapper.interrupt(1, 'frame')
78 wrapper.interrupt(1, 'frame')
79 fail_mock.assert_called_once_with("Exited by timeout")
79 fail_mock.assert_called_once_with("Exited by timeout")
80
80
81 def test_fail(self):
81 def test_fail(self):
82 process_mock = Mock()
82 process_mock = Mock()
83 wrapper = SubversionTunnelWrapper(timeout=5)
83 wrapper = SubversionTunnelWrapper(timeout=5)
84 with patch.object(wrapper, 'remove_configs') as remove_configs_mock:
84 with patch.object(wrapper, 'remove_configs') as remove_configs_mock:
85 with patch('sys.stdout', new_callable=BytesIO) as stdout_mock:
85 with patch('sys.stdout', new_callable=BytesIO) as stdout_mock:
86 with patch.object(wrapper, 'process') as process_mock:
86 with patch.object(wrapper, 'process') as process_mock:
87 wrapper.fail('test message')
87 wrapper.fail('test message')
88 assert (
88 assert (
89 stdout_mock.getvalue() ==
89 stdout_mock.getvalue() ==
90 '( failure ( ( 210005 12:test message 0: 0 ) ) )\n')
90 '( failure ( ( 210005 12:test message 0: 0 ) ) )\n')
91 process_mock.kill.assert_called_once_with()
91 process_mock.kill.assert_called_once_with()
92 remove_configs_mock.assert_called_once_with()
92 remove_configs_mock.assert_called_once_with()
93
93
94 @pytest.mark.parametrize(
94 @pytest.mark.parametrize(
95 'client, expected_client', [
95 'client, expected_client', [
96 ['test ', 'test '],
96 ['test ', 'test '],
97 ['', ''],
97 ['', ''],
98 [None, '']
98 [None, '']
99 ])
99 ])
100 def test_client_in_patch_first_client_response(
100 def test_client_in_patch_first_client_response(
101 self, client, expected_client):
101 self, client, expected_client):
102 response = {
102 response = {
103 'version': 2,
103 'version': 2,
104 'capabilities': 'edit-pipeline svndiff1 absent-entries depth',
104 'capabilities': 'edit-pipeline svndiff1 absent-entries depth',
105 'url': 'svn+ssh://example.com/svn',
105 'url': 'svn+ssh://example.com/svn',
106 'ra_client': 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)',
106 'ra_client': 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)',
107 'client': client
107 'client': client
108 }
108 }
109 wrapper = SubversionTunnelWrapper(timeout=5)
109 wrapper = SubversionTunnelWrapper(timeout=5)
110 stdin = BytesIO()
110 stdin = BytesIO()
111 with patch.object(wrapper, 'process') as process_mock:
111 with patch.object(wrapper, 'process') as process_mock:
112 process_mock.stdin = stdin
112 process_mock.stdin = stdin
113 wrapper.patch_first_client_response(response)
113 wrapper.patch_first_client_response(response)
114 assert (
114 assert (
115 stdin.getvalue() ==
115 stdin.getvalue() ==
116 '( 2 ( edit-pipeline svndiff1 absent-entries depth )'
116 '( 2 ( edit-pipeline svndiff1 absent-entries depth )'
117 ' 25:svn+ssh://example.com/svn 38:SVN/1.8.11'
117 ' 25:svn+ssh://example.com/svn 38:SVN/1.8.11'
118 ' (x86_64-apple-darwin14.1.0) ( {expected_client}) ) '.format(
118 ' (x86_64-apple-darwin14.1.0) ( {expected_client}) ) '.format(
119 expected_client=expected_client))
119 expected_client=expected_client))
120
120
121 def test_kwargs_override_data_in_patch_first_client_response(self):
121 def test_kwargs_override_data_in_patch_first_client_response(self):
122 response = {
122 response = {
123 'version': 2,
123 'version': 2,
124 'capabilities': 'edit-pipeline svndiff1 absent-entries depth',
124 'capabilities': 'edit-pipeline svndiff1 absent-entries depth',
125 'url': 'svn+ssh://example.com/svn',
125 'url': 'svn+ssh://example.com/svn',
126 'ra_client': 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)',
126 'ra_client': 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)',
127 'client': 'test'
127 'client': 'test'
128 }
128 }
129 wrapper = SubversionTunnelWrapper(timeout=5)
129 wrapper = SubversionTunnelWrapper(timeout=5)
130 stdin = BytesIO()
130 stdin = BytesIO()
131 with patch.object(wrapper, 'process') as process_mock:
131 with patch.object(wrapper, 'process') as process_mock:
132 process_mock.stdin = stdin
132 process_mock.stdin = stdin
133 wrapper.patch_first_client_response(
133 wrapper.patch_first_client_response(
134 response, version=3, client='abcde ',
134 response, version=3, client='abcde ',
135 capabilities='absent-entries depth',
135 capabilities='absent-entries depth',
136 url='svn+ssh://example.org/test',
136 url='svn+ssh://example.org/test',
137 ra_client='SVN/1.8.12 (ubuntu 14.04)')
137 ra_client='SVN/1.8.12 (ubuntu 14.04)')
138 assert (
138 assert (
139 stdin.getvalue() ==
139 stdin.getvalue() ==
140 '( 3 ( absent-entries depth ) 26:svn+ssh://example.org/test'
140 '( 3 ( absent-entries depth ) 26:svn+ssh://example.org/test'
141 ' 25:SVN/1.8.12 (ubuntu 14.04) ( abcde ) ) ')
141 ' 25:SVN/1.8.12 (ubuntu 14.04) ( abcde ) ) ')
142
142
143 def test_patch_first_client_response_sets_environment(self):
143 def test_patch_first_client_response_sets_environment(self):
144 response = {
144 response = {
145 'version': 2,
145 'version': 2,
146 'capabilities': 'edit-pipeline svndiff1 absent-entries depth',
146 'capabilities': 'edit-pipeline svndiff1 absent-entries depth',
147 'url': 'svn+ssh://example.com/svn',
147 'url': 'svn+ssh://example.com/svn',
148 'ra_client': 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)',
148 'ra_client': 'SVN/1.8.11 (x86_64-apple-darwin14.1.0)',
149 'client': 'test'
149 'client': 'test'
150 }
150 }
151 wrapper = SubversionTunnelWrapper(timeout=5)
151 wrapper = SubversionTunnelWrapper(timeout=5)
152 stdin = BytesIO()
152 stdin = BytesIO()
153 with patch.object(wrapper, 'create_hooks_env') as create_hooks_mock:
153 with patch.object(wrapper, 'create_hooks_env') as create_hooks_mock:
154 with patch.object(wrapper, 'process') as process_mock:
154 with patch.object(wrapper, 'process') as process_mock:
155 process_mock.stdin = stdin
155 process_mock.stdin = stdin
156 wrapper.patch_first_client_response(response)
156 wrapper.patch_first_client_response(response)
157 create_hooks_mock.assert_called_once_with()
157 create_hooks_mock.assert_called_once_with()
158
158
159 def test_get_first_client_response_exits_by_signal(self):
159 def test_get_first_client_response_exits_by_signal(self):
160 wrapper = SubversionTunnelWrapper(timeout=1)
160 wrapper = SubversionTunnelWrapper(timeout=1)
161 read_patch = patch.object(wrapper, '_read_first_client_response')
161 read_patch = patch.object(wrapper, '_read_first_client_response')
162 parse_patch = patch.object(wrapper, '_parse_first_client_response')
162 parse_patch = patch.object(wrapper, '_parse_first_client_response')
163 interrupt_patch = patch.object(wrapper, 'interrupt')
163 interrupt_patch = patch.object(wrapper, 'interrupt')
164
164
165 with read_patch as read_mock, parse_patch as parse_mock, \
165 with read_patch as read_mock, parse_patch as parse_mock, \
166 interrupt_patch as interrupt_mock:
166 interrupt_patch as interrupt_mock:
167 read_mock.side_effect = lambda: sleep(3)
167 read_mock.side_effect = lambda: sleep(3)
168 wrapper.get_first_client_response()
168 wrapper.get_first_client_response()
169
169
170 assert parse_mock.call_count == 0
170 assert parse_mock.call_count == 0
171 assert interrupt_mock.call_count == 1
171 assert interrupt_mock.call_count == 1
172
172
173 def test_get_first_client_response_parses_data(self):
173 def test_get_first_client_response_parses_data(self):
174 wrapper = SubversionTunnelWrapper(timeout=5)
174 wrapper = SubversionTunnelWrapper(timeout=5)
175 response = (
175 response = (
176 '( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo'
176 '( 2 ( edit-pipeline svndiff1 absent-entries depth mergeinfo'
177 ' log-revprops ) 26:svn+ssh://vcs@vm/hello-svn 38:SVN/1.8.11'
177 ' log-revprops ) 26:svn+ssh://vcs@vm/hello-svn 38:SVN/1.8.11'
178 ' (x86_64-apple-darwin14.1.0) ( ) ) ')
178 ' (x86_64-apple-darwin14.1.0) ( ) ) ')
179 read_patch = patch.object(wrapper, '_read_first_client_response')
179 read_patch = patch.object(wrapper, '_read_first_client_response')
180 parse_patch = patch.object(wrapper, '_parse_first_client_response')
180 parse_patch = patch.object(wrapper, '_parse_first_client_response')
181
181
182 with read_patch as read_mock, parse_patch as parse_mock:
182 with read_patch as read_mock, parse_patch as parse_mock:
183 read_mock.return_value = response
183 read_mock.return_value = response
184 wrapper.get_first_client_response()
184 wrapper.get_first_client_response()
185
185
186 parse_mock.assert_called_once_with(response)
186 parse_mock.assert_called_once_with(response)
187
187
188 def test_return_code(self):
188 def test_return_code(self):
189 wrapper = SubversionTunnelWrapper(timeout=5)
189 wrapper = SubversionTunnelWrapper(timeout=5)
190 with patch.object(wrapper, 'process') as process_mock:
190 with patch.object(wrapper, 'process') as process_mock:
191 process_mock.returncode = 1
191 process_mock.returncode = 1
192 assert wrapper.return_code == 1
192 assert wrapper.return_code == 1
193
193
194 def test_sync_loop_breaks_when_process_cannot_be_polled(self):
194 def test_sync_loop_breaks_when_process_cannot_be_polled(self):
195 self.counter = 0
195 self.counter = 0
196 buffer_ = 'abcdefghij'
196 buffer_ = 'abcdefghij'
197
197
198 wrapper = SubversionTunnelWrapper(timeout=5)
198 wrapper = SubversionTunnelWrapper(timeout=5)
199 wrapper.stdin = BytesIO(buffer_)
199 wrapper.stdin = BytesIO(buffer_)
200 with patch.object(wrapper, 'remove_configs') as remove_configs_mock:
200 with patch.object(wrapper, 'remove_configs') as remove_configs_mock:
201 with patch.object(wrapper, 'process') as process_mock:
201 with patch.object(wrapper, 'process') as process_mock:
202 process_mock.poll.side_effect = self._poll
202 process_mock.poll.side_effect = self._poll
203 process_mock.stdin = BytesIO()
203 process_mock.stdin = BytesIO()
204 wrapper.sync()
204 wrapper.sync()
205 assert process_mock.stdin.getvalue() == 'abcde'
205 assert process_mock.stdin.getvalue() == 'abcde'
206 remove_configs_mock.assert_called_once_with()
206 remove_configs_mock.assert_called_once_with()
207
207
208 def test_sync_loop_breaks_when_nothing_to_read(self):
208 def test_sync_loop_breaks_when_nothing_to_read(self):
209 self.counter = 0
209 self.counter = 0
210 buffer_ = 'abcdefghij'
210 buffer_ = 'abcdefghij'
211
211
212 wrapper = SubversionTunnelWrapper(timeout=5)
212 wrapper = SubversionTunnelWrapper(timeout=5)
213 wrapper.stdin = BytesIO(buffer_)
213 wrapper.stdin = BytesIO(buffer_)
214 with patch.object(wrapper, 'remove_configs') as remove_configs_mock:
214 with patch.object(wrapper, 'remove_configs') as remove_configs_mock:
215 with patch.object(wrapper, 'process') as process_mock:
215 with patch.object(wrapper, 'process') as process_mock:
216 process_mock.poll.return_value = None
216 process_mock.poll.return_value = None
217 process_mock.stdin = BytesIO()
217 process_mock.stdin = BytesIO()
218 wrapper.sync()
218 wrapper.sync()
219 assert process_mock.stdin.getvalue() == buffer_
219 assert process_mock.stdin.getvalue() == buffer_
220 remove_configs_mock.assert_called_once_with()
220 remove_configs_mock.assert_called_once_with()
221
221
222 def test_start_without_repositories_root(self):
222 def test_start_without_repositories_root(self):
223 svn_path = '/usr/local/bin/svnserve'
223 svn_path = '/usr/local/bin/svnserve'
224 wrapper = SubversionTunnelWrapper(timeout=5, svn_path=svn_path)
224 wrapper = SubversionTunnelWrapper(timeout=5, svn_path=svn_path)
225 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.Popen') as popen_mock:
225 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.Popen') as popen_mock:
226 wrapper.start()
226 wrapper.start()
227 expected_command = [
227 expected_command = [
228 svn_path, '-t', '--config-file', wrapper.svn_conf_path]
228 svn_path, '-t', '--config-file', wrapper.svn_conf_path]
229 popen_mock.assert_called_once_with(
229 popen_mock.assert_called_once_with(
230 expected_command, stdin=subprocess.PIPE)
230 expected_command, stdin=subprocess.PIPE)
231 assert wrapper.process == popen_mock()
231 assert wrapper.process == popen_mock()
232
232
233 def test_start_with_repositories_root(self):
233 def test_start_with_repositories_root(self):
234 svn_path = '/usr/local/bin/svnserve'
234 svn_path = '/usr/local/bin/svnserve'
235 repositories_root = '/home/repos'
235 repositories_root = '/home/repos'
236 wrapper = SubversionTunnelWrapper(
236 wrapper = SubversionTunnelWrapper(
237 timeout=5, svn_path=svn_path, repositories_root=repositories_root)
237 timeout=5, svn_path=svn_path, repositories_root=repositories_root)
238 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.Popen') as popen_mock:
238 with patch('rhodecode.apps.ssh_support.lib.ssh_wrapper.Popen') as popen_mock:
239 wrapper.start()
239 wrapper.start()
240 expected_command = [
240 expected_command = [
241 svn_path, '-t', '--config-file', wrapper.svn_conf_path,
241 svn_path, '-t', '--config-file', wrapper.svn_conf_path,
242 '-r', repositories_root]
242 '-r', repositories_root]
243 popen_mock.assert_called_once_with(
243 popen_mock.assert_called_once_with(
244 expected_command, stdin=subprocess.PIPE)
244 expected_command, stdin=subprocess.PIPE)
245 assert wrapper.process == popen_mock()
245 assert wrapper.process == popen_mock()
246
246
247 def test_create_svn_config(self):
247 def test_create_svn_config(self):
248 wrapper = SubversionTunnelWrapper(timeout=5)
248 wrapper = SubversionTunnelWrapper(timeout=5)
249 file_mock = MagicMock(spec=file)
249 file_mock = MagicMock(spec=file)
250 with patch('os.fdopen', create=True) as open_mock:
250 with patch('os.fdopen', create=True) as open_mock:
251 open_mock.return_value = file_mock
251 open_mock.return_value = file_mock
252 wrapper.create_svn_config()
252 wrapper.create_svn_config()
253 open_mock.assert_called_once_with(wrapper.svn_conf_fd, 'w')
253 open_mock.assert_called_once_with(wrapper.svn_conf_fd, 'w')
254 expected_content = '[general]\nhooks-env = {}\n'.format(
254 expected_content = '[general]\nhooks-env = {}\n'.format(
255 wrapper.hooks_env_path)
255 wrapper.hooks_env_path)
256 file_handle = file_mock.__enter__.return_value
256 file_handle = file_mock.__enter__.return_value
257 file_handle.write.assert_called_once_with(expected_content)
257 file_handle.write.assert_called_once_with(expected_content)
258
258
259 @pytest.mark.parametrize(
259 @pytest.mark.parametrize(
260 'read_only, expected_content', [
260 'read_only, expected_content', [
261 [True, '[default]\nLANG = en_US.UTF-8\nSSH_READ_ONLY = 1\n'],
261 [True, '[default]\nLANG = en_US.UTF-8\nSSH_READ_ONLY = 1\n'],
262 [False, '[default]\nLANG = en_US.UTF-8\n']
262 [False, '[default]\nLANG = en_US.UTF-8\n']
263 ], ids=no_newline_id_generator)
263 ], ids=no_newline_id_generator)
264 def test_create_hooks_env(self, read_only, expected_content):
264 def test_create_hooks_env(self, read_only, expected_content):
265 wrapper = SubversionTunnelWrapper(timeout=5)
265 wrapper = SubversionTunnelWrapper(timeout=5)
266 wrapper.read_only = read_only
266 wrapper.read_only = read_only
267 file_mock = MagicMock(spec=file)
267 file_mock = MagicMock(spec=file)
268 with patch('os.fdopen', create=True) as open_mock:
268 with patch('os.fdopen', create=True) as open_mock:
269 open_mock.return_value = file_mock
269 open_mock.return_value = file_mock
270 wrapper.create_hooks_env()
270 wrapper.create_hooks_env()
271 open_mock.assert_called_once_with(wrapper.hooks_env_fd, 'w')
271 open_mock.assert_called_once_with(wrapper.hooks_env_fd, 'w')
272 file_handle = file_mock.__enter__.return_value
272 file_handle = file_mock.__enter__.return_value
273 file_handle.write.assert_called_once_with(expected_content)
273 file_handle.write.assert_called_once_with(expected_content)
274
274
275 def test_remove_configs(self):
275 def test_remove_configs(self):
276 wrapper = SubversionTunnelWrapper(timeout=5)
276 wrapper = SubversionTunnelWrapper(timeout=5)
277 with patch('os.remove') as remove_mock:
277 with patch('os.remove') as remove_mock:
278 wrapper.remove_configs()
278 wrapper.remove_configs()
279 expected_calls = [
279 expected_calls = [
280 call(wrapper.svn_conf_path), call(wrapper.hooks_env_path)]
280 call(wrapper.svn_conf_path), call(wrapper.hooks_env_path)]
281 assert sorted(remove_mock.call_args_list) == sorted(expected_calls)
281 assert sorted(remove_mock.call_args_list) == sorted(expected_calls)
282
282
283 def _poll(self):
283 def _poll(self):
284 self.counter += 1
284 self.counter += 1
285 return None if self.counter < 6 else 1
285 return None if self.counter < 6 else 1
@@ -1,119 +1,121 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import stat
22 import stat
23 import logging
23 import logging
24 import tempfile
24 import tempfile
25 import datetime
25 import datetime
26
26
27 from . import config_keys
27 from . import config_keys
28 from rhodecode.model.db import true, joinedload, User, UserSshKeys
28 from rhodecode.model.db import true, joinedload, User, UserSshKeys
29
29
30
30
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33 HEADER = \
33 HEADER = \
34 "# This file is managed by RhodeCode, please do not edit it manually. # \n" \
34 "# This file is managed by RhodeCode, please do not edit it manually. # \n" \
35 "# Current entries: {}, create date: UTC:{}.\n"
35 "# Current entries: {}, create date: UTC:{}.\n"
36
36
37 # Default SSH options for authorized_keys file, can be override via .ini
37 # Default SSH options for authorized_keys file, can be override via .ini
38 SSH_OPTS = 'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding'
38 SSH_OPTS = 'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding'
39
39
40
40
41 def get_all_active_keys():
41 def get_all_active_keys():
42 result = UserSshKeys.query() \
42 result = UserSshKeys.query() \
43 .options(joinedload(UserSshKeys.user)) \
43 .options(joinedload(UserSshKeys.user)) \
44 .filter(UserSshKeys.user != User.get_default_user()) \
44 .filter(UserSshKeys.user != User.get_default_user()) \
45 .filter(User.active == true()) \
45 .filter(User.active == true()) \
46 .all()
46 .all()
47 return result
47 return result
48
48
49
49
50 def _generate_ssh_authorized_keys_file(
50 def _generate_ssh_authorized_keys_file(
51 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts, debug):
51 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts, debug):
52
52
53 import rhodecode
53 import rhodecode
54 all_active_keys = get_all_active_keys()
54 all_active_keys = get_all_active_keys()
55
55
56 if allow_shell:
56 if allow_shell:
57 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --shell'
57 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --shell'
58 if debug:
58 if debug:
59 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --debug'
59 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --debug'
60
60
61 if not os.path.isfile(authorized_keys_file_path):
61 if not os.path.isfile(authorized_keys_file_path):
62 with open(authorized_keys_file_path, 'w'):
62 with open(authorized_keys_file_path, 'w'):
63 pass
63 pass
64
64
65 if not os.access(authorized_keys_file_path, os.R_OK):
65 if not os.access(authorized_keys_file_path, os.R_OK):
66 raise OSError('Access to file {} is without read access'.format(
66 raise OSError('Access to file {} is without read access'.format(
67 authorized_keys_file_path))
67 authorized_keys_file_path))
68
68
69 line_tmpl = '{ssh_opts},command="{wrapper_command} {ini_path} --user-id={user_id} --user={user}" {key}\n'
69 line_tmpl = '{ssh_opts},command="{wrapper_command} {ini_path} --user-id={user_id} --user={user} --key-id={user_key_id}" {key}\n'
70
70
71 fd, tmp_authorized_keys = tempfile.mkstemp(
71 fd, tmp_authorized_keys = tempfile.mkstemp(
72 '.authorized_keys_write',
72 '.authorized_keys_write',
73 dir=os.path.dirname(authorized_keys_file_path))
73 dir=os.path.dirname(authorized_keys_file_path))
74
74
75 now = datetime.datetime.utcnow().isoformat()
75 now = datetime.datetime.utcnow().isoformat()
76 keys_file = os.fdopen(fd, 'wb')
76 keys_file = os.fdopen(fd, 'wb')
77 keys_file.write(HEADER.format(len(all_active_keys), now))
77 keys_file.write(HEADER.format(len(all_active_keys), now))
78 ini_path = rhodecode.CONFIG['__file__']
78 ini_path = rhodecode.CONFIG['__file__']
79
79
80 for user_key in all_active_keys:
80 for user_key in all_active_keys:
81 username = user_key.user.username
81 username = user_key.user.username
82 user_id = user_key.user.user_id
82 user_id = user_key.user.user_id
83
83
84 keys_file.write(
84 keys_file.write(
85 line_tmpl.format(
85 line_tmpl.format(
86 ssh_opts=ssh_opts or SSH_OPTS,
86 ssh_opts=ssh_opts or SSH_OPTS,
87 wrapper_command=ssh_wrapper_cmd,
87 wrapper_command=ssh_wrapper_cmd,
88 ini_path=ini_path,
88 ini_path=ini_path,
89 user_id=user_id,
89 user_id=user_id,
90 user=username, key=user_key.ssh_key_data))
90 user=username,
91 user_key_id=user_key.ssh_key_id,
92 key=user_key.ssh_key_data))
91 log.debug('addkey: Key added for user: `%s`', username)
93 log.debug('addkey: Key added for user: `%s`', username)
92 keys_file.close()
94 keys_file.close()
93
95
94 # Explicitly setting read-only permissions to authorized_keys
96 # Explicitly setting read-only permissions to authorized_keys
95 os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
97 os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
96 # Rename is atomic operation
98 # Rename is atomic operation
97 os.rename(tmp_authorized_keys, authorized_keys_file_path)
99 os.rename(tmp_authorized_keys, authorized_keys_file_path)
98
100
99
101
100 def generate_ssh_authorized_keys_file(registry):
102 def generate_ssh_authorized_keys_file(registry):
101 log.info('Generating new authorized key file')
103 log.info('Generating new authorized key file')
102
104
103 authorized_keys_file_path = registry.settings.get(
105 authorized_keys_file_path = registry.settings.get(
104 config_keys.authorized_keys_file_path)
106 config_keys.authorized_keys_file_path)
105
107
106 ssh_wrapper_cmd = registry.settings.get(
108 ssh_wrapper_cmd = registry.settings.get(
107 config_keys.wrapper_cmd)
109 config_keys.wrapper_cmd)
108 allow_shell = registry.settings.get(
110 allow_shell = registry.settings.get(
109 config_keys.wrapper_allow_shell)
111 config_keys.wrapper_allow_shell)
110 ssh_opts = registry.settings.get(
112 ssh_opts = registry.settings.get(
111 config_keys.authorized_keys_line_ssh_opts)
113 config_keys.authorized_keys_line_ssh_opts)
112 debug = registry.settings.get(
114 debug = registry.settings.get(
113 config_keys.enable_debug_logging)
115 config_keys.enable_debug_logging)
114
116
115 _generate_ssh_authorized_keys_file(
117 _generate_ssh_authorized_keys_file(
116 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts,
118 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts,
117 debug)
119 debug)
118
120
119 return 0
121 return 0
@@ -1,777 +1,769 b''
1
1
2
2
3 ################################################################################
3 ################################################################################
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
4 ## RHODECODE COMMUNITY EDITION CONFIGURATION ##
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10
10
11 ################################################################################
11 ################################################################################
12 ## EMAIL CONFIGURATION ##
12 ## EMAIL CONFIGURATION ##
13 ## Uncomment and replace with the email address which should receive ##
13 ## Uncomment and replace with the email address which should receive ##
14 ## any error reports after an application crash ##
14 ## any error reports after an application crash ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
15 ## Additionally these settings will be used by the RhodeCode mailing system ##
16 ################################################################################
16 ################################################################################
17
17
18 ## prefix all emails subjects with given prefix, helps filtering out emails
18 ## prefix all emails subjects with given prefix, helps filtering out emails
19 #email_prefix = [RhodeCode]
19 #email_prefix = [RhodeCode]
20
20
21 ## email FROM address all mails will be sent
21 ## email FROM address all mails will be sent
22 #app_email_from = rhodecode-noreply@localhost
22 #app_email_from = rhodecode-noreply@localhost
23
23
24 ## Uncomment and replace with the address which should receive any error report
24 ## Uncomment and replace with the address which should receive any error report
25 ## note: using appenlight for error handling doesn't need this to be uncommented
25 ## note: using appenlight for error handling doesn't need this to be uncommented
26 #email_to = admin@localhost
26 #email_to = admin@localhost
27
27
28 ## in case of Application errors, sent an error email form
28 ## in case of Application errors, sent an error email form
29 #error_email_from = rhodecode_error@localhost
29 #error_email_from = rhodecode_error@localhost
30
30
31 ## additional error message to be send in case of server crash
31 ## additional error message to be send in case of server crash
32 #error_message =
32 #error_message =
33
33
34
34
35 #smtp_server = mail.server.com
35 #smtp_server = mail.server.com
36 #smtp_username =
36 #smtp_username =
37 #smtp_password =
37 #smtp_password =
38 #smtp_port =
38 #smtp_port =
39 #smtp_use_tls = false
39 #smtp_use_tls = false
40 #smtp_use_ssl = true
40 #smtp_use_ssl = true
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
41 ## Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
42 #smtp_auth =
42 #smtp_auth =
43
43
44 [server:main]
44 [server:main]
45 ## COMMON ##
45 ## COMMON ##
46 host = 0.0.0.0
46 host = 0.0.0.0
47 port = 5000
47 port = 5000
48
48
49 ##################################
49 ##################################
50 ## WAITRESS WSGI SERVER ##
50 ## WAITRESS WSGI SERVER ##
51 ## Recommended for Development ##
51 ## Recommended for Development ##
52 ##################################
52 ##################################
53
53
54 use = egg:waitress#main
54 use = egg:waitress#main
55 ## number of worker threads
55 ## number of worker threads
56 threads = 5
56 threads = 5
57 ## MAX BODY SIZE 100GB
57 ## MAX BODY SIZE 100GB
58 max_request_body_size = 107374182400
58 max_request_body_size = 107374182400
59 ## Use poll instead of select, fixes file descriptors limits problems.
59 ## Use poll instead of select, fixes file descriptors limits problems.
60 ## May not work on old windows systems.
60 ## May not work on old windows systems.
61 asyncore_use_poll = true
61 asyncore_use_poll = true
62
62
63
63
64 ##########################
64 ##########################
65 ## GUNICORN WSGI SERVER ##
65 ## GUNICORN WSGI SERVER ##
66 ##########################
66 ##########################
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
67 ## run with gunicorn --log-config rhodecode.ini --paste rhodecode.ini
68
68
69 #use = egg:gunicorn#main
69 #use = egg:gunicorn#main
70 ## Sets the number of process workers. You must set `instance_id = *`
70 ## Sets the number of process workers. You must set `instance_id = *`
71 ## when this option is set to more than one worker, recommended
71 ## when this option is set to more than one worker, recommended
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
72 ## value is (2 * NUMBER_OF_CPUS + 1), eg 2CPU = 5 workers
73 ## The `instance_id = *` must be set in the [app:main] section below
73 ## The `instance_id = *` must be set in the [app:main] section below
74 #workers = 2
74 #workers = 2
75 ## number of threads for each of the worker, must be set to 1 for gevent
75 ## number of threads for each of the worker, must be set to 1 for gevent
76 ## generally recommened to be at 1
76 ## generally recommened to be at 1
77 #threads = 1
77 #threads = 1
78 ## process name
78 ## process name
79 #proc_name = rhodecode
79 #proc_name = rhodecode
80 ## type of worker class, one of sync, gevent
80 ## type of worker class, one of sync, gevent
81 ## recommended for bigger setup is using of of other than sync one
81 ## recommended for bigger setup is using of of other than sync one
82 #worker_class = sync
82 #worker_class = sync
83 ## The maximum number of simultaneous clients. Valid only for Gevent
83 ## The maximum number of simultaneous clients. Valid only for Gevent
84 #worker_connections = 10
84 #worker_connections = 10
85 ## max number of requests that worker will handle before being gracefully
85 ## max number of requests that worker will handle before being gracefully
86 ## restarted, could prevent memory leaks
86 ## restarted, could prevent memory leaks
87 #max_requests = 1000
87 #max_requests = 1000
88 #max_requests_jitter = 30
88 #max_requests_jitter = 30
89 ## amount of time a worker can spend with handling a request before it
89 ## amount of time a worker can spend with handling a request before it
90 ## gets killed and restarted. Set to 6hrs
90 ## gets killed and restarted. Set to 6hrs
91 #timeout = 21600
91 #timeout = 21600
92
92
93 ## UWSGI ##
93 ## UWSGI ##
94 ## run with uwsgi --ini-paste-logged <inifile.ini>
94 ## run with uwsgi --ini-paste-logged <inifile.ini>
95 #[uwsgi]
95 #[uwsgi]
96 #socket = /tmp/uwsgi.sock
96 #socket = /tmp/uwsgi.sock
97 #master = true
97 #master = true
98 #http = 127.0.0.1:5000
98 #http = 127.0.0.1:5000
99
99
100 ## set as deamon and redirect all output to file
100 ## set as deamon and redirect all output to file
101 #daemonize = ./uwsgi_rhodecode.log
101 #daemonize = ./uwsgi_rhodecode.log
102
102
103 ## master process PID
103 ## master process PID
104 #pidfile = ./uwsgi_rhodecode.pid
104 #pidfile = ./uwsgi_rhodecode.pid
105
105
106 ## stats server with workers statistics, use uwsgitop
106 ## stats server with workers statistics, use uwsgitop
107 ## for monitoring, `uwsgitop 127.0.0.1:1717`
107 ## for monitoring, `uwsgitop 127.0.0.1:1717`
108 #stats = 127.0.0.1:1717
108 #stats = 127.0.0.1:1717
109 #memory-report = true
109 #memory-report = true
110
110
111 ## log 5XX errors
111 ## log 5XX errors
112 #log-5xx = true
112 #log-5xx = true
113
113
114 ## Set the socket listen queue size.
114 ## Set the socket listen queue size.
115 #listen = 256
115 #listen = 256
116
116
117 ## Gracefully Reload workers after the specified amount of managed requests
117 ## Gracefully Reload workers after the specified amount of managed requests
118 ## (avoid memory leaks).
118 ## (avoid memory leaks).
119 #max-requests = 1000
119 #max-requests = 1000
120
120
121 ## enable large buffers
121 ## enable large buffers
122 #buffer-size=65535
122 #buffer-size=65535
123
123
124 ## socket and http timeouts ##
124 ## socket and http timeouts ##
125 #http-timeout=3600
125 #http-timeout=3600
126 #socket-timeout=3600
126 #socket-timeout=3600
127
127
128 ## Log requests slower than the specified number of milliseconds.
128 ## Log requests slower than the specified number of milliseconds.
129 #log-slow = 10
129 #log-slow = 10
130
130
131 ## Exit if no app can be loaded.
131 ## Exit if no app can be loaded.
132 #need-app = true
132 #need-app = true
133
133
134 ## Set lazy mode (load apps in workers instead of master).
134 ## Set lazy mode (load apps in workers instead of master).
135 #lazy = true
135 #lazy = true
136
136
137 ## scaling ##
137 ## scaling ##
138 ## set cheaper algorithm to use, if not set default will be used
138 ## set cheaper algorithm to use, if not set default will be used
139 #cheaper-algo = spare
139 #cheaper-algo = spare
140
140
141 ## minimum number of workers to keep at all times
141 ## minimum number of workers to keep at all times
142 #cheaper = 1
142 #cheaper = 1
143
143
144 ## number of workers to spawn at startup
144 ## number of workers to spawn at startup
145 #cheaper-initial = 1
145 #cheaper-initial = 1
146
146
147 ## maximum number of workers that can be spawned
147 ## maximum number of workers that can be spawned
148 #workers = 4
148 #workers = 4
149
149
150 ## how many workers should be spawned at a time
150 ## how many workers should be spawned at a time
151 #cheaper-step = 1
151 #cheaper-step = 1
152
152
153 ## prefix middleware for RhodeCode.
153 ## prefix middleware for RhodeCode.
154 ## recommended when using proxy setup.
154 ## recommended when using proxy setup.
155 ## allows to set RhodeCode under a prefix in server.
155 ## allows to set RhodeCode under a prefix in server.
156 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
156 ## eg https://server.com/custom_prefix. Enable `filter-with =` option below as well.
157 ## And set your prefix like: `prefix = /custom_prefix`
157 ## And set your prefix like: `prefix = /custom_prefix`
158 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
158 ## be sure to also set beaker.session.cookie_path = /custom_prefix if you need
159 ## to make your cookies only work on prefix url
159 ## to make your cookies only work on prefix url
160 [filter:proxy-prefix]
160 [filter:proxy-prefix]
161 use = egg:PasteDeploy#prefix
161 use = egg:PasteDeploy#prefix
162 prefix = /
162 prefix = /
163
163
164 [app:main]
164 [app:main]
165 is_test = True
165 is_test = True
166 use = egg:rhodecode-enterprise-ce
166 use = egg:rhodecode-enterprise-ce
167
167
168 ## enable proxy prefix middleware, defined above
168 ## enable proxy prefix middleware, defined above
169 #filter-with = proxy-prefix
169 #filter-with = proxy-prefix
170
170
171
171
172 ## RHODECODE PLUGINS ##
172 ## RHODECODE PLUGINS ##
173 rhodecode.includes = rhodecode.api
173 rhodecode.includes = rhodecode.api
174
174
175 # api prefix url
175 # api prefix url
176 rhodecode.api.url = /_admin/api
176 rhodecode.api.url = /_admin/api
177
177
178
178
179 ## END RHODECODE PLUGINS ##
179 ## END RHODECODE PLUGINS ##
180
180
181 ## encryption key used to encrypt social plugin tokens,
181 ## encryption key used to encrypt social plugin tokens,
182 ## remote_urls with credentials etc, if not set it defaults to
182 ## remote_urls with credentials etc, if not set it defaults to
183 ## `beaker.session.secret`
183 ## `beaker.session.secret`
184 #rhodecode.encrypted_values.secret =
184 #rhodecode.encrypted_values.secret =
185
185
186 ## decryption strict mode (enabled by default). It controls if decryption raises
186 ## decryption strict mode (enabled by default). It controls if decryption raises
187 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
187 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
188 #rhodecode.encrypted_values.strict = false
188 #rhodecode.encrypted_values.strict = false
189
189
190 ## return gzipped responses from Rhodecode (static files/application)
190 ## return gzipped responses from Rhodecode (static files/application)
191 gzip_responses = false
191 gzip_responses = false
192
192
193 ## autogenerate javascript routes file on startup
193 ## autogenerate javascript routes file on startup
194 generate_js_files = false
194 generate_js_files = false
195
195
196 ## Optional Languages
196 ## Optional Languages
197 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
197 ## en(default), be, de, es, fr, it, ja, pl, pt, ru, zh
198 lang = en
198 lang = en
199
199
200 ## perform a full repository scan on each server start, this should be
200 ## perform a full repository scan on each server start, this should be
201 ## set to false after first startup, to allow faster server restarts.
201 ## set to false after first startup, to allow faster server restarts.
202 startup.import_repos = true
202 startup.import_repos = true
203
203
204 ## Uncomment and set this path to use archive download cache.
204 ## Uncomment and set this path to use archive download cache.
205 ## Once enabled, generated archives will be cached at this location
205 ## Once enabled, generated archives will be cached at this location
206 ## and served from the cache during subsequent requests for the same archive of
206 ## and served from the cache during subsequent requests for the same archive of
207 ## the repository.
207 ## the repository.
208 #archive_cache_dir = /tmp/tarballcache
208 #archive_cache_dir = /tmp/tarballcache
209
209
210 ## change this to unique ID for security
210 ## change this to unique ID for security
211 app_instance_uuid = rc-production
211 app_instance_uuid = rc-production
212
212
213 ## cut off limit for large diffs (size in bytes)
213 ## cut off limit for large diffs (size in bytes)
214 cut_off_limit_diff = 1024000
214 cut_off_limit_diff = 1024000
215 cut_off_limit_file = 256000
215 cut_off_limit_file = 256000
216
216
217 ## use cache version of scm repo everywhere
217 ## use cache version of scm repo everywhere
218 vcs_full_cache = false
218 vcs_full_cache = false
219
219
220 ## force https in RhodeCode, fixes https redirects, assumes it's always https
220 ## force https in RhodeCode, fixes https redirects, assumes it's always https
221 ## Normally this is controlled by proper http flags sent from http server
221 ## Normally this is controlled by proper http flags sent from http server
222 force_https = false
222 force_https = false
223
223
224 ## use Strict-Transport-Security headers
224 ## use Strict-Transport-Security headers
225 use_htsts = false
225 use_htsts = false
226
226
227 ## number of commits stats will parse on each iteration
227 ## number of commits stats will parse on each iteration
228 commit_parse_limit = 25
228 commit_parse_limit = 25
229
229
230 ## git rev filter option, --all is the default filter, if you need to
230 ## git rev filter option, --all is the default filter, if you need to
231 ## hide all refs in changelog switch this to --branches --tags
231 ## hide all refs in changelog switch this to --branches --tags
232 git_rev_filter = --all
232 git_rev_filter = --all
233
233
234 # Set to true if your repos are exposed using the dumb protocol
234 # Set to true if your repos are exposed using the dumb protocol
235 git_update_server_info = false
235 git_update_server_info = false
236
236
237 ## RSS/ATOM feed options
237 ## RSS/ATOM feed options
238 rss_cut_off_limit = 256000
238 rss_cut_off_limit = 256000
239 rss_items_per_page = 10
239 rss_items_per_page = 10
240 rss_include_diff = false
240 rss_include_diff = false
241
241
242 ## gist URL alias, used to create nicer urls for gist. This should be an
242 ## gist URL alias, used to create nicer urls for gist. This should be an
243 ## url that does rewrites to _admin/gists/{gistid}.
243 ## url that does rewrites to _admin/gists/{gistid}.
244 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
244 ## example: http://gist.rhodecode.org/{gistid}. Empty means use the internal
245 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
245 ## RhodeCode url, ie. http[s]://rhodecode.server/_admin/gists/{gistid}
246 gist_alias_url =
246 gist_alias_url =
247
247
248 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
248 ## List of views (using glob pattern syntax) that AUTH TOKENS could be
249 ## used for access.
249 ## used for access.
250 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
250 ## Adding ?auth_token=TOKEN_HASH to the url authenticates this request as if it
251 ## came from the the logged in user who own this authentication token.
251 ## came from the the logged in user who own this authentication token.
252 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
252 ## Additionally @TOKEN syntaxt can be used to bound the view to specific
253 ## authentication token. Such view would be only accessible when used together
253 ## authentication token. Such view would be only accessible when used together
254 ## with this authentication token
254 ## with this authentication token
255 ##
255 ##
256 ## list of all views can be found under `/_admin/permissions/auth_token_access`
256 ## list of all views can be found under `/_admin/permissions/auth_token_access`
257 ## The list should be "," separated and on a single line.
257 ## The list should be "," separated and on a single line.
258 ##
258 ##
259 ## Most common views to enable:
259 ## Most common views to enable:
260 # RepoCommitsView:repo_commit_download
260 # RepoCommitsView:repo_commit_download
261 # RepoCommitsView:repo_commit_patch
261 # RepoCommitsView:repo_commit_patch
262 # RepoCommitsView:repo_commit_raw
262 # RepoCommitsView:repo_commit_raw
263 # RepoCommitsView:repo_commit_raw@TOKEN
263 # RepoCommitsView:repo_commit_raw@TOKEN
264 # RepoFilesView:repo_files_diff
264 # RepoFilesView:repo_files_diff
265 # RepoFilesView:repo_archivefile
265 # RepoFilesView:repo_archivefile
266 # RepoFilesView:repo_file_raw
266 # RepoFilesView:repo_file_raw
267 # GistView:*
267 # GistView:*
268 api_access_controllers_whitelist =
268 api_access_controllers_whitelist =
269
269
270 ## default encoding used to convert from and to unicode
270 ## default encoding used to convert from and to unicode
271 ## can be also a comma separated list of encoding in case of mixed encodings
271 ## can be also a comma separated list of encoding in case of mixed encodings
272 default_encoding = UTF-8
272 default_encoding = UTF-8
273
273
274 ## instance-id prefix
274 ## instance-id prefix
275 ## a prefix key for this instance used for cache invalidation when running
275 ## a prefix key for this instance used for cache invalidation when running
276 ## multiple instances of rhodecode, make sure it's globally unique for
276 ## multiple instances of rhodecode, make sure it's globally unique for
277 ## all running rhodecode instances. Leave empty if you don't use it
277 ## all running rhodecode instances. Leave empty if you don't use it
278 instance_id =
278 instance_id =
279
279
280 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
280 ## Fallback authentication plugin. Set this to a plugin ID to force the usage
281 ## of an authentication plugin also if it is disabled by it's settings.
281 ## of an authentication plugin also if it is disabled by it's settings.
282 ## This could be useful if you are unable to log in to the system due to broken
282 ## This could be useful if you are unable to log in to the system due to broken
283 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
283 ## authentication settings. Then you can enable e.g. the internal rhodecode auth
284 ## module to log in again and fix the settings.
284 ## module to log in again and fix the settings.
285 ##
285 ##
286 ## Available builtin plugin IDs (hash is part of the ID):
286 ## Available builtin plugin IDs (hash is part of the ID):
287 ## egg:rhodecode-enterprise-ce#rhodecode
287 ## egg:rhodecode-enterprise-ce#rhodecode
288 ## egg:rhodecode-enterprise-ce#pam
288 ## egg:rhodecode-enterprise-ce#pam
289 ## egg:rhodecode-enterprise-ce#ldap
289 ## egg:rhodecode-enterprise-ce#ldap
290 ## egg:rhodecode-enterprise-ce#jasig_cas
290 ## egg:rhodecode-enterprise-ce#jasig_cas
291 ## egg:rhodecode-enterprise-ce#headers
291 ## egg:rhodecode-enterprise-ce#headers
292 ## egg:rhodecode-enterprise-ce#crowd
292 ## egg:rhodecode-enterprise-ce#crowd
293 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
293 #rhodecode.auth_plugin_fallback = egg:rhodecode-enterprise-ce#rhodecode
294
294
295 ## alternative return HTTP header for failed authentication. Default HTTP
295 ## alternative return HTTP header for failed authentication. Default HTTP
296 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
296 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
297 ## handling that causing a series of failed authentication calls.
297 ## handling that causing a series of failed authentication calls.
298 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
298 ## Set this variable to 403 to return HTTPForbidden, or any other HTTP code
299 ## This will be served instead of default 401 on bad authnetication
299 ## This will be served instead of default 401 on bad authnetication
300 auth_ret_code =
300 auth_ret_code =
301
301
302 ## use special detection method when serving auth_ret_code, instead of serving
302 ## use special detection method when serving auth_ret_code, instead of serving
303 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
303 ## ret_code directly, use 401 initially (Which triggers credentials prompt)
304 ## and then serve auth_ret_code to clients
304 ## and then serve auth_ret_code to clients
305 auth_ret_code_detection = false
305 auth_ret_code_detection = false
306
306
307 ## locking return code. When repository is locked return this HTTP code. 2XX
307 ## locking return code. When repository is locked return this HTTP code. 2XX
308 ## codes don't break the transactions while 4XX codes do
308 ## codes don't break the transactions while 4XX codes do
309 lock_ret_code = 423
309 lock_ret_code = 423
310
310
311 ## allows to change the repository location in settings page
311 ## allows to change the repository location in settings page
312 allow_repo_location_change = true
312 allow_repo_location_change = true
313
313
314 ## allows to setup custom hooks in settings page
314 ## allows to setup custom hooks in settings page
315 allow_custom_hooks_settings = true
315 allow_custom_hooks_settings = true
316
316
317 ## generated license token, goto license page in RhodeCode settings to obtain
317 ## generated license token, goto license page in RhodeCode settings to obtain
318 ## new token
318 ## new token
319 license_token = abra-cada-bra1-rce3
319 license_token = abra-cada-bra1-rce3
320
320
321 ## supervisor connection uri, for managing supervisor and logs.
321 ## supervisor connection uri, for managing supervisor and logs.
322 supervisor.uri =
322 supervisor.uri =
323 ## supervisord group name/id we only want this RC instance to handle
323 ## supervisord group name/id we only want this RC instance to handle
324 supervisor.group_id = dev
324 supervisor.group_id = dev
325
325
326 ## Display extended labs settings
326 ## Display extended labs settings
327 labs_settings_active = true
327 labs_settings_active = true
328
328
329 ####################################
329 ####################################
330 ### CELERY CONFIG ####
330 ### CELERY CONFIG ####
331 ####################################
331 ####################################
332 use_celery = false
332 use_celery = false
333 broker.host = localhost
333 broker.host = localhost
334 broker.vhost = rabbitmqhost
334 broker.vhost = rabbitmqhost
335 broker.port = 5672
335 broker.port = 5672
336 broker.user = rabbitmq
336 broker.user = rabbitmq
337 broker.password = qweqwe
337 broker.password = qweqwe
338
338
339 celery.imports = rhodecode.lib.celerylib.tasks
339 celery.imports = rhodecode.lib.celerylib.tasks
340
340
341 celery.result.backend = amqp
341 celery.result.backend = amqp
342 celery.result.dburi = amqp://
342 celery.result.dburi = amqp://
343 celery.result.serialier = json
343 celery.result.serialier = json
344
344
345 #celery.send.task.error.emails = true
345 #celery.send.task.error.emails = true
346 #celery.amqp.task.result.expires = 18000
346 #celery.amqp.task.result.expires = 18000
347
347
348 celeryd.concurrency = 2
348 celeryd.concurrency = 2
349 #celeryd.log.file = celeryd.log
349 #celeryd.log.file = celeryd.log
350 celeryd.log.level = debug
350 celeryd.log.level = debug
351 celeryd.max.tasks.per.child = 1
351 celeryd.max.tasks.per.child = 1
352
352
353 ## tasks will never be sent to the queue, but executed locally instead.
353 ## tasks will never be sent to the queue, but executed locally instead.
354 celery.always.eager = false
354 celery.always.eager = false
355
355
356 ####################################
356 ####################################
357 ### BEAKER CACHE ####
357 ### BEAKER CACHE ####
358 ####################################
358 ####################################
359 # default cache dir for templates. Putting this into a ramdisk
359 # default cache dir for templates. Putting this into a ramdisk
360 ## can boost performance, eg. %(here)s/data_ramdisk
360 ## can boost performance, eg. %(here)s/data_ramdisk
361 cache_dir = %(here)s/data
361 cache_dir = %(here)s/data
362
362
363 ## locking and default file storage for Beaker. Putting this into a ramdisk
363 ## locking and default file storage for Beaker. Putting this into a ramdisk
364 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
364 ## can boost performance, eg. %(here)s/data_ramdisk/cache/beaker_data
365 beaker.cache.data_dir = %(here)s/rc/data/cache/beaker_data
365 beaker.cache.data_dir = %(here)s/rc/data/cache/beaker_data
366 beaker.cache.lock_dir = %(here)s/rc/data/cache/beaker_lock
366 beaker.cache.lock_dir = %(here)s/rc/data/cache/beaker_lock
367
367
368 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
368 beaker.cache.regions = super_short_term, short_term, long_term, sql_cache_short, auth_plugins, repo_cache_long
369
369
370 beaker.cache.super_short_term.type = memory
370 beaker.cache.super_short_term.type = memory
371 beaker.cache.super_short_term.expire = 1
371 beaker.cache.super_short_term.expire = 1
372 beaker.cache.super_short_term.key_length = 256
372 beaker.cache.super_short_term.key_length = 256
373
373
374 beaker.cache.short_term.type = memory
374 beaker.cache.short_term.type = memory
375 beaker.cache.short_term.expire = 60
375 beaker.cache.short_term.expire = 60
376 beaker.cache.short_term.key_length = 256
376 beaker.cache.short_term.key_length = 256
377
377
378 beaker.cache.long_term.type = memory
378 beaker.cache.long_term.type = memory
379 beaker.cache.long_term.expire = 36000
379 beaker.cache.long_term.expire = 36000
380 beaker.cache.long_term.key_length = 256
380 beaker.cache.long_term.key_length = 256
381
381
382 beaker.cache.sql_cache_short.type = memory
382 beaker.cache.sql_cache_short.type = memory
383 beaker.cache.sql_cache_short.expire = 1
383 beaker.cache.sql_cache_short.expire = 1
384 beaker.cache.sql_cache_short.key_length = 256
384 beaker.cache.sql_cache_short.key_length = 256
385
385
386 ## default is memory cache, configure only if required
386 ## default is memory cache, configure only if required
387 ## using multi-node or multi-worker setup
387 ## using multi-node or multi-worker setup
388 #beaker.cache.auth_plugins.type = ext:database
388 #beaker.cache.auth_plugins.type = ext:database
389 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
389 #beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
390 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
390 #beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
391 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
391 #beaker.cache.auth_plugins.url = mysql://root:secret@127.0.0.1/rhodecode
392 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
392 #beaker.cache.auth_plugins.sa.pool_recycle = 3600
393 #beaker.cache.auth_plugins.sa.pool_size = 10
393 #beaker.cache.auth_plugins.sa.pool_size = 10
394 #beaker.cache.auth_plugins.sa.max_overflow = 0
394 #beaker.cache.auth_plugins.sa.max_overflow = 0
395
395
396 beaker.cache.repo_cache_long.type = memorylru_base
396 beaker.cache.repo_cache_long.type = memorylru_base
397 beaker.cache.repo_cache_long.max_items = 4096
397 beaker.cache.repo_cache_long.max_items = 4096
398 beaker.cache.repo_cache_long.expire = 2592000
398 beaker.cache.repo_cache_long.expire = 2592000
399
399
400 ## default is memorylru_base cache, configure only if required
400 ## default is memorylru_base cache, configure only if required
401 ## using multi-node or multi-worker setup
401 ## using multi-node or multi-worker setup
402 #beaker.cache.repo_cache_long.type = ext:memcached
402 #beaker.cache.repo_cache_long.type = ext:memcached
403 #beaker.cache.repo_cache_long.url = localhost:11211
403 #beaker.cache.repo_cache_long.url = localhost:11211
404 #beaker.cache.repo_cache_long.expire = 1209600
404 #beaker.cache.repo_cache_long.expire = 1209600
405 #beaker.cache.repo_cache_long.key_length = 256
405 #beaker.cache.repo_cache_long.key_length = 256
406
406
407 ####################################
407 ####################################
408 ### BEAKER SESSION ####
408 ### BEAKER SESSION ####
409 ####################################
409 ####################################
410
410
411 ## .session.type is type of storage options for the session, current allowed
411 ## .session.type is type of storage options for the session, current allowed
412 ## types are file, ext:memcached, ext:database, and memory (default).
412 ## types are file, ext:memcached, ext:database, and memory (default).
413 beaker.session.type = file
413 beaker.session.type = file
414 beaker.session.data_dir = %(here)s/rc/data/sessions/data
414 beaker.session.data_dir = %(here)s/rc/data/sessions/data
415
415
416 ## db based session, fast, and allows easy management over logged in users
416 ## db based session, fast, and allows easy management over logged in users
417 #beaker.session.type = ext:database
417 #beaker.session.type = ext:database
418 #beaker.session.table_name = db_session
418 #beaker.session.table_name = db_session
419 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
419 #beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
420 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
420 #beaker.session.sa.url = mysql://root:secret@127.0.0.1/rhodecode
421 #beaker.session.sa.pool_recycle = 3600
421 #beaker.session.sa.pool_recycle = 3600
422 #beaker.session.sa.echo = false
422 #beaker.session.sa.echo = false
423
423
424 beaker.session.key = rhodecode
424 beaker.session.key = rhodecode
425 beaker.session.secret = test-rc-uytcxaz
425 beaker.session.secret = test-rc-uytcxaz
426 beaker.session.lock_dir = %(here)s/rc/data/sessions/lock
426 beaker.session.lock_dir = %(here)s/rc/data/sessions/lock
427
427
428 ## Secure encrypted cookie. Requires AES and AES python libraries
428 ## Secure encrypted cookie. Requires AES and AES python libraries
429 ## you must disable beaker.session.secret to use this
429 ## you must disable beaker.session.secret to use this
430 #beaker.session.encrypt_key = key_for_encryption
430 #beaker.session.encrypt_key = key_for_encryption
431 #beaker.session.validate_key = validation_key
431 #beaker.session.validate_key = validation_key
432
432
433 ## sets session as invalid(also logging out user) if it haven not been
433 ## sets session as invalid(also logging out user) if it haven not been
434 ## accessed for given amount of time in seconds
434 ## accessed for given amount of time in seconds
435 beaker.session.timeout = 2592000
435 beaker.session.timeout = 2592000
436 beaker.session.httponly = true
436 beaker.session.httponly = true
437 ## Path to use for the cookie. Set to prefix if you use prefix middleware
437 ## Path to use for the cookie. Set to prefix if you use prefix middleware
438 #beaker.session.cookie_path = /custom_prefix
438 #beaker.session.cookie_path = /custom_prefix
439
439
440 ## uncomment for https secure cookie
440 ## uncomment for https secure cookie
441 beaker.session.secure = false
441 beaker.session.secure = false
442
442
443 ## auto save the session to not to use .save()
443 ## auto save the session to not to use .save()
444 beaker.session.auto = false
444 beaker.session.auto = false
445
445
446 ## default cookie expiration time in seconds, set to `true` to set expire
446 ## default cookie expiration time in seconds, set to `true` to set expire
447 ## at browser close
447 ## at browser close
448 #beaker.session.cookie_expires = 3600
448 #beaker.session.cookie_expires = 3600
449
449
450 ###################################
450 ###################################
451 ## SEARCH INDEXING CONFIGURATION ##
451 ## SEARCH INDEXING CONFIGURATION ##
452 ###################################
452 ###################################
453 ## Full text search indexer is available in rhodecode-tools under
453 ## Full text search indexer is available in rhodecode-tools under
454 ## `rhodecode-tools index` command
454 ## `rhodecode-tools index` command
455
455
456 ## WHOOSH Backend, doesn't require additional services to run
456 ## WHOOSH Backend, doesn't require additional services to run
457 ## it works good with few dozen repos
457 ## it works good with few dozen repos
458 search.module = rhodecode.lib.index.whoosh
458 search.module = rhodecode.lib.index.whoosh
459 search.location = %(here)s/data/index
459 search.location = %(here)s/data/index
460
460
461 ########################################
461 ########################################
462 ### CHANNELSTREAM CONFIG ####
462 ### CHANNELSTREAM CONFIG ####
463 ########################################
463 ########################################
464 ## channelstream enables persistent connections and live notification
464 ## channelstream enables persistent connections and live notification
465 ## in the system. It's also used by the chat system
465 ## in the system. It's also used by the chat system
466
466
467 channelstream.enabled = false
467 channelstream.enabled = false
468
468
469 ## server address for channelstream server on the backend
469 ## server address for channelstream server on the backend
470 channelstream.server = 127.0.0.1:9800
470 channelstream.server = 127.0.0.1:9800
471 ## location of the channelstream server from outside world
471 ## location of the channelstream server from outside world
472 ## use ws:// for http or wss:// for https. This address needs to be handled
472 ## use ws:// for http or wss:// for https. This address needs to be handled
473 ## by external HTTP server such as Nginx or Apache
473 ## by external HTTP server such as Nginx or Apache
474 ## see nginx/apache configuration examples in our docs
474 ## see nginx/apache configuration examples in our docs
475 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
475 channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
476 channelstream.secret = secret
476 channelstream.secret = secret
477 channelstream.history.location = %(here)s/channelstream_history
477 channelstream.history.location = %(here)s/channelstream_history
478
478
479 ## Internal application path that Javascript uses to connect into.
479 ## Internal application path that Javascript uses to connect into.
480 ## If you use proxy-prefix the prefix should be added before /_channelstream
480 ## If you use proxy-prefix the prefix should be added before /_channelstream
481 channelstream.proxy_path = /_channelstream
481 channelstream.proxy_path = /_channelstream
482
482
483
483
484 ###################################
484 ###################################
485 ## APPENLIGHT CONFIG ##
485 ## APPENLIGHT CONFIG ##
486 ###################################
486 ###################################
487
487
488 ## Appenlight is tailored to work with RhodeCode, see
488 ## Appenlight is tailored to work with RhodeCode, see
489 ## http://appenlight.com for details how to obtain an account
489 ## http://appenlight.com for details how to obtain an account
490
490
491 ## appenlight integration enabled
491 ## appenlight integration enabled
492 appenlight = false
492 appenlight = false
493
493
494 appenlight.server_url = https://api.appenlight.com
494 appenlight.server_url = https://api.appenlight.com
495 appenlight.api_key = YOUR_API_KEY
495 appenlight.api_key = YOUR_API_KEY
496 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
496 #appenlight.transport_config = https://api.appenlight.com?threaded=1&timeout=5
497
497
498 # used for JS client
498 # used for JS client
499 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
499 appenlight.api_public_key = YOUR_API_PUBLIC_KEY
500
500
501 ## TWEAK AMOUNT OF INFO SENT HERE
501 ## TWEAK AMOUNT OF INFO SENT HERE
502
502
503 ## enables 404 error logging (default False)
503 ## enables 404 error logging (default False)
504 appenlight.report_404 = false
504 appenlight.report_404 = false
505
505
506 ## time in seconds after request is considered being slow (default 1)
506 ## time in seconds after request is considered being slow (default 1)
507 appenlight.slow_request_time = 1
507 appenlight.slow_request_time = 1
508
508
509 ## record slow requests in application
509 ## record slow requests in application
510 ## (needs to be enabled for slow datastore recording and time tracking)
510 ## (needs to be enabled for slow datastore recording and time tracking)
511 appenlight.slow_requests = true
511 appenlight.slow_requests = true
512
512
513 ## enable hooking to application loggers
513 ## enable hooking to application loggers
514 appenlight.logging = true
514 appenlight.logging = true
515
515
516 ## minimum log level for log capture
516 ## minimum log level for log capture
517 appenlight.logging.level = WARNING
517 appenlight.logging.level = WARNING
518
518
519 ## send logs only from erroneous/slow requests
519 ## send logs only from erroneous/slow requests
520 ## (saves API quota for intensive logging)
520 ## (saves API quota for intensive logging)
521 appenlight.logging_on_error = false
521 appenlight.logging_on_error = false
522
522
523 ## list of additonal keywords that should be grabbed from environ object
523 ## list of additonal keywords that should be grabbed from environ object
524 ## can be string with comma separated list of words in lowercase
524 ## can be string with comma separated list of words in lowercase
525 ## (by default client will always send following info:
525 ## (by default client will always send following info:
526 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
526 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
527 ## start with HTTP* this list be extended with additional keywords here
527 ## start with HTTP* this list be extended with additional keywords here
528 appenlight.environ_keys_whitelist =
528 appenlight.environ_keys_whitelist =
529
529
530 ## list of keywords that should be blanked from request object
530 ## list of keywords that should be blanked from request object
531 ## can be string with comma separated list of words in lowercase
531 ## can be string with comma separated list of words in lowercase
532 ## (by default client will always blank keys that contain following words
532 ## (by default client will always blank keys that contain following words
533 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
533 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
534 ## this list be extended with additional keywords set here
534 ## this list be extended with additional keywords set here
535 appenlight.request_keys_blacklist =
535 appenlight.request_keys_blacklist =
536
536
537 ## list of namespaces that should be ignores when gathering log entries
537 ## list of namespaces that should be ignores when gathering log entries
538 ## can be string with comma separated list of namespaces
538 ## can be string with comma separated list of namespaces
539 ## (by default the client ignores own entries: appenlight_client.client)
539 ## (by default the client ignores own entries: appenlight_client.client)
540 appenlight.log_namespace_blacklist =
540 appenlight.log_namespace_blacklist =
541
541
542
542
543 ################################################################################
543 ################################################################################
544 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
544 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
545 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
545 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
546 ## execute malicious code after an exception is raised. ##
546 ## execute malicious code after an exception is raised. ##
547 ################################################################################
547 ################################################################################
548 set debug = false
548 set debug = false
549
549
550
550
551 ##############
551 ##############
552 ## STYLING ##
552 ## STYLING ##
553 ##############
553 ##############
554 debug_style = false
554 debug_style = false
555
555
556 ###########################################
556 ###########################################
557 ### MAIN RHODECODE DATABASE CONFIG ###
557 ### MAIN RHODECODE DATABASE CONFIG ###
558 ###########################################
558 ###########################################
559 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
559 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
560 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
560 #sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode_test
561 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
561 #sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode_test
562 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
562 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode_test.db?timeout=30
563
563
564 # see sqlalchemy docs for other advanced settings
564 # see sqlalchemy docs for other advanced settings
565
565
566 ## print the sql statements to output
566 ## print the sql statements to output
567 sqlalchemy.db1.echo = false
567 sqlalchemy.db1.echo = false
568 ## recycle the connections after this amount of seconds
568 ## recycle the connections after this amount of seconds
569 sqlalchemy.db1.pool_recycle = 3600
569 sqlalchemy.db1.pool_recycle = 3600
570 sqlalchemy.db1.convert_unicode = true
570 sqlalchemy.db1.convert_unicode = true
571
571
572 ## the number of connections to keep open inside the connection pool.
572 ## the number of connections to keep open inside the connection pool.
573 ## 0 indicates no limit
573 ## 0 indicates no limit
574 #sqlalchemy.db1.pool_size = 5
574 #sqlalchemy.db1.pool_size = 5
575
575
576 ## the number of connections to allow in connection pool "overflow", that is
576 ## the number of connections to allow in connection pool "overflow", that is
577 ## connections that can be opened above and beyond the pool_size setting,
577 ## connections that can be opened above and beyond the pool_size setting,
578 ## which defaults to five.
578 ## which defaults to five.
579 #sqlalchemy.db1.max_overflow = 10
579 #sqlalchemy.db1.max_overflow = 10
580
580
581
581
582 ##################
582 ##################
583 ### VCS CONFIG ###
583 ### VCS CONFIG ###
584 ##################
584 ##################
585 vcs.server.enable = true
585 vcs.server.enable = true
586 vcs.server = localhost:9901
586 vcs.server = localhost:9901
587
587
588 ## Web server connectivity protocol, responsible for web based VCS operatations
588 ## Web server connectivity protocol, responsible for web based VCS operatations
589 ## Available protocols are:
589 ## Available protocols are:
590 ## `http` - use http-rpc backend (default)
590 ## `http` - use http-rpc backend (default)
591 vcs.server.protocol = http
591 vcs.server.protocol = http
592
592
593 ## Push/Pull operations protocol, available options are:
593 ## Push/Pull operations protocol, available options are:
594 ## `http` - use http-rpc backend (default)
594 ## `http` - use http-rpc backend (default)
595 ## `vcsserver.scm_app` - internal app (EE only)
595 ## `vcsserver.scm_app` - internal app (EE only)
596 vcs.scm_app_implementation = http
596 vcs.scm_app_implementation = http
597
597
598 ## Push/Pull operations hooks protocol, available options are:
598 ## Push/Pull operations hooks protocol, available options are:
599 ## `http` - use http-rpc backend (default)
599 ## `http` - use http-rpc backend (default)
600 vcs.hooks.protocol = http
600 vcs.hooks.protocol = http
601
601
602 vcs.server.log_level = debug
602 vcs.server.log_level = debug
603 ## Start VCSServer with this instance as a subprocess, usefull for development
603 ## Start VCSServer with this instance as a subprocess, usefull for development
604 vcs.start_server = false
604 vcs.start_server = false
605
605
606 ## List of enabled VCS backends, available options are:
606 ## List of enabled VCS backends, available options are:
607 ## `hg` - mercurial
607 ## `hg` - mercurial
608 ## `git` - git
608 ## `git` - git
609 ## `svn` - subversion
609 ## `svn` - subversion
610 vcs.backends = hg, git, svn
610 vcs.backends = hg, git, svn
611
611
612 vcs.connection_timeout = 3600
612 vcs.connection_timeout = 3600
613 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
613 ## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
614 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
614 ## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible, pre-1.9-compatible
615 #vcs.svn.compatible_version = pre-1.8-compatible
615 #vcs.svn.compatible_version = pre-1.8-compatible
616
616
617
617
618 ############################################################
618 ############################################################
619 ### Subversion proxy support (mod_dav_svn) ###
619 ### Subversion proxy support (mod_dav_svn) ###
620 ### Maps RhodeCode repo groups into SVN paths for Apache ###
620 ### Maps RhodeCode repo groups into SVN paths for Apache ###
621 ############################################################
621 ############################################################
622 ## Enable or disable the config file generation.
622 ## Enable or disable the config file generation.
623 svn.proxy.generate_config = false
623 svn.proxy.generate_config = false
624 ## Generate config file with `SVNListParentPath` set to `On`.
624 ## Generate config file with `SVNListParentPath` set to `On`.
625 svn.proxy.list_parent_path = true
625 svn.proxy.list_parent_path = true
626 ## Set location and file name of generated config file.
626 ## Set location and file name of generated config file.
627 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
627 svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
628 ## Used as a prefix to the `Location` block in the generated config file.
628 ## Used as a prefix to the `Location` block in the generated config file.
629 ## In most cases it should be set to `/`.
629 ## In most cases it should be set to `/`.
630 svn.proxy.location_root = /
630 svn.proxy.location_root = /
631 ## Command to reload the mod dav svn configuration on change.
631 ## Command to reload the mod dav svn configuration on change.
632 ## Example: `/etc/init.d/apache2 reload`
632 ## Example: `/etc/init.d/apache2 reload`
633 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
633 #svn.proxy.reload_cmd = /etc/init.d/apache2 reload
634 ## If the timeout expires before the reload command finishes, the command will
634 ## If the timeout expires before the reload command finishes, the command will
635 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
635 ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds.
636 #svn.proxy.reload_timeout = 10
636 #svn.proxy.reload_timeout = 10
637
637
638 ############################################################
638 ############################################################
639 ### SSH Support Settings ###
639 ### SSH Support Settings ###
640 ############################################################
640 ############################################################
641
641
642 ## Defines if the authorized_keys file should be written on any change of
642 ## Defines if the authorized_keys file should be written on any change of
643 ## user ssh keys, setting this to false also disables posibility of adding
643 ## user ssh keys, setting this to false also disables posibility of adding
644 ## ssh keys for users from web interface.
644 ## ssh keys for users from web interface.
645 ssh.generate_authorized_keyfile = true
645 ssh.generate_authorized_keyfile = true
646
646
647 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
647 ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding`
648 # ssh.authorized_keys_ssh_opts =
648 # ssh.authorized_keys_ssh_opts =
649
649
650 ## File to generate the authorized keys together with options
650 ## File to generate the authorized keys together with options
651 ## It is possible to have multiple key files specified in `sshd_config` e.g.
651 ## It is possible to have multiple key files specified in `sshd_config` e.g.
652 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
652 ## AuthorizedKeysFile %h/.ssh/authorized_keys %h/.ssh/authorized_keys_rhodecode
653 ssh.authorized_keys_file_path = %(here)s/rc/authorized_keys_rhodecode
653 ssh.authorized_keys_file_path = %(here)s/rc/authorized_keys_rhodecode
654
654
655 ## Command to execute the SSH wrapper. The binary is available in the
655 ## Command to execute the SSH wrapper. The binary is available in the
656 ## rhodecode installation directory.
656 ## rhodecode installation directory.
657 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
657 ## e.g ~/.rccontrol/community-1/profile/bin/rc-ssh-wrapper
658 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
658 ssh.wrapper_cmd = ~/.rccontrol/community-1/rc-ssh-wrapper
659
659
660 ## Allow shell when executing the ssh-wrapper command
660 ## Allow shell when executing the ssh-wrapper command
661 ssh.wrapper_cmd_allow_shell = false
661 ssh.wrapper_cmd_allow_shell = false
662
662
663 ## Enables logging, and detailed output send back to the client. Usefull for
663 ## Enables logging, and detailed output send back to the client. Usefull for
664 ## debugging, shouldn't be used in production.
664 ## debugging, shouldn't be used in production.
665 ssh.enable_debug_logging = false
665 ssh.enable_debug_logging = false
666
666
667 ## API KEY for user who has access to fetch other user permission information
668 ## most likely an super-admin account with some IP restrictions.
669 ssh.api_key =
670
671 ## API Host, the server address of RhodeCode instance that the api_key will
672 ## access
673 ssh.api_host = http://localhost
674
675 ## Paths to binary executrables, by default they are the names, but we can
667 ## Paths to binary executrables, by default they are the names, but we can
676 ## override them if we want to use a custom one
668 ## override them if we want to use a custom one
677 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
669 ssh.executable.hg = ~/.rccontrol/vcsserver-1/profile/bin/hg
678 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
670 ssh.executable.git = ~/.rccontrol/vcsserver-1/profile/bin/git
679 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
671 ssh.executable.svn = ~/.rccontrol/vcsserver-1/profile/bin/svnserve
680
672
681
673
682 ## Dummy marker to add new entries after.
674 ## Dummy marker to add new entries after.
683 ## Add any custom entries below. Please don't remove.
675 ## Add any custom entries below. Please don't remove.
684 custom.conf = 1
676 custom.conf = 1
685
677
686
678
687 ################################
679 ################################
688 ### LOGGING CONFIGURATION ####
680 ### LOGGING CONFIGURATION ####
689 ################################
681 ################################
690 [loggers]
682 [loggers]
691 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, ssh_wrapper
683 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, ssh_wrapper
692
684
693 [handlers]
685 [handlers]
694 keys = console, console_sql
686 keys = console, console_sql
695
687
696 [formatters]
688 [formatters]
697 keys = generic, color_formatter, color_formatter_sql
689 keys = generic, color_formatter, color_formatter_sql
698
690
699 #############
691 #############
700 ## LOGGERS ##
692 ## LOGGERS ##
701 #############
693 #############
702 [logger_root]
694 [logger_root]
703 level = NOTSET
695 level = NOTSET
704 handlers = console
696 handlers = console
705
697
706 [logger_routes]
698 [logger_routes]
707 level = DEBUG
699 level = DEBUG
708 handlers =
700 handlers =
709 qualname = routes.middleware
701 qualname = routes.middleware
710 ## "level = DEBUG" logs the route matched and routing variables.
702 ## "level = DEBUG" logs the route matched and routing variables.
711 propagate = 1
703 propagate = 1
712
704
713 [logger_beaker]
705 [logger_beaker]
714 level = DEBUG
706 level = DEBUG
715 handlers =
707 handlers =
716 qualname = beaker.container
708 qualname = beaker.container
717 propagate = 1
709 propagate = 1
718
710
719 [logger_templates]
711 [logger_templates]
720 level = INFO
712 level = INFO
721 handlers =
713 handlers =
722 qualname = pylons.templating
714 qualname = pylons.templating
723 propagate = 1
715 propagate = 1
724
716
725 [logger_rhodecode]
717 [logger_rhodecode]
726 level = DEBUG
718 level = DEBUG
727 handlers =
719 handlers =
728 qualname = rhodecode
720 qualname = rhodecode
729 propagate = 1
721 propagate = 1
730
722
731 [logger_sqlalchemy]
723 [logger_sqlalchemy]
732 level = ERROR
724 level = ERROR
733 handlers = console_sql
725 handlers = console_sql
734 qualname = sqlalchemy.engine
726 qualname = sqlalchemy.engine
735 propagate = 0
727 propagate = 0
736
728
737 [logger_ssh_wrapper]
729 [logger_ssh_wrapper]
738 level = DEBUG
730 level = DEBUG
739 handlers =
731 handlers =
740 qualname = ssh_wrapper
732 qualname = ssh_wrapper
741 propagate = 1
733 propagate = 1
742
734
743
735
744 ##############
736 ##############
745 ## HANDLERS ##
737 ## HANDLERS ##
746 ##############
738 ##############
747
739
748 [handler_console]
740 [handler_console]
749 class = StreamHandler
741 class = StreamHandler
750 args = (sys.stderr,)
742 args = (sys.stderr,)
751 level = DEBUG
743 level = DEBUG
752 formatter = generic
744 formatter = generic
753
745
754 [handler_console_sql]
746 [handler_console_sql]
755 class = StreamHandler
747 class = StreamHandler
756 args = (sys.stderr,)
748 args = (sys.stderr,)
757 level = WARN
749 level = WARN
758 formatter = generic
750 formatter = generic
759
751
760 ################
752 ################
761 ## FORMATTERS ##
753 ## FORMATTERS ##
762 ################
754 ################
763
755
764 [formatter_generic]
756 [formatter_generic]
765 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
757 class = rhodecode.lib.logging_formatter.ExceptionAwareFormatter
766 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
758 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
767 datefmt = %Y-%m-%d %H:%M:%S
759 datefmt = %Y-%m-%d %H:%M:%S
768
760
769 [formatter_color_formatter]
761 [formatter_color_formatter]
770 class = rhodecode.lib.logging_formatter.ColorFormatter
762 class = rhodecode.lib.logging_formatter.ColorFormatter
771 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
763 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
772 datefmt = %Y-%m-%d %H:%M:%S
764 datefmt = %Y-%m-%d %H:%M:%S
773
765
774 [formatter_color_formatter_sql]
766 [formatter_color_formatter_sql]
775 class = rhodecode.lib.logging_formatter.ColorFormatterSql
767 class = rhodecode.lib.logging_formatter.ColorFormatterSql
776 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
768 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
777 datefmt = %Y-%m-%d %H:%M:%S
769 datefmt = %Y-%m-%d %H:%M:%S
General Comments 0
You need to be logged in to leave comments. Login now