hgbook
diff en/hook.tex @ 38:b49a7dd4e564
More content for hook chapter.
Overview of hooks.
Description of hook security implications.
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