Mercurial > hg
view tests/test-ssh-proto.t @ 36527:44dc34b8d17b
debugcommands: add debugserve command
`hg serve --stdio` requires the exact command argument form
`hg -R <path> serve --stdio` for security reasons. An upcoming
commit will need to start an SSH protocol server process with
custom settings.
This commit creates a `hg debugserve` command for starting servers
with custom options. There are no security restrictions and we can
add options here that aren't appropriate for built-in commands.
We currently only support starting an SSH protocol server using
the process's stdio file descriptors. The server supports logging
its I/O activity to a file descriptor number passed as a command
argument.
Differential Revision: https://phab.mercurial-scm.org/D2464
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Tue, 27 Feb 2018 15:47:44 -0800 |
parents | 02782e6e2c38 |
children | 72e487851a53 |
line wrap: on
line source
$ cat >> $HGRCPATH << EOF > [ui] > ssh = $PYTHON "$TESTDIR/dummyssh" > [devel] > debug.peer-request = true > [extensions] > sshprotoext = $TESTDIR/sshprotoext.py > EOF $ hg init server $ cd server $ echo 0 > foo $ hg -q add foo $ hg commit -m initial $ cd .. Test a normal behaving server, for sanity $ hg --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command remote: 384 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN remote: 1 url: ssh://user@dummy/server local: no pushable: yes Server should answer the "hello" command in isolation $ hg -R server serve --stdio << EOF > hello > EOF 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN `hg debugserve --sshstdio` works $ cd server $ hg debugserve --sshstdio << EOF > hello > EOF 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN I/O logging works $ hg debugserve --sshstdio --logiofd 1 << EOF > hello > EOF o> write(4) -> None: o> 384\n o> write(384) -> None: o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN o> flush() -> None $ hg debugserve --sshstdio --logiofile $TESTTMP/io << EOF > hello > EOF 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN $ cat $TESTTMP/io o> write(4) -> None: o> 384\n o> write(384) -> None: o> capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n o> flush() -> None $ cd .. >=0.9.1 clients send a "hello" + "between" for the null range as part of handshake. Server should reply with capabilities and should send "1\n\n" as a successful reply with empty response to the "between". $ hg -R server serve --stdio << EOF > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 SSH banner is not printed by default, ignored by clients $ SSHSERVERMODE=banner hg debugpeer ssh://user@dummy/server url: ssh://user@dummy/server local: no pushable: yes --debug will print the banner $ SSHSERVERMODE=banner hg --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command remote: banner: line 0 remote: banner: line 1 remote: banner: line 2 remote: banner: line 3 remote: banner: line 4 remote: banner: line 5 remote: banner: line 6 remote: banner: line 7 remote: banner: line 8 remote: banner: line 9 remote: 384 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN remote: 1 url: ssh://user@dummy/server local: no pushable: yes And test the banner with the raw protocol $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF banner: line 0 banner: line 1 banner: line 2 banner: line 3 banner: line 4 banner: line 5 banner: line 6 banner: line 7 banner: line 8 banner: line 9 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 Connecting to a <0.9.1 server that doesn't support the hello command. The client should refuse, as we dropped support for connecting to such servers. $ SSHSERVERMODE=no-hello hg --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command remote: 0 remote: 1 abort: no suitable response from remote hg! [255] Sending an unknown command to the server results in an empty response to that command $ hg -R server serve --stdio << EOF > pre-hello > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) sending no-args command devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command remote: 0 remote: 384 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN remote: 1 url: ssh://user@dummy/server local: no pushable: yes Send multiple unknown commands before hello $ hg -R server serve --stdio << EOF > unknown1 > unknown2 > unknown3 > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 0 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) sending unknown1 command sending unknown2 command sending unknown3 command devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command remote: 0 remote: 0 remote: 0 remote: 384 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN remote: 1 url: ssh://user@dummy/server local: no pushable: yes Send an unknown command before hello that has arguments $ hg -R server serve --stdio << EOF > with-args > foo 13 > value for foo > bar 13 > value for bar > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 0 0 0 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 Send an unknown command having an argument that looks numeric $ hg -R server serve --stdio << EOF > unknown > foo 1 > 0 > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 0 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 $ hg -R server serve --stdio << EOF > unknown > foo 1 > 1 > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 0 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 When sending a dict argument value, it is serialized to "<arg> <item count>" followed by "<key> <len>\n<value>" for each item in the dict. Dictionary value for unknown command $ hg -R server serve --stdio << EOF > unknown > dict 3 > key1 3 > foo > key2 3 > bar > key3 3 > baz > hello > EOF 0 0 0 0 0 0 0 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN Incomplete dictionary send $ hg -R server serve --stdio << EOF > unknown > dict 3 > key1 3 > foo > EOF 0 0 0 0 Incomplete value send $ hg -R server serve --stdio << EOF > unknown > dict 3 > key1 3 > fo > EOF 0 0 0 0 Send a command line with spaces $ hg -R server serve --stdio << EOF > unknown withspace > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 $ hg -R server serve --stdio << EOF > unknown with multiple spaces > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 $ hg -R server serve --stdio << EOF > unknown with spaces > key 10 > some value > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 0 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 Send an unknown command after the "between" $ hg -R server serve --stdio << EOF > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown > EOF 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 0 And one with arguments $ hg -R server serve --stdio << EOF > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown > foo 5 > value > bar 3 > baz > EOF 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 0 0 0 0 0 Send a valid command before the handshake $ hg -R server serve --stdio << EOF > heads > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 41 68986213bd4485ea51533535e3fc9e78007a711f 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 And a variation that doesn't send the between command $ hg -R server serve --stdio << EOF > heads > hello > EOF 41 68986213bd4485ea51533535e3fc9e78007a711f 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN Send an upgrade request to a server that doesn't support that command $ hg -R server serve --stdio << EOF > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2 > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) sending upgrade request: * proto=exp-ssh-v2-0001 (glob) devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command remote: 0 remote: 384 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN remote: 1 url: ssh://user@dummy/server local: no pushable: yes Enable version 2 support on server. We need to do this in hgrc because we can't use --config with `hg serve --stdio`. $ cat >> server/.hg/hgrc << EOF > [experimental] > sshserver.support-v2 = true > EOF Send an upgrade request to a server that supports upgrade >>> with open('payload', 'wb') as fh: ... fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n') ... fh.write(b'hello\n') ... fh.write(b'between\n') ... fh.write(b'pairs 81\n') ... fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000') $ hg -R server serve --stdio < payload upgraded this-is-some-token exp-ssh-v2-0001 383 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) sending upgrade request: * proto=exp-ssh-v2-0001 (glob) devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command protocol upgraded to exp-ssh-v2-0001 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN url: ssh://user@dummy/server local: no pushable: yes Verify the peer has capabilities $ hg --config experimental.sshpeer.advertise-v2=true --debug debugcapabilities ssh://user@dummy/server running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !) running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !) sending upgrade request: * proto=exp-ssh-v2-0001 (glob) devel-peer-request: hello sending hello command devel-peer-request: between devel-peer-request: pairs: 81 bytes sending between command protocol upgraded to exp-ssh-v2-0001 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN Main capabilities: batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset getbundle known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash Bundle2 capabilities: HG20 bookmarks changegroup 01 02 digests md5 sha1 sha512 error abort unsupportedcontent pushraced pushkey hgtagsfnodes listkeys phases heads pushkey remote-changegroup http https Command after upgrade to version 2 is processed >>> with open('payload', 'wb') as fh: ... fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n') ... fh.write(b'hello\n') ... fh.write(b'between\n') ... fh.write(b'pairs 81\n') ... fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000') ... fh.write(b'hello\n') $ hg -R server serve --stdio < payload upgraded this-is-some-token exp-ssh-v2-0001 383 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN Multiple upgrades is not allowed >>> with open('payload', 'wb') as fh: ... fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n') ... fh.write(b'hello\n') ... fh.write(b'between\n') ... fh.write(b'pairs 81\n') ... fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000') ... fh.write(b'upgrade another-token proto=irrelevant\n') ... fh.write(b'hello\n') $ hg -R server serve --stdio < payload upgraded this-is-some-token exp-ssh-v2-0001 383 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN cannot upgrade protocols multiple times - Malformed upgrade request line (not exactly 3 space delimited tokens) $ hg -R server serve --stdio << EOF > upgrade > EOF 0 $ hg -R server serve --stdio << EOF > upgrade token > EOF 0 $ hg -R server serve --stdio << EOF > upgrade token foo=bar extra-token > EOF 0 Upgrade request to unsupported protocol is ignored $ hg -R server serve --stdio << EOF > upgrade this-is-some-token proto=unknown1,unknown2 > hello > between > pairs 81 > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000 > EOF 0 384 capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN 1 Upgrade request must be followed by hello + between $ hg -R server serve --stdio << EOF > upgrade token proto=exp-ssh-v2-0001 > invalid > EOF malformed handshake protocol: missing hello - $ hg -R server serve --stdio << EOF > upgrade token proto=exp-ssh-v2-0001 > hello > invalid > EOF malformed handshake protocol: missing between - $ hg -R server serve --stdio << EOF > upgrade token proto=exp-ssh-v2-0001 > hello > between > invalid > EOF malformed handshake protocol: missing pairs 81 -