Design: Server-Dictated Configuration

Many software development shops of non-trivial size desire to have (and to the extent possible, to enforce) a uniform configuration environment among the various clients which commit to their repositories. Although these shops may have some ability to control the environment on the client machines (dictating software versions, etc), expecting humans to consistently set and maintain various runtime configuration parameters in accordance with corporate policy and on every repository-accessing client computer is both error-prone and unscalable.

Subversion already provides the means of enforcing much (but not all) of this configuration through the hook script mechanism, but at best this can only punish non-compliant client behavior and clumsily recommend configuration changes (which, again, a human must implement on their client computer). Allowing the administrator to store a default configuration on the server, which is automatically pushed to and honored by (well-behaved) clients, would save both time and frustration.

Behavioral specification

The high-level behavior for server-dictated configuration is relatively simple: the repository maintains a list of configuration parameters and values which, as necessary, the server provides to the client. The client, then, behaves in accordance with the server-dictated configuration.

Subversion could recognize multiple levels of possible hierarchy in the server-side configuration: server-wide, per repository, or per repository-path. The current plan is to allow configuration at the most granular level, per repository-path.

There are a number of configuration options that existing Subversion users and administrators might wish to have propagated from the server to the client. The following is a list of the specific options we are currently planning to implement (this list is obviously subject to change):







Enforceable via hook scripts

Non-overrideable by well-behaved clients.



Enforceable via hook scripts

Non-overrideable by well-behaved clients.




Non-overrideable by well-behaved clients.

"Well-Behaved Clients" and "Trust, But Verify"

The configuration the server dictates can at best be only a suggestion to the client. Older clients will obviously not even understand the new dictates. As open source software, though, it is relatively easy for a malicious user to modify a client to ignore server-side suggestions. Given this reality, server-side enforcement of desired behaviors (where possible, and often via hook scripts) is still strongly recommended.

Server-client transmission mechanism

When connecting to a repository which supports this feature, the server will provide to the client a SHA1 checksum of the repository's configuration. A supporting client may then use that checksum (and the UUID of the repository) to compare against its own cached copy of the repository configuration. If the checksums differ, the client will request a new configuration from the server.

Over ra-neon/ra-serf, the client will receive the repository's configuration checksum as part of the OPTIONS response. It will request new configuration bits via a custom REPORT request aimed at the repos-global report target (the "me resource" for HTTPv2, the "default VCC" otherwise). ra-svn will behave similarly, using the initial handshake/feature negotiation phase for the repository's checksum delivery, and a new query for the configuration fetch.

We'll need a way for clients to announce to the server that they will honor the server's dictated configuration. The obvious way is via a new capability, so administrators may choose to use the presence/absence of the capabilitiy in the list of capabilities passed to the start-commit hook to determine whether to allow commits from certain clients. There are a few different ways we might want to procede however:



A single new capability string ("server-config")

Simple, but isn't sufficient to differentiate from later releases which might support new configuration options.

New capability strings per supported option (e.g. "server-config-autoprops", "server-config-ignores", "server-config-store-plaintext-passwords")

Solves the problem at hand neatly, allows future releases to add new configuration options, but while we're thinking about this space, haven't you ever wished for...

New capability for each minor release (e.g. "client-version-1.8")

...A way for the client to communicate it's version to the server? This goes beyond what is needed for server dictated configuration, but why not put it in place now?

New capability for each patch release (e.g. "client-version-1.8.0")

Ditto, but if knowing the minor release is good, kowing the patch release must be better no?

Server-side Changes

Configuration storage

The most logical format for server-side configuration is to use the INI file format[1] which is already employed for several other purposes across Subversion. The INI file will reside in _${REPOS_PATH}/conf/_repos.conf.

[1]The actual syntax is documented in the default README file created by Subversion in the per-user configuration area (e.g. %APPDATA%\Subversion\README.txt on Windows and ~/.subversion/README on *nix) or can be found in the Subversion source code in config_file.c – see svn_config_ensure().

Client-side Changes

API changes

svn_ra_open5 (svn_ra.h) will be introduced, differing from its predecessor by the addition of an svn_checksum_t ** return value.

 * Open a repository access session to the repository at @a repos_URL,
 * or inform the caller regarding a correct URL by which to access
 * that repository.
 * If @a repos_URL can be used successfully to access the repository,
 * set @a *session_p to an opaque object representing a repository
 * session for the repository and (if @a corrected_url is non-NULL)
 * set @a *corrected_url to NULL.  If there's a better URL that the
 * caller should try and @a corrected_url is non-NULL, set
 * @a *session_p to NULL and @a *corrected_url to the corrected URL.  If
 * there's a better URL that the caller should try, and @a
 * corrected_url is NULL, return an #SVN_ERR_RA_SESSION_URL_MISMATCH
 * error.  Allocate all returned items in @a pool.
 * If @a config_checksum is not NULL, set @a *config_checksum to the SHA1
 * checksum of the repository's configuration.  (Clients should use this
 * value to determine if they need to request an updated copy of the
 * server-side configuration via @c svn_ra_get_repos_config().)
 * Return @c SVN_ERR_RA_UUID_MISMATCH if @a uuid is non-NULL and not equal
 * to the UUID of the repository at @a repos_URL.
 * @a callbacks/@a callback_baton is a table of callbacks provided by the
 * client; see @c svn_ra_callbacks2_t.
 * @a config is a hash mapping <tt>const char *</tt> keys to
 * @c svn_config_t * values.  For example, the @c svn_config_t for the
 * "~/.subversion/config" file is under the key "config".
 * All RA requests require a session; they will continue to
 * use @a pool for memory allocation.
 * @see svn_client_open_ra_session().
 * @since New in 1.8.
