hgitaly 18.2.1__tar.gz → 18.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. {hgitaly-18.2.1/hgitaly.egg-info → hgitaly-18.2.3}/PKG-INFO +1 -1
  2. hgitaly-18.2.3/hgitaly/VERSION +1 -0
  3. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/operations.py +42 -39
  4. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_operations.py +36 -1
  5. {hgitaly-18.2.1 → hgitaly-18.2.3/hgitaly.egg-info}/PKG-INFO +1 -1
  6. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_operations.py +2 -3
  7. hgitaly-18.2.1/hgitaly/VERSION +0 -1
  8. {hgitaly-18.2.1 → hgitaly-18.2.3}/LICENSE +0 -0
  9. {hgitaly-18.2.1 → hgitaly-18.2.3}/MANIFEST.in +0 -0
  10. {hgitaly-18.2.1 → hgitaly-18.2.3}/README.md +0 -0
  11. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgext3rd/__init__.py +0 -0
  12. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgext3rd/hgitaly/__init__.py +0 -0
  13. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgext3rd/hgitaly/revset.py +0 -0
  14. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgext3rd/hgitaly/tests/__init__.py +0 -0
  15. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
  16. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
  17. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/__init__.py +0 -0
  18. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/branch.py +0 -0
  19. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/changelog.py +0 -0
  20. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/diff.py +0 -0
  21. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/errors.py +0 -0
  22. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/feature.py +0 -0
  23. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/file_content.py +0 -0
  24. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/file_context.py +0 -0
  25. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/git.py +0 -0
  26. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/gitlab_ref.py +0 -0
  27. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/identification.py +0 -0
  28. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/logging.py +0 -0
  29. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/manifest.py +0 -0
  30. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/message.py +0 -0
  31. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/oid.py +0 -0
  32. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/pagination.py +0 -0
  33. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/path.py +0 -0
  34. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/peer.py +0 -0
  35. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/procutil.py +0 -0
  36. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/repository.py +0 -0
  37. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/revision.py +0 -0
  38. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/revset.py +0 -0
  39. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/scripts.py +0 -0
  40. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/__init__.py +0 -0
  41. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/address.py +0 -0
  42. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/mono.py +0 -0
  43. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/prefork.py +0 -0
  44. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/tests/__init__.py +0 -0
  45. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/tests/test_address.py +0 -0
  46. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/tests/test_mono.py +0 -0
  47. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/tests/test_prefork.py +0 -0
  48. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/tests/test_worker.py +0 -0
  49. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/server/worker.py +0 -0
  50. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/__init__.py +0 -0
  51. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/analysis.py +0 -0
  52. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/blob.py +0 -0
  53. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/commit.py +0 -0
  54. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/diff.py +0 -0
  55. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/interceptors.py +0 -0
  56. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/mercurial_changeset.py +0 -0
  57. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/mercurial_operations.py +0 -0
  58. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/mercurial_repository.py +0 -0
  59. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/ref.py +0 -0
  60. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/repository.py +0 -0
  61. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/server.py +0 -0
  62. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/__init__.py +0 -0
  63. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/fixture.py +0 -0
  64. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_analysis.py +0 -0
  65. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_blob.py +0 -0
  66. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_commit.py +0 -0
  67. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_default_branch.py +0 -0
  68. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_diff.py +0 -0
  69. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
  70. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_mercurial_operations.py +0 -0
  71. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
  72. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_ref.py +0 -0
  73. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_repository_service.py +0 -0
  74. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/service/tests/test_server.py +0 -0
  75. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/servicer.py +0 -0
  76. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/ssh.py +0 -0
  77. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stream.py +0 -0
  78. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/__init__.py +0 -0
  79. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/analysis_pb2.py +0 -0
  80. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
  81. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/blob_pb2.py +0 -0
  82. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/blob_pb2_grpc.py +0 -0
  83. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/commit_pb2.py +0 -0
  84. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/commit_pb2_grpc.py +0 -0
  85. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/diff_pb2.py +0 -0
  86. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/diff_pb2_grpc.py +0 -0
  87. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/errors_pb2.py +0 -0
  88. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/errors_pb2_grpc.py +0 -0
  89. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/lint_pb2.py +0 -0
  90. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/lint_pb2_grpc.py +0 -0
  91. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
  92. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
  93. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
  94. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
  95. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
  96. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
  97. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
  98. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
  99. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/operations_pb2.py +0 -0
  100. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/operations_pb2_grpc.py +0 -0
  101. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/ref_pb2.py +0 -0
  102. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/ref_pb2_grpc.py +0 -0
  103. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/remote_pb2.py +0 -0
  104. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/remote_pb2_grpc.py +0 -0
  105. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/repository_pb2.py +0 -0
  106. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/repository_pb2_grpc.py +0 -0
  107. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/server_pb2.py +0 -0
  108. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/server_pb2_grpc.py +0 -0
  109. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/shared_pb2.py +0 -0
  110. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/stub/shared_pb2_grpc.py +0 -0
  111. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tag.py +0 -0
  112. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/__init__.py +0 -0
  113. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/bundle.py +0 -0
  114. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/context.py +0 -0
  115. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/grpc.py +0 -0
  116. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/multiprocessing.py +0 -0
  117. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/ssh.py +0 -0
  118. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/sshd.py +0 -0
  119. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/storage.py +0 -0
  120. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/tests/__init__.py +0 -0
  121. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/testing/tests/test_sshd.py +0 -0
  122. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/__init__.py +0 -0
  123. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/common.py +0 -0
  124. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_branch.py +0 -0
  125. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_diff.py +0 -0
  126. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_errors.py +0 -0
  127. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_feature.py +0 -0
  128. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_file_context.py +0 -0
  129. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_gitlab_ref.py +0 -0
  130. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_identification.py +0 -0
  131. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_manifest.py +0 -0
  132. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_messages.py +0 -0
  133. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_oid.py +0 -0
  134. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_peer.py +0 -0
  135. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_repository.py +0 -0
  136. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_revision.py +0 -0
  137. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_revset.py +0 -0
  138. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_servicer.py +0 -0
  139. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_stream.py +0 -0
  140. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_tag.py +0 -0
  141. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/tests/test_workdir.py +0 -0
  142. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/util.py +0 -0
  143. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly/workdir.py +0 -0
  144. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly.egg-info/SOURCES.txt +0 -0
  145. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly.egg-info/dependency_links.txt +0 -0
  146. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly.egg-info/entry_points.txt +0 -0
  147. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly.egg-info/requires.txt +0 -0
  148. {hgitaly-18.2.1 → hgitaly-18.2.3}/hgitaly.egg-info/top_level.txt +0 -0
  149. {hgitaly-18.2.1 → hgitaly-18.2.3}/install-requirements.txt +0 -0
  150. {hgitaly-18.2.1 → hgitaly-18.2.3}/setup.cfg +0 -0
  151. {hgitaly-18.2.1 → hgitaly-18.2.3}/setup.py +0 -0
  152. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/__init__.py +0 -0
  153. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/comparison.py +0 -0
  154. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/conftest.py +0 -0
  155. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/gitaly.py +0 -0
  156. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/hgitaly_rhgitaly_comparison.py +0 -0
  157. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/rhgitaly.py +0 -0
  158. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_blob_tree.py +0 -0
  159. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_commit.py +0 -0
  160. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_comparison.py +0 -0
  161. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_diff.py +0 -0
  162. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_gitaly_server.py +0 -0
  163. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_mercurial_aux_git.py +0 -0
  164. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_mercurial_operations.py +0 -0
  165. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_mercurial_repository.py +0 -0
  166. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_ref.py +0 -0
  167. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_remote.py +0 -0
  168. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_repository_service.py +0 -0
  169. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_rhgitaly_server.py +0 -0
  170. {hgitaly-18.2.1 → hgitaly-18.2.3}/tests_with_gitaly/test_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 18.2.1
