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