svn_error_t *
svn_ra_open5(svn_ra_session_t **session_p,
             const char **corrected_url,
             svn_checksum_t **config_checksum,
             const char *repos_URL,
             const char *uuid,
             const svn_ra_callbacks2_t *callbacks,
             void *callback_baton,
             apr_hash_t *config,
             apr_pool_t *pool);

Of course, svn_ra_open4() will then be deprecated and made into a wrapper around svn_ra_open5() which passed NULL for the 'config_checksum' parameter.

Additionally, we'll introduce a new API function, svn_ra_get_repos_config():

/* Set *repos_config to a string representing the repository configuration
   for the repository associated with RA_SESSION, allocated from POOL. */
svn_error_t *
svn_ra_get_repos_config(const svn_string_t **repos_config,
                        svn_ra_session_t *ra_session,
                        apr_pool_t *pool);

Cache storage

The client currently maintains its configuration in two files, ${HOME}/.subversion/confi_g and _${HOME}/.subversion/servers. This feature will introduce the ${HOME}/.subversion/repos/ directory (%APPDATA%\Subversion\repos on Windows), which will hold additional subdirectories keyed on the UUID of the repository. It is in this subdirectory that the cached version of the repository configuration will be stored. To facilitate path-specific configuration within a repository, the typical section names of the configuration bits will be combined with the subtree path to which the options therein apply (this will not apply for the store-plaintext-passwords configuration option, which is per-repository). For example:

$ cat ${HOME}/13f79535-47bb-0310-9956-ffa450edef68/config
enable-auto-props = no

enable-auto-props = yes

*.c = svn:mime-type=text/x-csrc;svn:eol-style=native;svn:keywords=Author Date Id Rev URL
*.html = svn:mime-type=text/html;; charset=UTF-8;svn:eol-style=native


Configuration hierarchy

As detailed in the behavioral specification matrix, only specific options will be made available for server-dictated configuration. Server-dictated configuration will be the highest priority configuration recognized by well-behaved Subversion clients. So the new order order in which specific configuration options will be honored is as follows (lower-numbered locations take precedence over higher-numbered locations):

  1. Server-dictated configuration
  2. Command-line options
  3. Per-user runtime configuration (${HOME}/.subversion/*)
  4. The per-user Registry values (Windows Only)
  5. Per-machine runtime configuration (/etc/subversion/*)
  6. The system-wide Registry values (Windows Only)


Most of this idea of server-dictated configuration seems sane. But there's one bit that stands out – the server dictating how the client stores authentication credentials. No matter how I look at this, it feels wrong. Not just wrong, but unique amongst the open source client/server software that I'm familiar with. Perhaps that's because we're trying to use this server-dictated-configuration thing as a cheap (as in, two features for the price of one) way to solve the general concern that some big Subversion-using shops have regarding the need to force Subversion to use EncryptedPasswordStorage on the client side. Note that even if we can convince ourselves that this is okay, I'm concerned that by the time any client would have consulted the server to ask about its configuration, it will have already cached (in plaintext, perhaps) the very authentication credentials it just used to talk to that server. ~cmpilato

Deferred Goals

As with any long desired feature (issue #1974 is over seven years old) there are differing opinions on what "Server Dictacted Configuration" should entail. This section tracks functionality we are currently not planning to implement in the first phase – Obviously this is subject to change.

  1. New Server-Side Enforcement: Other than the existing hook script infrastructure there are no plans for additional server-side enforcement of the server-dictated configuration.
  2. True Server-Wide Config: Setting a consistent configuration for all repositories on a given server will be accomplished by using consistent configs for each repository; there are no plans for a dedicated server-wide config. Administrators are already used to having configuration duplicated across many repositories (hook scripts, authz files, etc.), so we suspect it's no showstopper if "server" configuration is done by ensuring that every repository is properly configured.
  3. Log Message Templates.
  4. Reworking the client-side local configuration to support similar hierarchies of configuration. Today, the local configuration is largely universal in terms of remote scope – changes to the configuration apply to all working copies of all repositories on all servers. (Some exceptions exist in the 'servers' file, but those are largely disinteresting for our purpose.) If the client had access to hierarchical configuration, users could configure such things as "in all working copies of ${ASF_REPOS_UUID}:/subversion, do not store pristines".
  5. Configuration options other than global-ignores, auto-props, and store-plaintext-passwords.
  6. Allow well-behaved clients the ability to override some configuration options on a per-use basis (i.e. using --config-option=FILE:SECTION:OPTION=[VALUE]). Currently all planned server dictated configs can only be overridden by a hacked client. A mechanism to specify which options are overrideable would also be required (e.g. hardcoded client-side whitelists).

Related Issues:

Other Related Resources

  • No labels