3
+ Version: 18.2.3
4
4
  Summary: Server-side implementation of Gitaly protocol for Mercurial
5
5
  Home-page: https://foss.heptapod.net/heptapod/hgitaly
6
6
  Author: Georges Racinet
@@ -0,0 +1 @@
1
+ 18.2.3
@@ -43,6 +43,7 @@ from ..revision import (
43
43
  changeset_by_commit_id_abort,
44
44
  gitlab_revision_changeset,
45
45
  validate_oid,
46
+ ZERO_SHA,
46
47
  )
47
48
  from ..servicer import HGitalyServicer
48
49
 
@@ -346,13 +347,18 @@ class OperationServicer(OperationServiceServicer, HGitalyServicer):
346
347
  and repo.ui.configbool(b'experimental',
347
348
  b'topic.publish-bare-branch'))
348
349
 
350
+ old_oid = commit_header.expected_old_oid.encode('ascii')
349
351
  start_ctx = gitlab_revision_changeset(repo, start_rev)
350
352
  if start_ctx is None:
351
- if len(repo) > 0:
353
+ if len(repo) > 0 and old_oid != ZERO_SHA:
352
354
  context.abort(StatusCode.INTERNAL,
353
355
  "Unresolvable start ref or commit")
354
356
  else:
355
357
  repo_created = branch_created = True
