robustcheckout: reject --revision arguments that aren't SHA-1s (
bug 1274095); r?jlund
We take shortcuts with regards to handling the --revision argument: if
the value resolves to a known revision, we skip pulling from the remote
and checkout directly. This is faster. But it assumes --revision is
constant. --revision isn't constant if it is symbolic. e.g. "default"
or "tip." To prevent these kinds of errors, reject values to --revision
that don't resemble SHA-1 fragments.
We enforce the check in 2 locations: first as a visual check during
argument processing then again when checking the revision is known
locally. The 2nd only occurs if the revision's value looks like a SHA-1
fragment but isn't a known SHA-1 fragment.
MozReview-Commit-ID: 98O2F7ye6mD
--- a/hgext/robustcheckout/__init__.py
+++ b/hgext/robustcheckout/__init__.py
@@ -122,16 +122,22 @@ def robustcheckout(ui, url, dest, upstre
purge=False, sharebase=None):
"""Ensure a working copy has the specified revision checked out."""
if not revision and not branch:
raise error.Abort('must specify one of --revision or --branch')
if revision and branch:
raise error.Abort('cannot specify both --revision and --branch')
+ # Require revision to look like a SHA-1.
+ if revision:
+ if len(revision) < 12 or len(revision) > 40 or not re.match('^[a-f0-9]+$', revision):
+ raise error.Abort('--revision must be a SHA-1 fragment 12-40 '
+ 'characters long')
+
sharebase = sharebase or ui.config('share', 'pool')
if not sharebase:
raise error.Abort('share base directory not defined; refusing to operate',
hint='define share.pool config option or pass --sharebase')
# worker.backgroundclose only makes things faster if running anti-virus,
# which our automation doesn't. Disable it.
ui.setconfig('worker', 'backgroundclose', False)
@@ -238,17 +244,25 @@ def _docheckout(ui, url, dest, upstream,
created = True
# The destination .hg directory should exist. Now make sure we have the
# wanted revision.
repo = hg.repository(ui, dest)
havewantedrev = False
if revision:
- havewantedrev = revision in repo
+ if revision in repo:
+ ctx = repo[revision]
+
+ if not ctx.hex().startswith(revision):
+ raise error.Abort('--revision argument is ambiguous',
+ hint='must be the first 12+ characters of a '
+ 'SHA-1 fragment')
+
+ havewantedrev = True
else:
assert branch
# Branch names are not constant over time, so always pull to
# ensure we have the latest revision.
if not havewantedrev:
ui.write('(pulling to obtain %s)\n' % (revision or branch,))
--- a/hgext/robustcheckout/tests/test-revision-branch.t
+++ b/hgext/robustcheckout/tests/test-revision-branch.t
@@ -7,16 +7,34 @@ Must specify revision or branch argument
[255]
Only 1 of revision and branch can be specified
$ hg robustcheckout http://localhost:$HGPORT/repo0 dest --branch default --revision 5d6cdc75a09b
abort: cannot specify both --revision and --branch
[255]
+A SHA-1 fragment is required in --revision argument
+
+ $ hg robustcheckout http://localhost:$HGPORT/repo0 dest --revision default
+ abort: --revision must be a SHA-1 fragment 12-40 characters long
+ [255]
+
+It must be 12+ characters long
+
+ $ hg robustcheckout http://localhost:$HGPORT/repo0 dest --revision 0123456789a
+ abort: --revision must be a SHA-1 fragment 12-40 characters long
+ [255]
+
+It can't be more than 40 characters
+
+ $ hg robustcheckout http://localhost:$HGPORT/repo0 dest --revision 01234567890123456789012345678901234567890
+ abort: --revision must be a SHA-1 fragment 12-40 characters long
+ [255]
+
Specifying branch argument will checkout branch
$ hg robustcheckout http://localhost:$HGPORT/repo0 dest --branch default
ensuring http://localhost:$HGPORT/repo0@default is available at dest
(sharing from new pooled repository b8b78f0253d822e33ba652fd3d80a5c0837cfdf3)
requesting all changes
adding changesets
adding manifests
@@ -51,8 +69,27 @@ Updating to another branch works
Specifying revision will switch away from branch
$ hg robustcheckout http://localhost:$HGPORT/repo0 dest --revision 5d6cdc75a09b
ensuring http://localhost:$HGPORT/repo0@5d6cdc75a09b is available at dest
(existing repository shared store: $TESTTMP/share/b8b78f0253d822e33ba652fd3d80a5c0837cfdf3/.hg)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
updated to 5d6cdc75a09bcccf76f9339a28e1d89360c59dce
+
+Create a branch that looks like a SHA-1 but isn't and verify we refuse to accept
+updating to it
+
+ $ cd dest
+ $ hg branch abcdef0123456
+ marked working directory as branch abcdef0123456
+ $ echo nosha1 > foo
+ $ hg commit -m 'ambiguous branch'
+ $ cd ..
+
+ $ hg robustcheckout http://localhost:$HGPORT/repo0 ambiguous --revision abcdef0123456
+ ensuring http://localhost:$HGPORT/repo0@abcdef0123456 is available at ambiguous
+ (sharing from existing pooled repository b8b78f0253d822e33ba652fd3d80a5c0837cfdf3)
+ searching for changes
+ no changes found
+ abort: --revision argument is ambiguous
+ (must be the first 12+ characters of a SHA-1 fragment)
+ [255]