scmrepo 3.3.4__tar.gz → 3.3.6__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.
Potentially problematic release.
This version of scmrepo might be problematic. Click here for more details.
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.github/workflows/tests.yaml +3 -4
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.pre-commit-config.yaml +2 -2
- {scmrepo-3.3.4/src/scmrepo.egg-info → scmrepo-3.3.6}/PKG-INFO +2 -2
- {scmrepo-3.3.4 → scmrepo-3.3.6}/noxfile.py +0 -8
- {scmrepo-3.3.4 → scmrepo-3.3.6}/pyproject.toml +8 -5
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/dulwich/asyncssh_vendor.py +5 -5
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/dulwich/client.py +1 -1
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/gitpython.py +1 -1
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/pygit2/__init__.py +55 -78
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/pygit2/callbacks.py +1 -1
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/credentials.py +12 -12
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/fetch.py +2 -2
- {scmrepo-3.3.4 → scmrepo-3.3.6/src/scmrepo.egg-info}/PKG-INFO +2 -2
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo.egg-info/requires.txt +1 -1
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/docker-compose.yml +2 -2
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_dulwich.py +75 -7
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.coveragerc +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.cruft.json +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.gitattributes +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.github/dependabot.yml +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.github/workflows/release.yaml +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.github/workflows/update-template.yaml +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/.gitignore +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/CODE_OF_CONDUCT.rst +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/CONTRIBUTING.rst +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/LICENSE +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/README.rst +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/setup.cfg +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/asyn.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/base.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/exceptions.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/fs.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/base.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/dulwich/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/backend/pygit2/filter.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/config.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/client.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/exceptions.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/object.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/pointer.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/progress.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/smudge.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/lfs/storage.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/objects.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/git/stash.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/noscm.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/progress.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/py.typed +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/urls.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo/utils.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo.egg-info/SOURCES.txt +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo.egg-info/dependency_links.txt +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/src/scmrepo.egg-info/top_level.txt +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/conftest.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/git-init/git.sh +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_credentials.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_fs.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_git.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_lfs.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_noscm.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_pygit2.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_scmrepo.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_stash.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/test_urls.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/user.key +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/user.key.pub +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/vendor/__init__.py +0 -0
- {scmrepo-3.3.4 → scmrepo-3.3.6}/tests/vendor/test_paramiko_vendor.py +0 -0
|
@@ -40,12 +40,11 @@ jobs:
|
|
|
40
40
|
pip --version
|
|
41
41
|
nox --version
|
|
42
42
|
|
|
43
|
-
- name: Lint code
|
|
44
|
-
|
|
45
|
-
run: nox -s lint safety --verbose
|
|
43
|
+
- name: Lint code
|
|
44
|
+
run: nox -s lint
|
|
46
45
|
|
|
47
46
|
- name: Run tests
|
|
48
|
-
run: nox -s tests-${{ matrix.
|
|
47
|
+
run: nox -s tests-${{ matrix.pyv }} -- --slow --cov-report=xml
|
|
49
48
|
|
|
50
49
|
- name: Upload coverage report
|
|
51
50
|
uses: codecov/codecov-action@v3.1.0
|
|
@@ -20,13 +20,13 @@ repos:
|
|
|
20
20
|
- id: sort-simple-yaml
|
|
21
21
|
- id: trailing-whitespace
|
|
22
22
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
23
|
-
rev: 'v0.
|
|
23
|
+
rev: 'v0.5.0'
|
|
24
24
|
hooks:
|
|
25
25
|
- id: ruff
|
|
26
26
|
args: [--fix, --exit-non-zero-on-fix]
|
|
27
27
|
- id: ruff-format
|
|
28
28
|
- repo: https://github.com/codespell-project/codespell
|
|
29
|
-
rev: v2.
|
|
29
|
+
rev: v2.3.0
|
|
30
30
|
hooks:
|
|
31
31
|
- id: codespell
|
|
32
32
|
additional_dependencies: ["tomli"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: scmrepo
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.6
|
|
4
4
|
Summary: scmrepo
|
|
5
5
|
Author-email: Iterative <support@dvc.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -36,7 +36,7 @@ Requires-Dist: pytest-mock; extra == "tests"
|
|
|
36
36
|
Requires-Dist: pytest-sugar; extra == "tests"
|
|
37
37
|
Requires-Dist: pytest-test-utils<0.2,>=0.1.0; extra == "tests"
|
|
38
38
|
Provides-Extra: dev
|
|
39
|
-
Requires-Dist: mypy==1.10.
|
|
39
|
+
Requires-Dist: mypy==1.10.1; extra == "dev"
|
|
40
40
|
Requires-Dist: scmrepo[tests]; extra == "dev"
|
|
41
41
|
Requires-Dist: types-certifi; extra == "dev"
|
|
42
42
|
Requires-Dist: types-mock; extra == "dev"
|
|
@@ -32,14 +32,6 @@ def lint(session: nox.Session) -> None:
|
|
|
32
32
|
session.run("python", "-m", "mypy")
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
@nox.session
|
|
36
|
-
def safety(session: nox.Session) -> None:
|
|
37
|
-
"""Scan dependencies for insecure packages."""
|
|
38
|
-
session.install(".[dev]")
|
|
39
|
-
session.install("safety")
|
|
40
|
-
session.run("safety", "check", "--full-report", "--ignore=67599")
|
|
41
|
-
|
|
42
|
-
|
|
43
35
|
@nox.session
|
|
44
36
|
def build(session: nox.Session) -> None:
|
|
45
37
|
session.install("build", "setuptools", "twine")
|
|
@@ -50,7 +50,7 @@ tests = [
|
|
|
50
50
|
"pytest-test-utils>=0.1.0,<0.2",
|
|
51
51
|
]
|
|
52
52
|
dev = [
|
|
53
|
-
"mypy==1.10.
|
|
53
|
+
"mypy==1.10.1",
|
|
54
54
|
"scmrepo[tests]",
|
|
55
55
|
"types-certifi",
|
|
56
56
|
"types-mock",
|
|
@@ -123,8 +123,13 @@ ignore_missing_imports = true
|
|
|
123
123
|
|
|
124
124
|
[tool.codespell]
|
|
125
125
|
ignore-words-list = "cachable, keypair"
|
|
126
|
+
skip = "CODE_OF_CONDUCT.rst"
|
|
126
127
|
|
|
127
128
|
[tool.ruff]
|
|
129
|
+
output-format = "full"
|
|
130
|
+
show-fixes = true
|
|
131
|
+
|
|
132
|
+
[tool.ruff.lint]
|
|
128
133
|
ignore = [
|
|
129
134
|
"S101", # assert
|
|
130
135
|
"PLR2004", # magic-value-comparison
|
|
@@ -180,10 +185,8 @@ select = [
|
|
|
180
185
|
"W", # pycodestyle - Warning
|
|
181
186
|
"YTT", # flake8-2020
|
|
182
187
|
]
|
|
183
|
-
show-source = true
|
|
184
|
-
show-fixes = true
|
|
185
188
|
|
|
186
|
-
[tool.ruff.per-file-ignores]
|
|
189
|
+
[tool.ruff.lint.per-file-ignores]
|
|
187
190
|
"noxfile.py" = ["D", "PTH"]
|
|
188
191
|
"tests/**" = ["S", "ARG001", "ARG002", "ANN"]
|
|
189
192
|
"docs/**" = ["INP"]
|
|
@@ -199,5 +202,5 @@ strict = true
|
|
|
199
202
|
[tool.ruff.lint.isort]
|
|
200
203
|
known-first-party = ["scmrepo"]
|
|
201
204
|
|
|
202
|
-
[tool.ruff.pylint]
|
|
205
|
+
[tool.ruff.lint.pylint]
|
|
203
206
|
max-args = 10
|
|
@@ -66,8 +66,8 @@ class _StderrWrapper:
|
|
|
66
66
|
class AsyncSSHWrapper(BaseAsyncObject):
|
|
67
67
|
def __init__(self, conn: "SSHClientConnection", proc: "SSHClientProcess", **kwargs):
|
|
68
68
|
super().__init__(**kwargs)
|
|
69
|
-
self.conn:
|
|
70
|
-
self.proc:
|
|
69
|
+
self.conn: SSHClientConnection = conn
|
|
70
|
+
self.proc: SSHClientProcess = proc
|
|
71
71
|
self.stderr = _StderrWrapper(proc.stderr, self.loop)
|
|
72
72
|
|
|
73
73
|
def can_read(self) -> bool:
|
|
@@ -152,7 +152,7 @@ class InteractiveSSHClient(SSHClient):
|
|
|
152
152
|
def connection_lost(self, exc: Optional[Exception]) -> None:
|
|
153
153
|
self._conn = None
|
|
154
154
|
|
|
155
|
-
async def public_key_auth_requested( # noqa: C901
|
|
155
|
+
async def public_key_auth_requested( # noqa: C901
|
|
156
156
|
self,
|
|
157
157
|
) -> Optional["KeyPairListArg"]:
|
|
158
158
|
from asyncssh.public_key import (
|
|
@@ -298,7 +298,7 @@ class AsyncSSHVendor(BaseAsyncObject, SSHVendor):
|
|
|
298
298
|
host,
|
|
299
299
|
port=port if port is not None else (),
|
|
300
300
|
username=username if username is not None else (),
|
|
301
|
-
password=password
|
|
301
|
+
password=password,
|
|
302
302
|
client_keys=[key_filename] if key_filename else (),
|
|
303
303
|
ignore_encrypted=not key_filename,
|
|
304
304
|
known_hosts=None,
|
|
@@ -320,7 +320,7 @@ def get_unsupported_opts(config_paths: "ConfigPaths") -> Iterator[str]:
|
|
|
320
320
|
|
|
321
321
|
if config_paths:
|
|
322
322
|
if isinstance(config_paths, (str, PurePath)):
|
|
323
|
-
paths: Sequence[
|
|
323
|
+
paths: Sequence[FilePath] = [config_paths]
|
|
324
324
|
else:
|
|
325
325
|
paths = config_paths
|
|
326
326
|
|
|
@@ -22,7 +22,7 @@ class GitCredentialsHTTPClient(Urllib3HttpGitClient): # pylint: disable=abstrac
|
|
|
22
22
|
config=config,
|
|
23
23
|
**kwargs,
|
|
24
24
|
)
|
|
25
|
-
self._store_credentials: Optional[
|
|
25
|
+
self._store_credentials: Optional[Credential] = None
|
|
26
26
|
|
|
27
27
|
def _http_request(
|
|
28
28
|
self,
|
|
@@ -468,7 +468,7 @@ class GitPythonBackend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
468
468
|
except GitCommandError as exc:
|
|
469
469
|
raise SCMError(f"Failed to set ref '{name}'") from exc
|
|
470
470
|
|
|
471
|
-
def get_ref(self, name: str, follow: bool = True) -> Optional[str]: # noqa: C901, PLR0911
|
|
471
|
+
def get_ref(self, name: str, follow: bool = True) -> Optional[str]: # noqa: C901, PLR0911
|
|
472
472
|
from git.exc import GitCommandError
|
|
473
473
|
|
|
474
474
|
if name == "HEAD":
|
|
@@ -34,6 +34,7 @@ logger = logging.getLogger(__name__)
|
|
|
34
34
|
if TYPE_CHECKING:
|
|
35
35
|
from pygit2 import Commit, Oid, Signature
|
|
36
36
|
from pygit2.config import Config as _Pygit2Config
|
|
37
|
+
from pygit2.enums import CheckoutStrategy
|
|
37
38
|
from pygit2.remotes import Remote
|
|
38
39
|
from pygit2.repository import Repository
|
|
39
40
|
|
|
@@ -246,17 +247,15 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
246
247
|
)
|
|
247
248
|
|
|
248
249
|
@staticmethod
|
|
249
|
-
def _get_checkout_strategy(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES,
|
|
254
|
-
)
|
|
250
|
+
def _get_checkout_strategy(
|
|
251
|
+
strategy: Optional["CheckoutStrategy"] = None,
|
|
252
|
+
) -> "CheckoutStrategy":
|
|
253
|
+
from pygit2.enums import CheckoutStrategy
|
|
255
254
|
|
|
256
255
|
if strategy is None:
|
|
257
|
-
strategy =
|
|
256
|
+
strategy = CheckoutStrategy.SAFE | CheckoutStrategy.RECREATE_MISSING
|
|
258
257
|
if os.name == "nt":
|
|
259
|
-
strategy |=
|
|
258
|
+
strategy |= CheckoutStrategy.SKIP_LOCKED_DIRECTORIES
|
|
260
259
|
return strategy
|
|
261
260
|
|
|
262
261
|
# Workaround to force git_backend_odb_pack to release open file handles
|
|
@@ -343,9 +342,12 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
343
342
|
force: bool = False,
|
|
344
343
|
**kwargs,
|
|
345
344
|
):
|
|
346
|
-
from pygit2 import
|
|
345
|
+
from pygit2 import GitError
|
|
346
|
+
from pygit2.enums import CheckoutStrategy
|
|
347
347
|
|
|
348
|
-
strategy = self._get_checkout_strategy(
|
|
348
|
+
strategy = self._get_checkout_strategy(
|
|
349
|
+
CheckoutStrategy.FORCE if force else None
|
|
350
|
+
)
|
|
349
351
|
|
|
350
352
|
with self.release_odb_handles():
|
|
351
353
|
if create_new:
|
|
@@ -613,7 +615,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
613
615
|
force: bool = False,
|
|
614
616
|
on_diverged: Optional[Callable[[str, str], bool]] = None,
|
|
615
617
|
) -> SyncStatus:
|
|
616
|
-
import
|
|
618
|
+
from pygit2.enums import MergeAnalysis
|
|
617
619
|
|
|
618
620
|
rh_rev = self.resolve_rev(rh)
|
|
619
621
|
|
|
@@ -627,16 +629,16 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
627
629
|
self.set_ref(lh, rh_rev)
|
|
628
630
|
return SyncStatus.SUCCESS
|
|
629
631
|
|
|
630
|
-
if merge_result &
|
|
632
|
+
if merge_result & MergeAnalysis.UP_TO_DATE:
|
|
631
633
|
return SyncStatus.UP_TO_DATE
|
|
632
|
-
if merge_result &
|
|
634
|
+
if merge_result & MergeAnalysis.FASTFORWARD:
|
|
633
635
|
self.set_ref(lh, rh_rev)
|
|
634
636
|
return SyncStatus.SUCCESS
|
|
635
|
-
if merge_result &
|
|
637
|
+
if merge_result & MergeAnalysis.NORMAL:
|
|
636
638
|
if on_diverged and on_diverged(lh, rh_rev):
|
|
637
639
|
return SyncStatus.SUCCESS
|
|
638
640
|
return SyncStatus.DIVERGED
|
|
639
|
-
logger.debug("Unexpected merge result: %s",
|
|
641
|
+
logger.debug("Unexpected merge result: %s", MergeAnalysis.NORMAL)
|
|
640
642
|
raise SCMError("Unknown merge analysis result")
|
|
641
643
|
|
|
642
644
|
@contextmanager
|
|
@@ -696,7 +698,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
696
698
|
SCMError(f"Git failed to fetch ref from '{url}'"),
|
|
697
699
|
):
|
|
698
700
|
with RemoteCallbacks(progress=progress) as cb:
|
|
699
|
-
remote_refs: dict[str,
|
|
701
|
+
remote_refs: dict[str, Oid] = (
|
|
700
702
|
{
|
|
701
703
|
head["name"]: head["oid"]
|
|
702
704
|
for head in remote.ls_remotes(callbacks=cb)
|
|
@@ -710,7 +712,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
710
712
|
message="fetch",
|
|
711
713
|
)
|
|
712
714
|
|
|
713
|
-
result: dict[str,
|
|
715
|
+
result: dict[str, SyncStatus] = {}
|
|
714
716
|
for refspec in refspecs:
|
|
715
717
|
lh, rh = refspec.split(":")
|
|
716
718
|
if lh.endswith("*"):
|
|
@@ -779,7 +781,8 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
779
781
|
skip_conflicts: bool = False,
|
|
780
782
|
**kwargs,
|
|
781
783
|
):
|
|
782
|
-
from pygit2 import
|
|
784
|
+
from pygit2 import GitError
|
|
785
|
+
from pygit2.enums import CheckoutStrategy
|
|
783
786
|
|
|
784
787
|
from scmrepo.git import Stash
|
|
785
788
|
|
|
@@ -788,7 +791,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
788
791
|
self.repo.index.read(False)
|
|
789
792
|
strategy = self._get_checkout_strategy()
|
|
790
793
|
if skip_conflicts:
|
|
791
|
-
strategy |=
|
|
794
|
+
strategy |= CheckoutStrategy.ALLOW_CONFLICTS
|
|
792
795
|
self.repo.stash_apply(
|
|
793
796
|
index, strategy=strategy, reinstate_index=reinstate_index
|
|
794
797
|
)
|
|
@@ -834,7 +837,8 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
834
837
|
raise NotImplementedError
|
|
835
838
|
|
|
836
839
|
def reset(self, hard: bool = False, paths: Optional[Iterable[str]] = None):
|
|
837
|
-
from pygit2 import
|
|
840
|
+
from pygit2 import IndexEntry
|
|
841
|
+
from pygit2.enums import ResetMode
|
|
838
842
|
|
|
839
843
|
self.repo.index.read(False)
|
|
840
844
|
if paths is not None:
|
|
@@ -847,9 +851,9 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
847
851
|
self.repo.index.add(IndexEntry(rel, obj.id, obj.filemode))
|
|
848
852
|
self.repo.index.write()
|
|
849
853
|
elif hard:
|
|
850
|
-
self.repo.reset(self.repo.head.target,
|
|
854
|
+
self.repo.reset(self.repo.head.target, ResetMode.HARD)
|
|
851
855
|
else:
|
|
852
|
-
self.repo.reset(self.repo.head.target,
|
|
856
|
+
self.repo.reset(self.repo.head.target, ResetMode.MIXED)
|
|
853
857
|
|
|
854
858
|
def checkout_index(
|
|
855
859
|
self,
|
|
@@ -858,22 +862,17 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
858
862
|
ours: bool = False,
|
|
859
863
|
theirs: bool = False,
|
|
860
864
|
):
|
|
861
|
-
from pygit2 import
|
|
862
|
-
GIT_CHECKOUT_ALLOW_CONFLICTS,
|
|
863
|
-
GIT_CHECKOUT_FORCE,
|
|
864
|
-
GIT_CHECKOUT_RECREATE_MISSING,
|
|
865
|
-
GIT_CHECKOUT_SAFE,
|
|
866
|
-
)
|
|
865
|
+
from pygit2.enums import CheckoutStrategy
|
|
867
866
|
|
|
868
867
|
assert not (ours and theirs)
|
|
869
|
-
strategy =
|
|
868
|
+
strategy = CheckoutStrategy.RECREATE_MISSING
|
|
870
869
|
if force or ours or theirs:
|
|
871
|
-
strategy |=
|
|
870
|
+
strategy |= CheckoutStrategy.FORCE
|
|
872
871
|
else:
|
|
873
|
-
strategy |=
|
|
872
|
+
strategy |= CheckoutStrategy.SAFE
|
|
874
873
|
|
|
875
874
|
if ours or theirs:
|
|
876
|
-
strategy |=
|
|
875
|
+
strategy |= CheckoutStrategy.ALLOW_CONFLICTS
|
|
877
876
|
strategy = self._get_checkout_strategy(strategy)
|
|
878
877
|
|
|
879
878
|
index = self.repo.index
|
|
@@ -910,18 +909,7 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
910
909
|
def status(
|
|
911
910
|
self, ignored: bool = False, untracked_files: str = "all"
|
|
912
911
|
) -> tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
|
|
913
|
-
from pygit2 import
|
|
914
|
-
GIT_STATUS_IGNORED,
|
|
915
|
-
GIT_STATUS_INDEX_DELETED,
|
|
916
|
-
GIT_STATUS_INDEX_MODIFIED,
|
|
917
|
-
GIT_STATUS_INDEX_NEW,
|
|
918
|
-
GIT_STATUS_WT_DELETED,
|
|
919
|
-
GIT_STATUS_WT_MODIFIED,
|
|
920
|
-
GIT_STATUS_WT_NEW,
|
|
921
|
-
GIT_STATUS_WT_RENAMED,
|
|
922
|
-
GIT_STATUS_WT_TYPECHANGE,
|
|
923
|
-
GIT_STATUS_WT_UNREADABLE,
|
|
924
|
-
)
|
|
912
|
+
from pygit2.enums import FileStatus
|
|
925
913
|
|
|
926
914
|
staged: Mapping[str, list[str]] = {
|
|
927
915
|
"add": [],
|
|
@@ -932,19 +920,19 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
932
920
|
untracked: list[str] = []
|
|
933
921
|
|
|
934
922
|
states = {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
923
|
+
FileStatus.WT_NEW: untracked,
|
|
924
|
+
FileStatus.WT_MODIFIED: unstaged,
|
|
925
|
+
FileStatus.WT_TYPECHANGE: staged["modify"],
|
|
926
|
+
FileStatus.WT_DELETED: staged["modify"],
|
|
927
|
+
FileStatus.WT_RENAMED: staged["modify"],
|
|
928
|
+
FileStatus.INDEX_NEW: staged["add"],
|
|
929
|
+
FileStatus.INDEX_MODIFIED: staged["modify"],
|
|
930
|
+
FileStatus.INDEX_DELETED: staged["delete"],
|
|
931
|
+
FileStatus.WT_UNREADABLE: untracked,
|
|
944
932
|
}
|
|
945
933
|
|
|
946
934
|
if untracked_files != "no" and ignored:
|
|
947
|
-
states[
|
|
935
|
+
states[FileStatus.IGNORED] = untracked
|
|
948
936
|
|
|
949
937
|
for file, state in self.repo.status(
|
|
950
938
|
untracked_files=untracked_files, ignored=ignored
|
|
@@ -970,15 +958,8 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
970
958
|
msg: Optional[str] = None,
|
|
971
959
|
squash: bool = False,
|
|
972
960
|
) -> Optional[str]:
|
|
973
|
-
from pygit2 import
|
|
974
|
-
|
|
975
|
-
GIT_MERGE_ANALYSIS_NONE,
|
|
976
|
-
GIT_MERGE_ANALYSIS_UNBORN,
|
|
977
|
-
GIT_MERGE_ANALYSIS_UP_TO_DATE,
|
|
978
|
-
GIT_MERGE_PREFERENCE_FASTFORWARD_ONLY,
|
|
979
|
-
GIT_MERGE_PREFERENCE_NO_FASTFORWARD,
|
|
980
|
-
GitError,
|
|
981
|
-
)
|
|
961
|
+
from pygit2 import GitError
|
|
962
|
+
from pygit2.enums import MergeAnalysis, MergePreference
|
|
982
963
|
|
|
983
964
|
if commit and squash:
|
|
984
965
|
raise SCMError("Cannot merge with 'squash' and 'commit'")
|
|
@@ -991,9 +972,9 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
991
972
|
except GitError as exc:
|
|
992
973
|
raise SCMError("Merge analysis failed") from exc
|
|
993
974
|
|
|
994
|
-
if analysis ==
|
|
975
|
+
if analysis == MergeAnalysis.NONE:
|
|
995
976
|
raise SCMError(f"'{rev}' cannot be merged into HEAD")
|
|
996
|
-
if analysis &
|
|
977
|
+
if analysis & MergeAnalysis.UP_TO_DATE:
|
|
997
978
|
return None
|
|
998
979
|
|
|
999
980
|
try:
|
|
@@ -1006,15 +987,15 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
1006
987
|
raise MergeConflictError("Merge contained conflicts")
|
|
1007
988
|
|
|
1008
989
|
try:
|
|
1009
|
-
if not (squash or ff_pref &
|
|
1010
|
-
if analysis &
|
|
990
|
+
if not (squash or ff_pref & MergePreference.NO_FASTFORWARD):
|
|
991
|
+
if analysis & MergeAnalysis.FASTFORWARD:
|
|
1011
992
|
return self._merge_ff(rev, obj)
|
|
1012
993
|
|
|
1013
|
-
if analysis &
|
|
994
|
+
if analysis & MergeAnalysis.UNBORN:
|
|
1014
995
|
self.repo.set_head(obj.id)
|
|
1015
996
|
return str(obj.id)
|
|
1016
997
|
|
|
1017
|
-
if ff_pref &
|
|
998
|
+
if ff_pref & MergePreference.FASTFORWARD_ONLY:
|
|
1018
999
|
raise SCMError(f"Cannot fast-forward HEAD to '{rev}'")
|
|
1019
1000
|
|
|
1020
1001
|
if commit:
|
|
@@ -1105,19 +1086,15 @@ class Pygit2Backend(BaseGitBackend): # pylint:disable=abstract-method
|
|
|
1105
1086
|
attr: str,
|
|
1106
1087
|
source: Optional[str] = None,
|
|
1107
1088
|
) -> Optional[Union[bool, str]]:
|
|
1108
|
-
from pygit2 import
|
|
1109
|
-
|
|
1110
|
-
GIT_ATTR_CHECK_INCLUDE_COMMIT,
|
|
1111
|
-
GIT_ATTR_CHECK_INDEX_ONLY,
|
|
1112
|
-
GitError,
|
|
1113
|
-
)
|
|
1089
|
+
from pygit2 import GitError
|
|
1090
|
+
from pygit2.enums import AttrCheck
|
|
1114
1091
|
|
|
1115
|
-
commit: Optional[
|
|
1116
|
-
flags =
|
|
1092
|
+
commit: Optional[Commit] = None
|
|
1093
|
+
flags = AttrCheck.FILE_THEN_INDEX
|
|
1117
1094
|
if source:
|
|
1118
1095
|
try:
|
|
1119
1096
|
commit, _ref = self._resolve_refish(source)
|
|
1120
|
-
flags =
|
|
1097
|
+
flags = AttrCheck.INDEX_ONLY | AttrCheck.INCLUDE_COMMIT
|
|
1121
1098
|
except (KeyError, GitError) as exc:
|
|
1122
1099
|
raise SCMError(f"Invalid commit '{source}'") from exc
|
|
1123
1100
|
try:
|
|
@@ -28,7 +28,7 @@ class RemoteCallbacks(_RemoteCallbacks, AbstractContextManager):
|
|
|
28
28
|
):
|
|
29
29
|
super().__init__(*args, **kwargs)
|
|
30
30
|
self.progress = GitProgressReporter(progress) if progress else None
|
|
31
|
-
self._store_credentials: Optional[
|
|
31
|
+
self._store_credentials: Optional[Credential] = None
|
|
32
32
|
self._tried_credentials = False
|
|
33
33
|
self.result: dict[str, SyncStatus] = {}
|
|
34
34
|
|
|
@@ -136,8 +136,8 @@ class GitCredentialHelper(CredentialHelper):
|
|
|
136
136
|
if not shutil.which(executable) and shutil.which("git"):
|
|
137
137
|
# If the helper cannot be found in PATH, it might be
|
|
138
138
|
# a C git helper in GIT_EXEC_PATH
|
|
139
|
-
git_exec_path = subprocess.check_output(
|
|
140
|
-
("git", "--exec-path"),
|
|
139
|
+
git_exec_path = subprocess.check_output( # noqa: S603
|
|
140
|
+
("git", "--exec-path"),
|
|
141
141
|
text=True,
|
|
142
142
|
).strip()
|
|
143
143
|
if shutil.which(executable, path=git_exec_path):
|
|
@@ -158,8 +158,8 @@ class GitCredentialHelper(CredentialHelper):
|
|
|
158
158
|
helper_input.append("")
|
|
159
159
|
|
|
160
160
|
try:
|
|
161
|
-
res = subprocess.run(
|
|
162
|
-
cmd,
|
|
161
|
+
res = subprocess.run( # noqa: S603
|
|
162
|
+
cmd,
|
|
163
163
|
check=True,
|
|
164
164
|
capture_output=True,
|
|
165
165
|
input="\n".join(helper_input),
|
|
@@ -199,8 +199,8 @@ class GitCredentialHelper(CredentialHelper):
|
|
|
199
199
|
helper_input.append("")
|
|
200
200
|
|
|
201
201
|
try:
|
|
202
|
-
res = subprocess.run(
|
|
203
|
-
cmd,
|
|
202
|
+
res = subprocess.run( # noqa: S603
|
|
203
|
+
cmd,
|
|
204
204
|
capture_output=True,
|
|
205
205
|
input="\n".join(helper_input),
|
|
206
206
|
encoding=self._encoding,
|
|
@@ -224,8 +224,8 @@ class GitCredentialHelper(CredentialHelper):
|
|
|
224
224
|
helper_input.append("")
|
|
225
225
|
|
|
226
226
|
try:
|
|
227
|
-
res = subprocess.run(
|
|
228
|
-
cmd,
|
|
227
|
+
res = subprocess.run( # noqa: S603
|
|
228
|
+
cmd,
|
|
229
229
|
capture_output=True,
|
|
230
230
|
input="\n".join(helper_input),
|
|
231
231
|
encoding=self._encoding,
|
|
@@ -243,7 +243,7 @@ class GitCredentialHelper(CredentialHelper):
|
|
|
243
243
|
) -> Iterator[tuple[str, bool]]:
|
|
244
244
|
config = config or StackedConfig.default()
|
|
245
245
|
if isinstance(config, StackedConfig):
|
|
246
|
-
backends: Iterable[
|
|
246
|
+
backends: Iterable[ConfigDict] = config.backends
|
|
247
247
|
else:
|
|
248
248
|
backends = [config]
|
|
249
249
|
|
|
@@ -324,7 +324,7 @@ class MemoryCredentialHelper(CredentialHelper):
|
|
|
324
324
|
|
|
325
325
|
def __init__(self):
|
|
326
326
|
super().__init__()
|
|
327
|
-
self._credentials: dict[
|
|
327
|
+
self._credentials: dict[_CredentialKey, Credential] = {}
|
|
328
328
|
|
|
329
329
|
def __getitem__(self, key: object) -> "Credential":
|
|
330
330
|
if isinstance(key, _CredentialKey):
|
|
@@ -448,8 +448,8 @@ class _AskpassCommand:
|
|
|
448
448
|
def input(self, prompt: str) -> str:
|
|
449
449
|
argv = [self.command, prompt]
|
|
450
450
|
try:
|
|
451
|
-
res = subprocess.run(
|
|
452
|
-
argv,
|
|
451
|
+
res = subprocess.run( # noqa: S603
|
|
452
|
+
argv,
|
|
453
453
|
check=True,
|
|
454
454
|
capture_output=True,
|
|
455
455
|
encoding=locale.getpreferredencoding(),
|
|
@@ -46,7 +46,7 @@ def fetch(
|
|
|
46
46
|
scm.lfs_storage.fetch(url, objects, progress=progress)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def get_fetch_url(scm: "Git", remote: Optional[str] = None): # noqa: C901
|
|
49
|
+
def get_fetch_url(scm: "Git", remote: Optional[str] = None): # noqa: C901
|
|
50
50
|
"""Return LFS fetch URL for the specified repository."""
|
|
51
51
|
git_config = scm.get_config()
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ def get_fetch_url(scm: "Git", remote: Optional[str] = None): # noqa: C901,PLR09
|
|
|
56
56
|
except KeyError:
|
|
57
57
|
pass
|
|
58
58
|
try:
|
|
59
|
-
lfs_config: Optional[
|
|
59
|
+
lfs_config: Optional[Config] = scm.get_config(
|
|
60
60
|
os.path.join(scm.root_dir, ".lfsconfig")
|
|
61
61
|
)
|
|
62
62
|
except FileNotFoundError:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: scmrepo
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.6
|
|
4
4
|
Summary: scmrepo
|
|
5
5
|
Author-email: Iterative <support@dvc.org>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -36,7 +36,7 @@ Requires-Dist: pytest-mock; extra == "tests"
|
|
|
36
36
|
Requires-Dist: pytest-sugar; extra == "tests"
|
|
37
37
|
Requires-Dist: pytest-test-utils<0.2,>=0.1.0; extra == "tests"
|
|
38
38
|
Provides-Extra: dev
|
|
39
|
-
Requires-Dist: mypy==1.10.
|
|
39
|
+
Requires-Dist: mypy==1.10.1; extra == "dev"
|
|
40
40
|
Requires-Dist: scmrepo[tests]; extra == "dev"
|
|
41
41
|
Requires-Dist: types-certifi; extra == "dev"
|
|
42
42
|
Requires-Dist: types-mock; extra == "dev"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
version: '3.2'
|
|
3
3
|
services:
|
|
4
4
|
git-server:
|
|
5
|
-
image: ghcr.io/linuxserver/openssh-server
|
|
5
|
+
image: ghcr.io/linuxserver/openssh-server
|
|
6
6
|
environment:
|
|
7
7
|
- USER_NAME=user
|
|
8
8
|
- PUBLIC_KEY_FILE=/tmp/key
|
|
@@ -10,4 +10,4 @@ services:
|
|
|
10
10
|
- 2222
|
|
11
11
|
volumes:
|
|
12
12
|
- ./user.key.pub:/tmp/key
|
|
13
|
-
- ./git-init:/
|
|
13
|
+
- ./git-init:/custom-cont-init.d
|
|
@@ -11,18 +11,74 @@ import pytest
|
|
|
11
11
|
from pytest_mock import MockerFixture
|
|
12
12
|
from pytest_test_utils.waiters import wait_until
|
|
13
13
|
|
|
14
|
+
from scmrepo.exceptions import AuthError
|
|
14
15
|
from scmrepo.git.backend.dulwich.asyncssh_vendor import AsyncSSHVendor
|
|
15
16
|
|
|
16
|
-
from .vendor.test_paramiko_vendor import (
|
|
17
|
-
CLIENT_KEY,
|
|
18
|
-
PASSWORD,
|
|
19
|
-
USER,
|
|
20
|
-
Server,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
17
|
# pylint: disable=redefined-outer-name
|
|
24
18
|
|
|
25
19
|
|
|
20
|
+
USER = "testuser"
|
|
21
|
+
PASSWORD = "test"
|
|
22
|
+
CLIENT_KEY = """-----BEGIN RSA PRIVATE KEY-----
|
|
23
|
+
MIIEpAIBAAKCAQEAxvREKSElPOm/0z/nPO+j5rk2tjdgGcGc7We1QZ6TRXYLu7nN
|
|
24
|
+
GeEFIL4p8N1i6dmB+Eydt7xqCU79MWD6Yy4prFe1+/K1wCDUxIbFMxqQcX5zjJzd
|
|
25
|
+
i8j8PbcaUlVhP/OkjtkSxrXaGDO1BzfdV4iEBtTV/2l3zmLKJlt3jnOHLczP24CB
|
|
26
|
+
DTQKp3rKshbRefzot9Y+wnaK692RsYgsyo9YEP0GyWKG9topCHk13r46J6vGLeuj
|
|
27
|
+
ryUKqmbLJkzbJbIcEqwTDo5iHaCVqaMr5Hrb8BdMucSseqZQJsXSd+9tdRcIblUQ
|
|
28
|
+
38kZjmFMm4SFbruJcpZCNM2wNSZPIRX+3eiwNwIDAQABAoIBAHSacOBSJsr+jIi5
|
|
29
|
+
KUOTh9IPtzswVUiDKwARCjB9Sf8p4lKR4N1L/n9kNJyQhApeikgGT2GCMftmqgoo
|
|
30
|
+
tlculQoHFgemBlOmak0MV8NNzF5YKEy/GzF0CDH7gJfEpoyetVFrdA+2QS5yD6U9
|
|
31
|
+
XqKQxiBi2VEqdScmyyeT8AwzNYTnPeH/DOEcnbdRjqiy/CD79F49CQ1lX1Fuqm0K
|
|
32
|
+
I7BivBH1xo/rVnUP4F+IzocDqoga+Pjdj0LTXIgJlHQDSbhsQqWujWQDDuKb+MAw
|
|
33
|
+
sNK4Zf8ErV3j1PyA7f/M5LLq6zgstkW4qikDHo4SpZX8kFOO8tjqb7kujj7XqeaB
|
|
34
|
+
CxqrOTECgYEA73uWkrohcmDJ4KqbuL3tbExSCOUiaIV+sT1eGPNi7GCmXD4eW5Z4
|
|
35
|
+
75v2IHymW83lORSu/DrQ6sKr1nkuRpqr2iBzRmQpl/H+wahIhBXlnJ25uUjDsuPO
|
|
36
|
+
1Pq2LcmyD+jTxVnmbSe/q7O09gZQw3I6H4+BMHmpbf8tC97lqimzpJ0CgYEA1K0W
|
|
37
|
+
ZL70Xtn9quyHvbtae/BW07NZnxvUg4UaVIAL9Zu34JyplJzyzbIjrmlDbv6aRogH
|
|
38
|
+
/KtuG9tfbf55K/jjqNORiuRtzt1hUN1ye4dyW7tHx2/7lXdlqtyK40rQl8P0kqf8
|
|
39
|
+
zaS6BqjnobgSdSpg32rWoL/pcBHPdJCJEgQ8zeMCgYEA0/PK8TOhNIzrP1dgGSKn
|
|
40
|
+
hkkJ9etuB5nW5mEM7gJDFDf6JPupfJ/xiwe6z0fjKK9S57EhqgUYMB55XYnE5iIw
|
|
41
|
+
ZQ6BV9SAZ4V7VsRs4dJLdNC3tn/rDGHJBgCaym2PlbsX6rvFT+h1IC8dwv0V79Ui
|
|
42
|
+
Ehq9WTzkMoE8yhvNokvkPZUCgYEAgBAFxv5xGdh79ftdtXLmhnDvZ6S8l6Fjcxqo
|
|
43
|
+
Ay/jg66Tp43OU226iv/0mmZKM8Dd1xC8dnon4GBVc19jSYYiWBulrRPlx0Xo/o+K
|
|
44
|
+
CzZBN1lrXH1i6dqufpc0jq8TMf/N+q1q/c1uMupsKCY1/xVYpc+ok71b7J7c49zQ
|
|
45
|
+
nOeuUW8CgYA9Infooy65FTgbzca0c9kbCUBmcAPQ2ItH3JcPKWPQTDuV62HcT00o
|
|
46
|
+
fZdIV47Nez1W5Clk191RMy8TXuqI54kocciUWpThc6j44hz49oUueb8U4bLcEHzA
|
|
47
|
+
WxtWBWHwxfSmqgTXilEA3ALJp0kNolLnEttnhENwJpZHlqtes0ZA4w==
|
|
48
|
+
-----END RSA PRIVATE KEY-----"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class Server(paramiko.ServerInterface):
|
|
52
|
+
"""http://docs.paramiko.org/en/2.4/api/server.html."""
|
|
53
|
+
|
|
54
|
+
def __init__(self, commands, *args, **kwargs) -> None:
|
|
55
|
+
super().__init__(*args, **kwargs)
|
|
56
|
+
self.commands = commands
|
|
57
|
+
|
|
58
|
+
def check_channel_exec_request(self, channel, command):
|
|
59
|
+
self.commands.append(command)
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
def check_auth_password(self, username, password):
|
|
63
|
+
if username == USER and password == PASSWORD:
|
|
64
|
+
return paramiko.AUTH_SUCCESSFUL
|
|
65
|
+
return paramiko.AUTH_FAILED
|
|
66
|
+
|
|
67
|
+
def check_auth_publickey(self, username, key):
|
|
68
|
+
pubkey = paramiko.RSAKey.from_private_key(StringIO(CLIENT_KEY))
|
|
69
|
+
if username == USER and key == pubkey:
|
|
70
|
+
return paramiko.AUTH_SUCCESSFUL
|
|
71
|
+
return paramiko.AUTH_FAILED
|
|
72
|
+
|
|
73
|
+
def check_channel_request(self, kind, chanid):
|
|
74
|
+
if kind == "session":
|
|
75
|
+
return paramiko.OPEN_SUCCEEDED
|
|
76
|
+
return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED
|
|
77
|
+
|
|
78
|
+
def get_allowed_auths(self, username):
|
|
79
|
+
return "password,publickey"
|
|
80
|
+
|
|
81
|
+
|
|
26
82
|
@pytest.fixture
|
|
27
83
|
def ssh_conn(request: pytest.FixtureRequest) -> dict[str, Any]:
|
|
28
84
|
server = Server([])
|
|
@@ -77,6 +133,18 @@ def test_run_command_password(server: Server, ssh_port: int):
|
|
|
77
133
|
assert b"test_run_command_password" in server.commands
|
|
78
134
|
|
|
79
135
|
|
|
136
|
+
def test_run_command_no_password(server: Server, ssh_port: int):
|
|
137
|
+
vendor = AsyncSSHVendor()
|
|
138
|
+
with pytest.raises(AuthError):
|
|
139
|
+
vendor.run_command(
|
|
140
|
+
"127.0.0.1",
|
|
141
|
+
"test_run_command_password",
|
|
142
|
+
username=USER,
|
|
143
|
+
port=ssh_port,
|
|
144
|
+
password=None,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
80
148
|
def test_run_command_with_privkey(server: Server, ssh_port: int):
|
|
81
149
|
key = asyncssh.import_private_key(CLIENT_KEY)
|
|
82
150
|
|
|
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
|
|
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
|