Show More
@@ -161,15 +161,28 b' def _exthook(ui, repo, name, cmd, args, ' | |||||
161 | ui.warn(_('warning: %s hook %s\n') % (name, desc)) |
|
161 | ui.warn(_('warning: %s hook %s\n') % (name, desc)) | |
162 | return r |
|
162 | return r | |
163 |
|
163 | |||
|
164 | # represent an untrusted hook command | |||
|
165 | _fromuntrusted = object() | |||
|
166 | ||||
164 | def _allhooks(ui): |
|
167 | def _allhooks(ui): | |
165 | """return a list of (hook-id, cmd) pairs sorted by priority""" |
|
168 | """return a list of (hook-id, cmd) pairs sorted by priority""" | |
166 | hooks = _hookitems(ui) |
|
169 | hooks = _hookitems(ui) | |
|
170 | # Be careful in this section, propagating the real commands from untrusted | |||
|
171 | # sources would create a security vulnerability, make sure anything altered | |||
|
172 | # in that section uses "_fromuntrusted" as its command. | |||
|
173 | untrustedhooks = _hookitems(ui, _untrusted=True) | |||
|
174 | for name, value in untrustedhooks.items(): | |||
|
175 | trustedvalue = hooks.get(name, (None, None, name, _fromuntrusted)) | |||
|
176 | if value != trustedvalue: | |||
|
177 | (lp, lo, lk, lv) = trustedvalue | |||
|
178 | hooks[name] = (lp, lo, lk, _fromuntrusted) | |||
|
179 | # (end of the security sensitive section) | |||
167 | return [(k, v) for p, o, k, v in sorted(hooks.values())] |
|
180 | return [(k, v) for p, o, k, v in sorted(hooks.values())] | |
168 |
|
181 | |||
169 | def _hookitems(ui): |
|
182 | def _hookitems(ui, _untrusted=False): | |
170 | """return all hooks items ready to be sorted""" |
|
183 | """return all hooks items ready to be sorted""" | |
171 | hooks = {} |
|
184 | hooks = {} | |
172 | for name, cmd in ui.configitems('hooks'): |
|
185 | for name, cmd in ui.configitems('hooks', untrusted=_untrusted): | |
173 | if not name.startswith('priority'): |
|
186 | if not name.startswith('priority'): | |
174 | priority = ui.configint('hooks', 'priority.%s' % name, 0) |
|
187 | priority = ui.configint('hooks', 'priority.%s' % name, 0) | |
175 | hooks[name] = (-priority, len(hooks), name, cmd) |
|
188 | hooks[name] = (-priority, len(hooks), name, cmd) | |
@@ -214,7 +227,15 b' def runhooks(ui, repo, name, hooks, thro' | |||||
214 | # files seem to be bogus, give up on redirecting (WSGI, etc) |
|
227 | # files seem to be bogus, give up on redirecting (WSGI, etc) | |
215 | pass |
|
228 | pass | |
216 |
|
229 | |||
217 | if callable(cmd): |
|
230 | if cmd is _fromuntrusted: | |
|
231 | if throw: | |||
|
232 | raise error.HookAbort( | |||
|
233 | _('untrusted hook %s not executed') % name, | |||
|
234 | hint = _("see 'hg help config.trusted'")) | |||
|
235 | ui.warn(_('warning: untrusted hook %s not executed\n') % name) | |||
|
236 | r = 1 | |||
|
237 | raised = False | |||
|
238 | elif callable(cmd): | |||
218 | r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw) |
|
239 | r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw) | |
219 | elif cmd.startswith('python:'): |
|
240 | elif cmd.startswith('python:'): | |
220 | if cmd.count(':') >= 2: |
|
241 | if cmd.count(':') >= 2: |
@@ -794,7 +794,6 b' new commits must be visible in pretxncha' | |||||
794 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
794 | date: Thu Jan 01 00:00:00 1970 +0000 | |
795 | summary: b |
|
795 | summary: b | |
796 |
|
796 | |||
797 | $ cd .. |
|
|||
798 |
|
797 | |||
799 | pretxnclose hook failure should abort the transaction |
|
798 | pretxnclose hook failure should abort the transaction | |
800 |
|
799 | |||
@@ -816,3 +815,62 b' pretxnclose hook failure should abort th' | |||||
816 | $ hg recover |
|
815 | $ hg recover | |
817 | no interrupted transaction available |
|
816 | no interrupted transaction available | |
818 | [1] |
|
817 | [1] | |
|
818 | $ cd .. | |||
|
819 | ||||
|
820 | Hook from untrusted hgrc are reported as failure | |||
|
821 | ================================================ | |||
|
822 | ||||
|
823 | $ cat << EOF > $TESTTMP/untrusted.py | |||
|
824 | > from mercurial import scmutil, util | |||
|
825 | > def uisetup(ui): | |||
|
826 | > class untrustedui(ui.__class__): | |||
|
827 | > def _trusted(self, fp, f): | |||
|
828 | > if util.normpath(fp.name).endswith('untrusted/.hg/hgrc'): | |||
|
829 | > return False | |||
|
830 | > return super(untrustedui, self)._trusted(fp, f) | |||
|
831 | > ui.__class__ = untrustedui | |||
|
832 | > EOF | |||
|
833 | $ cat << EOF >> $HGRCPATH | |||
|
834 | > [extensions] | |||
|
835 | > untrusted=$TESTTMP/untrusted.py | |||
|
836 | > EOF | |||
|
837 | $ hg init untrusted | |||
|
838 | $ cd untrusted | |||
|
839 | ||||
|
840 | Non-blocking hook | |||
|
841 | ----------------- | |||
|
842 | ||||
|
843 | $ cat << EOF >> .hg/hgrc | |||
|
844 | > [hooks] | |||
|
845 | > txnclose.testing=echo txnclose hook called | |||
|
846 | > EOF | |||
|
847 | $ touch a && hg commit -Aqm a | |||
|
848 | warning: untrusted hook txnclose not executed | |||
|
849 | $ hg log | |||
|
850 | changeset: 0:3903775176ed | |||
|
851 | tag: tip | |||
|
852 | user: test | |||
|
853 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
854 | summary: a | |||
|
855 | ||||
|
856 | ||||
|
857 | Non-blocking hook | |||
|
858 | ----------------- | |||
|
859 | ||||
|
860 | $ cat << EOF >> .hg/hgrc | |||
|
861 | > [hooks] | |||
|
862 | > pretxnclose.testing=echo pre-txnclose hook called | |||
|
863 | > EOF | |||
|
864 | $ touch b && hg commit -Aqm a | |||
|
865 | transaction abort! | |||
|
866 | rollback completed | |||
|
867 | abort: untrusted hook pretxnclose not executed | |||
|
868 | (see 'hg help config.trusted') | |||
|
869 | [255] | |||
|
870 | $ hg log | |||
|
871 | changeset: 0:3903775176ed | |||
|
872 | tag: tip | |||
|
873 | user: test | |||
|
874 | date: Thu Jan 01 00:00:00 1970 +0000 | |||
|
875 | summary: a | |||
|
876 |
General Comments 0
You need to be logged in to leave comments.
Login now