hgbook

diff en/hook.tex @ 38:b49a7dd4e564

More content for hook chapter.
Overview of hooks.
Description of hook security implications.
author Bryan O'Sullivan <bos@serpentine.com>
date Wed Jul 19 00:06:21 2006 -0700 (2006-07-19)
parents 9fd0c59b009a
children 576fef93bb49
line diff
     1.1 --- a/en/hook.tex	Mon Jul 17 00:01:01 2006 -0700
     1.2 +++ b/en/hook.tex	Wed Jul 19 00:06:21 2006 -0700
     1.3 @@ -9,6 +9,175 @@
     1.4  Hooks are called ``triggers'' in some revision control systems, but
     1.5  the two names refer to the same idea.
     1.6  
     1.7 +\section{An overview of hooks in Mercurial}
     1.8 +
     1.9 +Here is a brief list of the hooks that Mercurial supports. For each
    1.10 +hook, we indicate when it is run, and a few examples of common tasks
    1.11 +you can use it for.  We will revisit each of these hooks in more
    1.12 +detail later.
    1.13 +\begin{itemize}
    1.14 +\item[\small\hook{changegroup}] This is run after a group of
    1.15 +  changesets has been brought into the repository from elsewhere.  In
    1.16 +  other words, it is run after a \hgcmd{pull} or \hgcmd{push} into a
    1.17 +  repository, but not after a \hgcmd{commit}.  You can use this for
    1.18 +  performing an action once for the entire group of newly arrived
    1.19 +  changesets.  For example, you could use this hook to send out email
    1.20 +  notifications, or kick off an automated build or test.
    1.21 +\item[\small\hook{commit}] This is run after a new changeset has been
    1.22 +  created in the local repository, typically using the \hgcmd{commit}
    1.23 +  command.
    1.24 +\item[\small\hook{incoming}] This is run once for each new changeset
    1.25 +  that is brought into the repository from elsewhere.  Notice the
    1.26 +  difference from \hook{changegroup}, which is run once per
    1.27 +  \emph{group} of changesets brought in.  You can use this for the
    1.28 +  same purposes as the \hook{changegroup} hook; it's simply more
    1.29 +  convenient sometimes to run a hook once per group of changesets,
    1.30 +  while othher times it's handier once per changeset.
    1.31 +\item[\small\hook{outgoing}] This is run after a group of changesets
    1.32 +  has been transmitted from this repository to another.  You can use
    1.33 +  this, for example, to notify subscribers every time changes are
    1.34 +  cloned or pulled from the repository.
    1.35 +\item[\small\hook{prechangegroup}] This is run before starting to
    1.36 +  bring a group of changesets into the repository.  It cannot see the
    1.37 +  actual changesets, because they have not yet been transmitted.  If
    1.38 +  it fails, the changesets will not be transmitted.  You can use this
    1.39 +  hook to ``lock down'' a repository against incoming changes.
    1.40 +\item[\small\hook{precommit}] This is run before starting a commit.
    1.41 +  It cannot tell what files are included in the commit, or any other
    1.42 +  information about the commit.  If it fails, the commit will not be
    1.43 +  allowed to start.  You can use this to perform a build and require
    1.44 +  it to complete successfully before a commit can proceed, or
    1.45 +  automatically enforce a requirement that modified files pass your
    1.46 +  coding style guidelines.
    1.47 +\item[\small\hook{preoutgoing}] This is run before starting to
    1.48 +  transmit a group of changesets from this repository.  You can use
    1.49 +  this to lock a repository against clones or pulls from remote
    1.50 +  clients.
    1.51 +\item[\small\hook{pretag}] This is run before creating a tag.  If it
    1.52 +  fails, the tag will not be created.  You can use this to enforce a
    1.53 +  uniform tag naming convention.
    1.54 +\item[\small\hook{pretxnchangegroup}] This is run after a group of
    1.55 +  changesets has been brought into the local repository from another,
    1.56 +  but before the transaction completes that will make the changes
    1.57 +  permanent in the repository.  If it fails, the transaction will be
    1.58 +  rolled back and the changes will disappear from the local
    1.59 +  repository.  You can use this to automatically check newly arrived
    1.60 +  changes and, for example, roll them back if the group as a whole
    1.61 +  does not build or pass your test suite.
    1.62 +\item[\small\hook{pretxncommit}] This is run after a new changeset has
    1.63 +  been created in the local repository, but before the transaction
    1.64 +  completes that will make it permanent.  Unlike the \hook{precommit}
    1.65 +  hook, this hook can see which changes are present in the changeset,
    1.66 +  and it can also see all other changeset metadata, such as the commit
    1.67 +  message.  You can use this to require that a commit message follows
    1.68 +  your local conventions, or that a changeset builds cleanly.
    1.69 +\item[\small\hook{preupdate}] This is run before starting an update or
    1.70 +  merge of the working directory.
    1.71 +\item[\small\hook{tag}] This is run after a tag is created.
    1.72 +\item[\small\hook{update}] This is run after an update or merge of the
    1.73 +  working directory has finished.
    1.74 +\end{itemize}
    1.75 +Each of the hooks with a ``\texttt{pre}'' prefix has the ability to
    1.76 +\emph{control} an activity.  If the hook succeeds, the activity may
    1.77 +proceed; if it fails, the activity is either not permitted or undone,
    1.78 +depending on the hook.
    1.79 +
    1.80 +\section{Hooks and security}
    1.81 +
    1.82 +\subsection{Hooks are run with your privileges}
    1.83 +
    1.84 +When you run a Mercurial command in a repository, and the command
    1.85 +causes a hook to run, that hook runs on your system, under your user
    1.86 +account, with your privilege level.  Since hooks are arbitrary pieces
    1.87 +of executable code, you should treat them with an appropriate level of
    1.88 +suspicion.  Do not install a hook unless you are confident that you
    1.89 +know who created it and what it does.
    1.90 +
    1.91 +In some cases, you may be exposed to hooks that you did not install
    1.92 +yourself.  If you work with Mercurial on an unfamiliar system,
    1.93 +Mercurial will run hooks defined in that system's global \hgrc\ file.
    1.94 +
    1.95 +If you are working with a repository owned by another user, Mercurial
    1.96 +will run hooks defined in that repository.  For example, if you
    1.97 +\hgcmd{pull} from that repository, and its \sfilename{.hg/hgrc}
    1.98 +defines a local \hook{outgoing} hook, that hook will run under your
    1.99 +user account, even though you don't own that repository.
   1.100 +
   1.101 +\begin{note}
   1.102 +  This only applies if you are pulling from a repository on a local or
   1.103 +  network filesystem.  If you're pulling over http or ssh, any
   1.104 +  \hook{outgoing} hook will run under the account of the server
   1.105 +  process, on the server.
   1.106 +\end{note}
   1.107 +
   1.108 +XXX To see what hooks are defined in a repository, use the
   1.109 +\hgcmdargs{config}{hooks} command.  If you are working in one
   1.110 +repository, but talking to another that you do not own (e.g.~using
   1.111 +\hgcmd{pull} or \hgcmd{incoming}), remember that it is the other
   1.112 +repository's hooks you should be checking, not your own.
   1.113 +
   1.114 +\subsection{Hooks do not propagate}
   1.115 +
   1.116 +In Mercurial, hooks are not revision controlled, and do not propagate
   1.117 +when you clone, or pull from, a repository.  The reason for this is
   1.118 +simple: a hook is a completely arbitrary piece of executable code.  It
   1.119 +runs under your user identity, with your privilege level, on your
   1.120 +machine.
   1.121 +
   1.122 +It would be extremely reckless for any distributed revision control
   1.123 +system to implement revision-controlled hooks, as this would offer an
   1.124 +easily exploitable way to subvert the accounts of users of the
   1.125 +revision control system.
   1.126 +
   1.127 +Since Mercurial does not propagate hooks, if you are collaborating
   1.128 +with other people on a common project, you should not assume that they
   1.129 +are using the same Mercurial hooks as you are, or that theirs are
   1.130 +correctly configured.  You should document the hooks you expect people
   1.131 +to use.
   1.132 +
   1.133 +In a corporate intranet, this is somewhat easier to control, as you
   1.134 +can for example provide a ``standard'' installation of Mercurial on an
   1.135 +NFS filesystem, and use a site-wide \hgrc\ file to define hooks that
   1.136 +all users will see.  However, this too has its limits; see below.
   1.137 +
   1.138 +\subsection{Hooks can be overridden}
   1.139 +
   1.140 +Mercurial allows you to override a hook definition by redefining the
   1.141 +hook.  You can disable it by setting its value to the empty string, or
   1.142 +change its behaviour as you wish.
   1.143 +
   1.144 +If you deploy a system-~or site-wide \hgrc\ file that defines some
   1.145 +hooks, you should thus understand that your users can disable or
   1.146 +override those hooks.
   1.147 +
   1.148 +\subsection{Ensuring that critical hooks are run}
   1.149 +
   1.150 +Sometimes you may want to enforce a policy that you do not want others
   1.151 +to be able to work around.  For example, you may have a requirement
   1.152 +that every changeset must pass a rigorous set of tests.  Defining this
   1.153 +requirement via a hook in a site-wide \hgrc\ won't work for remote
   1.154 +users on laptops, and of course local users can subvert it at will by
   1.155 +overriding the hook.
   1.156 +
   1.157 +Instead, you can set up your policies for use of Mercurial so that
   1.158 +people are expected to propagate changes through a well-known
   1.159 +``canonical'' server that you have locked down and configured
   1.160 +appropriately.
   1.161 +
   1.162 +One way to do this is via a combination of social engineering and
   1.163 +technology.  Set up a restricted-access account; users can push
   1.164 +changes over the network to repositories managed by this account, but
   1.165 +they cannot log into the account and run normal shell commands.  In
   1.166 +this scenario, a user can commit a changeset that contains any old
   1.167 +garbage they want.
   1.168 +
   1.169 +When someone pushes a changeset to the server that everyone pulls
   1.170 +from, the server will test the changeset before it accepts it as
   1.171 +permanent, and reject it if it fails to pass the test suite.  If
   1.172 +people only pull changes from this filtering server, it will serve to
   1.173 +ensure that all changes that people pull have been automatically
   1.174 +vetted.
   1.175 +
   1.176  \section{A short tutorial on using hooks}
   1.177  \label{sec:hook:simple}
   1.178