358
+ # now that sanity checks are done, we can normalize to null
359
+ # changeset if needed.
360
+ if start_ctx is None and old_oid == ZERO_SHA:
361
+ start_ctx = repo[ZERO_SHA]
356
362
  if commit_header.branch_name:
357
363
  old_oid = commit_header.expected_old_oid.encode('ascii')
358
364
  if old_oid and start_ctx.hex() != old_oid:
@@ -420,7 +426,9 @@ class OperationServicer(OperationServiceServicer, HGitalyServicer):
420
426
 
421
427
  if header.action in (ActionType.CREATE,
422
428
  ActionType.UPDATE):
423
- content_handler = UserCommitFilesContent(wd, header)
429
+ content_handler = UserCommitFilesContent(
430
+ context, wd, header
431
+ )
424
432
  else:
425
433
  content_handler = None
426
434
 
@@ -471,6 +479,31 @@ class OperationServicer(OperationServiceServicer, HGitalyServicer):
471
479
  )
472
480
 
473
481
 
482
+ def validate_checkout_path(context, relpath):
483
+ # absolute paths are interpreted by Gitaly as relative to the
484
+ # root of checkout.
485
+ relpath = relpath.lstrip(b'/')
486
+
487
+ for p in FORBIDDEN_IN_PATHS:
488
+ if p in relpath:
489
+ relpath_str = relpath.decode('utf-8', 'surrogateescape')
490
+
491
+ if p == DIRECTORY_CLIMB_UP:
492
+ # ill-named by upstream
493
+ error_type = 'ERROR_TYPE_DIRECTORY_TRAVERSAL'
494
+ msg = 'Path cannot include directory traversal'
495
+ else:
496
+ error_type = 'ERROR_TYPE_INVALID_PATH'
497
+ msg = f'invalid path: "{relpath_str}"'
498
+
499
+ index_error(context,
500
+ status_code='INVALID_ARGUMENT',
501
+ error_type=error_type,
502
+ msg=msg,
503
+ path=relpath)
504
+ return relpath
505
+
506
+
474
507
  class UserCommitFilesAction:
475
508
 
476
509
  def __init__(self, context, header, working_dir, changed_files):
@@ -479,9 +512,8 @@ class UserCommitFilesAction:
479
512
  self.changed_files = changed_files
480
513
 
481
514
  wd = self.working_dir = working_dir
482
- relpath = self.relpath = header.file_path
483
- self.validate(relpath)
484
- self.abspath = wd.file_path(relpath)
515
+ self.relpath = validate_checkout_path(context, header.file_path)
516
+ self.abspath = wd.file_path(self.relpath)
485
517
 
486
518
  def __call__(self):
487
519
  action = self.header.action
@@ -498,36 +530,6 @@ class UserCommitFilesAction:
498
530
  elif action == ActionType.CHMOD:
499
531
  return self.chmod()
500
532
 
501
- def validate(self, relpath):
502
- if os.path.isabs(relpath):
503
- index_error(
504
- self.context,
505
- status_code='INVALID_ARGUMENT',
506
- error_type='ERROR_TYPE_INVALID_PATH',
507
- msg='absolute',
508
- path=relpath,
509
- )
510
-
511
- for p in FORBIDDEN_IN_PATHS:
512
- if p in relpath:
513
- relpath_str = relpath.decode('utf-8', 'surrogateescape')
514
-
515
- if p == DIRECTORY_CLIMB_UP:
516
- # ill-named by upstream
517
- error_type = 'ERROR_TYPE_DIRECTORY_TRAVERSAL'
518
- msg = 'Path cannot include directory traversal'
519
- else:
520
- error_type = 'ERROR_TYPE_INVALID_PATH'
521
- msg = f'invalid path: "{relpath_str}"'
522
-
523
- index_error(
524
- self.context,
525
- status_code='INVALID_ARGUMENT',
526
- error_type=error_type,
527
- msg=msg,
528
- path=relpath,
529
- )
530
-
531
533
  def create(self):
532
534
  if os.path.exists(self.abspath):
533
535
  index_error(
@@ -594,8 +596,8 @@ class UserCommitFilesAction:
594
596
  def move(self):
595
597
  self.require_file_absence()
596
598
  abspath = self.abspath
597
- prev_relpath = self.header.previous_path
598
- self.validate(prev_relpath)
599
+ prev_relpath = validate_checkout_path(self.context,
600
+ self.header.previous_path)
599
601
  prev_abspath = self.working_dir.file_path(prev_relpath)
600
602
  self.require_file_existence(abspath=prev_abspath,
601
603
  relpath=prev_relpath)
@@ -630,8 +632,9 @@ class UserCommitFilesAction:
630
632
 
631
633
  class UserCommitFilesContent:
632
634
 
633
- def __init__(self, workdir, header):
634
- self.file_path = workdir.file_path(header.file_path)
635
+ def __init__(self, context, workdir, header):
636
+ relpath = validate_checkout_path(context, header.file_path)
637
+ self.file_path = workdir.file_path(relpath)
635
638
  self.fobj = open(self.file_path, 'wb')
636
639
  self.make_hg_executable = (header.action == ActionType.CREATE
637
640
  and header.execute_filemode)
@@ -581,6 +581,26 @@ def test_user_commit_files(operations_fixture, tmpdir):
581
581
  )
582
582
  assert not resp.HasField('branch_update')
583
583
 
584
+ # Special case for NULL
585
+ # (this normally done at repo creation, for the README)
586
+ resp = commit_files(
587
+ branch_name=b'branch/newroot',
588
+ commit_message=b'starting from NULL',
589
+ expected_old_oid='0000' * 10,
590
+ actions=(dict(action=ActionType.CREATE,
591
+ file_path=b'from_null',
592
+ content=b"it is admissible",
593
+ ),
594
+ )
595
+ )
596
+ hex10 = resp.branch_update.commit_id.encode()
597
+ wrapper.reload()
598
+ ctx10 = wrapper.repo[hex10]
599
+ # without special provisions for old_oid, the changeset would be
600
+ # stacked on the previous head of default
601
+ assert ctx10.p1().rev() == -1
602
+ assert ctx10.branch() == b'newroot'
603
+
584
604
  #
585
605
  # Error cases
586
606
  #
@@ -737,7 +757,7 @@ def test_user_commit_files(operations_fixture, tmpdir):
737
757
  assert exc_info.value.code() == StatusCode.ALREADY_EXISTS
738
758
 
739
759
  # invalid paths
740
- for path in ('double//slash', '../../../good.joke', '/etc/shadow'):
760
+ for path in ('double//slash', '../../../good.joke'):
741
761
  with pytest.raises(RpcError) as exc_info:
742
762
  commit_files(
743
763
  branch_name=gl_branch,
@@ -773,6 +793,21 @@ def test_user_commit_files(operations_fixture, tmpdir):
773
793
  )
774
794
  assert exc_info.value.code() == StatusCode.INVALID_ARGUMENT
775
795
 
796
+ # leading slash is interpreted as meaning the root of checkout
797
+ resp = commit_files(
798
+ branch_name=gl_branch,
799
+ commit_message=b'Deleted intopic',
800
+ actions=(dict(action=ActionType.CREATE,
801
+ file_path=b'/etc/shadow',
802
+ content=b"This is in repo!",
803
+ ),
804
+ )
805
+ )
806
+ hex11 = resp.branch_update.commit_id.encode()
807
+ wrapper.reload()
808
+ clone_pull_update(hex11)
809
+ assert (clone.path / 'etc/shadow').read_binary() == b"This is in repo!"
810
+
776
811
  # bogus request flows
777
812
  header_req = fixture.user_commit_files_header(
778
813
  branch_name=gl_other_branch,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 18.2.1
3
+ Version: 18.2.3
4
4
  Summary: Server-side implementation of Gitaly protocol for Mercurial
5
5
  Home-page: https://foss.heptapod.net/heptapod/hgitaly
6
6
  Author: Georges Racinet
@@ -382,7 +382,7 @@ def test_compare_commit_files(comparison):
382
382
  branch_name=b'branch/default',
383
383
  tail_requests=ucf_actions(dict(
384
384
  action=ActionType.CREATE,
385
- file_path=b'foo',
385
+ file_path=b'/foo',
386
386
  content=b'foo content')),
387
387
  )
388
388
 
@@ -498,8 +498,7 @@ def test_compare_commit_files(comparison):
498
498
  ))
499
499
  )
500
500
 
501
- # invalid path (Gitaly does not reject absolute paths and actually
502
- # seems to ignore them, thankfully)
501
+ # invalid path
503
502
  for path in ('double//slash', '../../../good.joke'):
504
503
  for action in ('CREATE', 'CREATE_DIR', 'CHMOD',
505
504
  'UPDATE', 'DELETE', 'MOVE'):
@@ -1 +0,0 @@
1
- 18.2.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes