sshscript 3.1.5__tar.gz → 4.0.2__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.
- sshscript-4.0.2/.github/ISSUE_TEMPLATE/bug_report.yml +109 -0
- sshscript-4.0.2/.github/ISSUE_TEMPLATE/config.yml +11 -0
- sshscript-4.0.2/.github/ISSUE_TEMPLATE/feature_request.yml +57 -0
- sshscript-4.0.2/.github/pull_request_template.md +32 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/.github/workflows/ci.yml +66 -7
- {sshscript-3.1.5 → sshscript-4.0.2}/.github/workflows/release.yml +30 -5
- sshscript-4.0.2/.gitignore +121 -0
- sshscript-4.0.2/API_GUIDE.md +631 -0
- sshscript-4.0.2/CHANGELOG.md +276 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/CONTRIBUTING.md +2 -1
- sshscript-4.0.2/EXCEPTIONS.md +145 -0
- sshscript-4.0.2/MANIFEST.in +56 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/PKG-INFO +214 -36
- {sshscript-3.1.5 → sshscript-4.0.2}/README.md +213 -35
- sshscript-4.0.2/RELEASING.md +63 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/SECURITY.md +12 -5
- sshscript-4.0.2/VERSIONING.md +109 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/pyproject.toml +5 -1
- sshscript-4.0.2/src/_sshscript_cli.py +19 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/__init__.py +13 -0
- sshscript-4.0.2/src/sshscript/__init__.pyi +15 -0
- sshscript-4.0.2/src/sshscript/_runtime.py +14 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/_version.py +1 -1
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/channelgeneric.py +48 -16
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/channelssh.py +8 -7
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/channelsubprocess.py +6 -6
- sshscript-4.0.2/src/sshscript/channelutils.py +715 -0
- sshscript-4.0.2/src/sshscript/commandjob.py +475 -0
- sshscript-4.0.2/src/sshscript/commandjob.pyi +45 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/commandresult.py +5 -2
- sshscript-4.0.2/src/sshscript/commandresult.pyi +18 -0
- sshscript-4.0.2/src/sshscript/consolejob.py +309 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/dollar.py +64 -33
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/dollarchanger.py +14 -2
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/patching.py +3 -1
- sshscript-4.0.2/src/sshscript/py.typed +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/session.py +307 -62
- sshscript-4.0.2/src/sshscript/session.pyi +73 -0
- sshscript-4.0.2/src/sshscript/sessionsettings.py +93 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/sessionwrapper.py +141 -11
- sshscript-4.0.2/src/sshscript/sessionwrapper.pyi +24 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/sshscript.py +21 -12
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/tokenparser.py +56 -1
- sshscript-4.0.2/src/sshscript/unittest/README.console-authentication.md +120 -0
- sshscript-4.0.2/src/sshscript/unittest/README.console-results.md +49 -0
- sshscript-4.0.2/src/sshscript/unittest/README.dollar-syntax-tests.md +57 -0
- sshscript-4.0.2/src/sshscript/unittest/README.module-tests.md +114 -0
- sshscript-3.1.5/src/sshscript/unittest/language.spy → sshscript-4.0.2/src/sshscript/unittest/language_fixture.spy +9 -112
- sshscript-4.0.2/src/sshscript/unittest/test_command_job.py +670 -0
- sshscript-4.0.2/src/sshscript/unittest/test_console_authentication.py +319 -0
- sshscript-4.0.2/src/sshscript/unittest/test_console_job.py +257 -0
- sshscript-4.0.2/src/sshscript/unittest/test_console_results.py +88 -0
- sshscript-4.0.2/src/sshscript/unittest/test_dollar_command_escapes.py +38 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_file_transfer.py +11 -3
- sshscript-4.0.2/src/sshscript/unittest/test_native_auth_runner.py +93 -0
- sshscript-4.0.2/src/sshscript/unittest/test_native_console_authentication.py +248 -0
- sshscript-4.0.2/src/sshscript/unittest/test_openssh_integration.py +497 -0
- sshscript-4.0.2/src/sshscript/unittest/test_public_types.py +29 -0
- sshscript-4.0.2/src/sshscript/unittest/test_python_version.py +113 -0
- sshscript-4.0.2/src/sshscript/unittest/test_recommended_examples.py +89 -0
- sshscript-4.0.2/src/sshscript/unittest/test_release_inputs.py +92 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_session_close_reporting.py +115 -0
- sshscript-4.0.2/src/sshscript/unittest/test_session_settings.py +154 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_ssh_config.py +36 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_ssh_security.py +18 -5
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_sshscript_dollar_syntax.py +11 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_sshscript_module.py +20 -3
- sshscript-4.0.2/src/sshscript/unittest/test_stdin_contract.py +142 -0
- sshscript-4.0.2/src/sshscript/unittest/test_version_policy.py +48 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript.egg-info/PKG-INFO +214 -36
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript.egg-info/SOURCES.txt +42 -2
- sshscript-4.0.2/src/sshscript.egg-info/entry_points.txt +2 -0
- sshscript-4.0.2/src/sshscript.egg-info/top_level.txt +2 -0
- sshscript-4.0.2/tools/check_baseline_examples.py +38 -0
- sshscript-4.0.2/tools/check_public_types.py +75 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/tools/check_release.py +16 -1
- sshscript-4.0.2/tools/prepare_release.py +149 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/tools/publish_release.py +4 -0
- sshscript-4.0.2/tools/run_checks.py +36 -0
- sshscript-4.0.2/tools/run_native_auth_ci.py +79 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/tools/setup_openssh_ci.sh +7 -1
- sshscript-4.0.2/tools/sync_api_guide.py +38 -0
- sshscript-4.0.2/tools/version_policy.py +25 -0
- sshscript-3.1.5/CHANGELOG.md +0 -101
- sshscript-3.1.5/EXCEPTIONS.md +0 -54
- sshscript-3.1.5/MANIFEST.in +0 -7
- sshscript-3.1.5/RELEASING.md +0 -29
- sshscript-3.1.5/src/sshscript/channelutils.py +0 -444
- sshscript-3.1.5/src/sshscript/unittest/language_fixture.spy +0 -10
- sshscript-3.1.5/src/sshscript/unittest/test_openssh_integration.py +0 -311
- sshscript-3.1.5/src/sshscript.egg-info/entry_points.txt +0 -2
- sshscript-3.1.5/src/sshscript.egg-info/top_level.txt +0 -1
- sshscript-3.1.5/tools/prepare_release.py +0 -59
- sshscript-3.1.5/tools/run_checks.py +0 -19
- {sshscript-3.1.5 → sshscript-4.0.2}/.github/dependabot.yml +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/.github/workflows/codeql.yml +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/CODE_OF_CONDUCT.md +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/LICENSE.txt +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/SUPPORT.md +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/setup.cfg +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/dollarparser.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/errorutils.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/spyimporter.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/sshconfig.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/stdio.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/check_package_asserts.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/dollar_syntax.spy +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/dollar_syntax_fixture.spy +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_channelgeneric_expect.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_check_file.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_command_api.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_logger_api.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_logger_integration.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_production_contract.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_session_proxy_cleanup.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_spy_source_mapping.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_spy_thread_session.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_stdio_dynamic_string.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_syntax_error.spy +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript/unittest/test_update_check.py +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript.egg-info/dependency_links.txt +0 -0
- {sshscript-3.1.5 → sshscript-4.0.2}/src/sshscript.egg-info/requires.txt +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a reproducible problem in a supported SSHScript release
|
|
3
|
+
title: "[Bug] "
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thank you for helping improve SSHScript. Do not include credentials,
|
|
9
|
+
private host details, or production output. Report suspected
|
|
10
|
+
vulnerabilities through GitHub private vulnerability reporting instead.
|
|
11
|
+
|
|
12
|
+
- type: checkboxes
|
|
13
|
+
id: preflight
|
|
14
|
+
attributes:
|
|
15
|
+
label: Preflight
|
|
16
|
+
options:
|
|
17
|
+
- label: I reproduced this with the latest SSHScript 3.1.x release.
|
|
18
|
+
required: true
|
|
19
|
+
- label: I searched existing issues and discussions for this problem.
|
|
20
|
+
required: true
|
|
21
|
+
- label: This report contains no password, key, token, or private infrastructure detail.
|
|
22
|
+
required: true
|
|
23
|
+
- label: This is not a security vulnerability.
|
|
24
|
+
required: true
|
|
25
|
+
|
|
26
|
+
- type: input
|
|
27
|
+
id: sshscript-version
|
|
28
|
+
attributes:
|
|
29
|
+
label: SSHScript version
|
|
30
|
+
description: Paste the output of `sshscript --version`.
|
|
31
|
+
placeholder: "3.1.4"
|
|
32
|
+
validations:
|
|
33
|
+
required: true
|
|
34
|
+
|
|
35
|
+
- type: input
|
|
36
|
+
id: python-paramiko
|
|
37
|
+
attributes:
|
|
38
|
+
label: Python and Paramiko versions
|
|
39
|
+
placeholder: "Python 3.12.7; Paramiko 4.0.0"
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
|
|
43
|
+
- type: input
|
|
44
|
+
id: environment
|
|
45
|
+
attributes:
|
|
46
|
+
label: Operating system and SSH server
|
|
47
|
+
description: Include the SSH server implementation/version when relevant.
|
|
48
|
+
placeholder: "Ubuntu 24.04; OpenSSH_9.6p1"
|
|
49
|
+
validations:
|
|
50
|
+
required: true
|
|
51
|
+
|
|
52
|
+
- type: dropdown
|
|
53
|
+
id: interface
|
|
54
|
+
attributes:
|
|
55
|
+
label: Interface
|
|
56
|
+
options:
|
|
57
|
+
- Python module API
|
|
58
|
+
- Dollar syntax (.spy)
|
|
59
|
+
- Both
|
|
60
|
+
- Command-line interface
|
|
61
|
+
validations:
|
|
62
|
+
required: true
|
|
63
|
+
|
|
64
|
+
- type: dropdown
|
|
65
|
+
id: operation
|
|
66
|
+
attributes:
|
|
67
|
+
label: Operation
|
|
68
|
+
options:
|
|
69
|
+
- Local command
|
|
70
|
+
- Direct SSH command
|
|
71
|
+
- Nested SSH command
|
|
72
|
+
- Persistent or interactive console
|
|
73
|
+
- sudo or su
|
|
74
|
+
- Upload or download
|
|
75
|
+
- Import or source transformation
|
|
76
|
+
- Installation or packaging
|
|
77
|
+
- Other
|
|
78
|
+
validations:
|
|
79
|
+
required: true
|
|
80
|
+
|
|
81
|
+
- type: textarea
|
|
82
|
+
id: reproduction
|
|
83
|
+
attributes:
|
|
84
|
+
label: Minimal reproduction
|
|
85
|
+
description: Use a disposable host or credential-free example and include exact steps.
|
|
86
|
+
render: python
|
|
87
|
+
validations:
|
|
88
|
+
required: true
|
|
89
|
+
|
|
90
|
+
- type: textarea
|
|
91
|
+
id: expected
|
|
92
|
+
attributes:
|
|
93
|
+
label: Expected behavior
|
|
94
|
+
validations:
|
|
95
|
+
required: true
|
|
96
|
+
|
|
97
|
+
- type: textarea
|
|
98
|
+
id: actual
|
|
99
|
+
attributes:
|
|
100
|
+
label: Actual behavior
|
|
101
|
+
description: Include the exit status and a redacted traceback or error message.
|
|
102
|
+
validations:
|
|
103
|
+
required: true
|
|
104
|
+
|
|
105
|
+
- type: textarea
|
|
106
|
+
id: additional-context
|
|
107
|
+
attributes:
|
|
108
|
+
label: Additional context
|
|
109
|
+
description: Add sanitized details that are necessary to understand the issue.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Documentation
|
|
4
|
+
url: https://iapyeh.github.io/sshscript/v3a/
|
|
5
|
+
about: Read installation, tutorials, how-to guides, and reference material.
|
|
6
|
+
- name: Usage questions and design discussion
|
|
7
|
+
url: https://github.com/iapyeh/sshscript/discussions
|
|
8
|
+
about: Ask for help or discuss an idea before opening an issue.
|
|
9
|
+
- name: Report a security vulnerability privately
|
|
10
|
+
url: https://github.com/iapyeh/sshscript/security/advisories/new
|
|
11
|
+
about: Do not disclose a suspected vulnerability in a public issue.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Propose a focused, testable improvement to SSHScript
|
|
3
|
+
title: "[Feature] "
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Explain the user problem before the proposed API. For usage questions
|
|
9
|
+
and early design discussion, use GitHub Discussions.
|
|
10
|
+
|
|
11
|
+
- type: checkboxes
|
|
12
|
+
id: preflight
|
|
13
|
+
attributes:
|
|
14
|
+
label: Preflight
|
|
15
|
+
options:
|
|
16
|
+
- label: I searched existing issues and discussions for this request.
|
|
17
|
+
required: true
|
|
18
|
+
- label: This request contains no credentials or private infrastructure detail.
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: problem
|
|
23
|
+
attributes:
|
|
24
|
+
label: Problem or use case
|
|
25
|
+
description: What workflow is difficult today, and who is affected?
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: proposal
|
|
31
|
+
attributes:
|
|
32
|
+
label: Proposed behavior
|
|
33
|
+
description: Show a small API or `.spy` example when that makes the behavior clearer.
|
|
34
|
+
validations:
|
|
35
|
+
required: true
|
|
36
|
+
|
|
37
|
+
- type: textarea
|
|
38
|
+
id: alternatives
|
|
39
|
+
attributes:
|
|
40
|
+
label: Alternatives considered
|
|
41
|
+
description: Describe existing SSHScript or Python approaches you tried.
|
|
42
|
+
validations:
|
|
43
|
+
required: true
|
|
44
|
+
|
|
45
|
+
- type: textarea
|
|
46
|
+
id: compatibility
|
|
47
|
+
attributes:
|
|
48
|
+
label: Compatibility and security impact
|
|
49
|
+
description: Note effects on the module API, dollar syntax, platforms, logging, credentials, or host-key handling.
|
|
50
|
+
|
|
51
|
+
- type: textarea
|
|
52
|
+
id: acceptance
|
|
53
|
+
attributes:
|
|
54
|
+
label: Acceptance criteria
|
|
55
|
+
description: List observable behavior that tests and documentation could verify.
|
|
56
|
+
validations:
|
|
57
|
+
required: true
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What changes, and what user or maintainer problem does it solve? -->
|
|
4
|
+
|
|
5
|
+
## Behavior and compatibility
|
|
6
|
+
|
|
7
|
+
<!-- Describe public API, dollar syntax, CLI, exception, security, or migration impact. -->
|
|
8
|
+
|
|
9
|
+
## Validation
|
|
10
|
+
|
|
11
|
+
<!-- List exact commands and results. At minimum, run the credential-free gate. -->
|
|
12
|
+
|
|
13
|
+
- [ ] `python3 tools/run_checks.py`
|
|
14
|
+
- [ ] `python3 tools/check_release.py --output /tmp/sshscript-candidate-UNIQUE`
|
|
15
|
+
- [ ] A regression test covers the change, or the reason it cannot is explained.
|
|
16
|
+
- [ ] Relevant behavior was checked with and without `python -O`.
|
|
17
|
+
|
|
18
|
+
## Documentation and release notes
|
|
19
|
+
|
|
20
|
+
- [ ] README or v3 documentation is updated for user-visible behavior.
|
|
21
|
+
- [ ] `CHANGELOG.md` is updated, or this change has no user-visible effect.
|
|
22
|
+
- [ ] Module API and dollar-syntax descriptions remain aligned.
|
|
23
|
+
|
|
24
|
+
## Security and hygiene
|
|
25
|
+
|
|
26
|
+
- [ ] No credential, private key, token, internal hostname, private path, or production output is included.
|
|
27
|
+
- [ ] Host-key, command-injection, privilege, timeout, logging, and cleanup effects were considered.
|
|
28
|
+
- [ ] New dependencies or permissions are justified in the summary.
|
|
29
|
+
|
|
30
|
+
## Related issue
|
|
31
|
+
|
|
32
|
+
<!-- Use "Closes #123" when appropriate. -->
|
|
@@ -19,9 +19,11 @@ jobs:
|
|
|
19
19
|
with:
|
|
20
20
|
python-version: ${{ matrix.python-version }}
|
|
21
21
|
- name: Install test and build dependencies
|
|
22
|
-
run: python -m pip install 'paramiko>=2.11,<5' 'packaging>=21' build twine
|
|
22
|
+
run: python -m pip install 'paramiko>=2.11,<5' 'packaging>=21' build twine 'mypy==2.3.1'
|
|
23
23
|
- name: Test source
|
|
24
24
|
run: python tools/run_checks.py
|
|
25
|
+
- name: Check public type contracts
|
|
26
|
+
run: python tools/check_public_types.py
|
|
25
27
|
- name: Build and verify installed release
|
|
26
28
|
run: python tools/check_release.py --output '${{ runner.temp }}/verified-artifacts'
|
|
27
29
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
@@ -29,14 +31,40 @@ jobs:
|
|
|
29
31
|
name: sshscript-${{ matrix.os }}-${{ matrix.python-version }}
|
|
30
32
|
path: ${{ runner.temp }}/verified-artifacts/
|
|
31
33
|
|
|
34
|
+
baseline-examples:
|
|
35
|
+
name: Published 3.1.5 examples
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
timeout-minutes: 5
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
|
40
|
+
with:
|
|
41
|
+
persist-credentials: false
|
|
42
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97
|
|
43
|
+
with:
|
|
44
|
+
python-version: '3.11'
|
|
45
|
+
- run: python -m pip install 'sshscript==3.1.5'
|
|
46
|
+
- run: python -I tools/check_baseline_examples.py
|
|
47
|
+
|
|
32
48
|
openssh-integration:
|
|
33
|
-
name: OpenSSH integration (Python ${{ matrix.python-version }})
|
|
49
|
+
name: OpenSSH integration (Python ${{ matrix.python-version }}, ${{ matrix.dependency-label }})
|
|
34
50
|
runs-on: ubuntu-latest
|
|
35
51
|
timeout-minutes: 25
|
|
36
52
|
strategy:
|
|
37
53
|
fail-fast: false
|
|
38
54
|
matrix:
|
|
39
|
-
|
|
55
|
+
include:
|
|
56
|
+
- python-version: '3.11'
|
|
57
|
+
paramiko: 'paramiko==2.11.0'
|
|
58
|
+
dependency-label: minimum
|
|
59
|
+
- python-version: '3.14'
|
|
60
|
+
paramiko: 'paramiko==2.11.0'
|
|
61
|
+
dependency-label: minimum-new-python
|
|
62
|
+
- python-version: '3.11'
|
|
63
|
+
paramiko: 'paramiko>=3,<4'
|
|
64
|
+
dependency-label: 3.x
|
|
65
|
+
- python-version: '3.14'
|
|
66
|
+
paramiko: 'paramiko>=4,<5'
|
|
67
|
+
dependency-label: 4.x
|
|
40
68
|
steps:
|
|
41
69
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
42
70
|
with:
|
|
@@ -45,24 +73,37 @@ jobs:
|
|
|
45
73
|
with:
|
|
46
74
|
python-version: ${{ matrix.python-version }}
|
|
47
75
|
- name: Install test and build dependencies
|
|
48
|
-
run: python -m pip install
|
|
76
|
+
run: python -m pip install "${{ matrix.paramiko }}" 'packaging>=21' build twine
|
|
77
|
+
- name: Test source with selected Paramiko
|
|
78
|
+
run: python tools/run_checks.py
|
|
49
79
|
- name: Build and verify wheel
|
|
50
80
|
run: python tools/check_release.py --output "$RUNNER_TEMP/verified-artifacts"
|
|
51
81
|
- name: Install verified wheel
|
|
52
|
-
run: python -m pip install --force-reinstall "$RUNNER_TEMP"/verified-artifacts/*.whl
|
|
82
|
+
run: python -m pip install --force-reinstall "$RUNNER_TEMP"/verified-artifacts/*.whl "${{ matrix.paramiko }}"
|
|
53
83
|
- name: Provision loopback OpenSSH server
|
|
54
84
|
run: bash tools/setup_openssh_ci.sh "$GITHUB_ENV"
|
|
55
85
|
- name: Test installed wheel against OpenSSH
|
|
56
86
|
run: |
|
|
57
87
|
mkdir -p "$RUNNER_TEMP/openssh-tests"
|
|
58
|
-
|
|
88
|
+
TEST_SOURCE=unittest/test_openssh_integration.py
|
|
89
|
+
if [[ -d src/sshscript ]]; then TEST_SOURCE=src/sshscript/unittest/test_openssh_integration.py; fi
|
|
90
|
+
cp "$TEST_SOURCE" "$RUNNER_TEMP/openssh-tests/"
|
|
59
91
|
cd "$RUNNER_TEMP/openssh-tests"
|
|
60
92
|
python -I test_openssh_integration.py -v
|
|
93
|
+
- name: Verify native su/sudo contracts on local and SSH backends
|
|
94
|
+
run: python tools/run_native_auth_ci.py --wheel "$RUNNER_TEMP"/verified-artifacts/*.whl --report "$RUNNER_TEMP/native-auth-report.json"
|
|
95
|
+
- name: Save native authentication evidence
|
|
96
|
+
if: always()
|
|
97
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
|
98
|
+
with:
|
|
99
|
+
name: native-auth-python-${{ matrix.python-version }}-${{ matrix.dependency-label }}
|
|
100
|
+
if-no-files-found: warn
|
|
101
|
+
path: ${{ runner.temp }}/native-auth-report.json
|
|
61
102
|
- name: Upload OpenSSH server log
|
|
62
103
|
if: ${{ failure() && env.SSHSCRIPT_OPENSSH_LOG != '' }}
|
|
63
104
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
64
105
|
with:
|
|
65
|
-
name: openssh-log-python-${{ matrix.python-version }}
|
|
106
|
+
name: openssh-log-python-${{ matrix.python-version }}-${{ matrix.dependency-label }}
|
|
66
107
|
if-no-files-found: warn
|
|
67
108
|
path: ${{ env.SSHSCRIPT_OPENSSH_LOG }}
|
|
68
109
|
- name: Remove disposable OpenSSH state
|
|
@@ -83,3 +124,21 @@ jobs:
|
|
|
83
124
|
if [[ -n "${SSHSCRIPT_OPENSSH_ROOT:-}" && "$SSHSCRIPT_OPENSSH_ROOT" == "$RUNNER_TEMP"/sshscript-openssh.* ]]; then
|
|
84
125
|
sudo rm -rf -- "$SSHSCRIPT_OPENSSH_ROOT"
|
|
85
126
|
fi
|
|
127
|
+
|
|
128
|
+
# Preserve the required-check names configured on the protected release branch.
|
|
129
|
+
# Both gates require every supported Python/Paramiko integration leg to pass.
|
|
130
|
+
openssh-required-311:
|
|
131
|
+
name: OpenSSH integration (Python 3.11)
|
|
132
|
+
needs: openssh-integration
|
|
133
|
+
if: ${{ always() }}
|
|
134
|
+
runs-on: ubuntu-latest
|
|
135
|
+
steps:
|
|
136
|
+
- run: test "${{ needs.openssh-integration.result }}" = success
|
|
137
|
+
|
|
138
|
+
openssh-required-314:
|
|
139
|
+
name: OpenSSH integration (Python 3.14)
|
|
140
|
+
needs: openssh-integration
|
|
141
|
+
if: ${{ always() }}
|
|
142
|
+
runs-on: ubuntu-latest
|
|
143
|
+
steps:
|
|
144
|
+
- run: test "${{ needs.openssh-integration.result }}" = success
|
|
@@ -39,6 +39,8 @@ jobs:
|
|
|
39
39
|
run: |
|
|
40
40
|
PACKAGE_VERSION=$(python -c "import runpy; print(runpy.run_path('src/sshscript/_version.py')['__version__'])")
|
|
41
41
|
test "$RELEASE_TAG" = "v$PACKAGE_VERSION"
|
|
42
|
+
- name: Reject development versions for production publication
|
|
43
|
+
run: python tools/version_policy.py --production
|
|
42
44
|
- name: Stabilize build timestamps
|
|
43
45
|
run: echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)" >> "$GITHUB_ENV"
|
|
44
46
|
- name: Run release gates and build verified artifacts
|
|
@@ -58,14 +60,26 @@ jobs:
|
|
|
58
60
|
path: ${{ runner.temp }}/sshscript-release/
|
|
59
61
|
|
|
60
62
|
openssh-integration:
|
|
61
|
-
name: Release OpenSSH integration (Python ${{ matrix.python-version }})
|
|
63
|
+
name: Release OpenSSH integration (Python ${{ matrix.python-version }}, ${{ matrix.dependency-label }})
|
|
62
64
|
needs: build
|
|
63
65
|
runs-on: ubuntu-latest
|
|
64
66
|
timeout-minutes: 15
|
|
65
67
|
strategy:
|
|
66
68
|
fail-fast: false
|
|
67
69
|
matrix:
|
|
68
|
-
|
|
70
|
+
include:
|
|
71
|
+
- python-version: '3.11'
|
|
72
|
+
paramiko: 'paramiko==2.11.0'
|
|
73
|
+
dependency-label: minimum
|
|
74
|
+
- python-version: '3.14'
|
|
75
|
+
paramiko: 'paramiko==2.11.0'
|
|
76
|
+
dependency-label: minimum-new-python
|
|
77
|
+
- python-version: '3.11'
|
|
78
|
+
paramiko: 'paramiko>=3,<4'
|
|
79
|
+
dependency-label: 3.x
|
|
80
|
+
- python-version: '3.14'
|
|
81
|
+
paramiko: 'paramiko>=4,<5'
|
|
82
|
+
dependency-label: 4.x
|
|
69
83
|
steps:
|
|
70
84
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
71
85
|
with:
|
|
@@ -78,20 +92,31 @@ jobs:
|
|
|
78
92
|
name: python-package-distributions
|
|
79
93
|
path: dist
|
|
80
94
|
- name: Install verified wheel
|
|
81
|
-
run: python -m pip install dist/*.whl
|
|
95
|
+
run: python -m pip install dist/*.whl "${{ matrix.paramiko }}"
|
|
82
96
|
- name: Provision loopback OpenSSH server
|
|
83
97
|
run: bash tools/setup_openssh_ci.sh "$GITHUB_ENV"
|
|
84
98
|
- name: Test installed wheel against OpenSSH
|
|
85
99
|
run: |
|
|
86
100
|
mkdir -p "$RUNNER_TEMP/openssh-tests"
|
|
87
|
-
|
|
101
|
+
TEST_SOURCE=unittest/test_openssh_integration.py
|
|
102
|
+
if [[ -d src/sshscript ]]; then TEST_SOURCE=src/sshscript/unittest/test_openssh_integration.py; fi
|
|
103
|
+
cp "$TEST_SOURCE" "$RUNNER_TEMP/openssh-tests/"
|
|
88
104
|
cd "$RUNNER_TEMP/openssh-tests"
|
|
89
105
|
python -I test_openssh_integration.py -v
|
|
106
|
+
- name: Verify native su/sudo contracts on local and SSH backends
|
|
107
|
+
run: python tools/run_native_auth_ci.py --wheel dist/*.whl --report "$RUNNER_TEMP/native-auth-report.json"
|
|
108
|
+
- name: Save native authentication evidence
|
|
109
|
+
if: always()
|
|
110
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
|
|
111
|
+
with:
|
|
112
|
+
name: release-native-auth-python-${{ matrix.python-version }}-${{ matrix.dependency-label }}
|
|
113
|
+
if-no-files-found: warn
|
|
114
|
+
path: ${{ runner.temp }}/native-auth-report.json
|
|
90
115
|
- name: Upload OpenSSH server log
|
|
91
116
|
if: ${{ failure() && env.SSHSCRIPT_OPENSSH_LOG != '' }}
|
|
92
117
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
93
118
|
with:
|
|
94
|
-
name: release-openssh-log-python-${{ matrix.python-version }}
|
|
119
|
+
name: release-openssh-log-python-${{ matrix.python-version }}-${{ matrix.dependency-label }}
|
|
95
120
|
if-no-files-found: warn
|
|
96
121
|
path: ${{ env.SSHSCRIPT_OPENSSH_LOG }}
|
|
97
122
|
- name: Remove disposable OpenSSH state
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
|
|
3
|
+
# Python bytecode and caches
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
*$py.class
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.mypy_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
|
|
11
|
+
# Environments
|
|
12
|
+
.venv/
|
|
13
|
+
venv/
|
|
14
|
+
env/
|
|
15
|
+
|
|
16
|
+
# Packaging output
|
|
17
|
+
build/
|
|
18
|
+
dist/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
*.egg
|
|
21
|
+
|
|
22
|
+
# Coverage and local tooling
|
|
23
|
+
.coverage
|
|
24
|
+
.coverage.*
|
|
25
|
+
htmlcov/
|
|
26
|
+
.tox/
|
|
27
|
+
.nox/
|
|
28
|
+
|
|
29
|
+
# Editors
|
|
30
|
+
.idea/
|
|
31
|
+
.vscode/
|
|
32
|
+
*.swp
|
|
33
|
+
*~
|
|
34
|
+
|
|
35
|
+
# Local configuration and credentials
|
|
36
|
+
/unittest-v3/hostsall.py
|
|
37
|
+
.env
|
|
38
|
+
.env.*
|
|
39
|
+
*.pem
|
|
40
|
+
*.key
|
|
41
|
+
*secret*
|
|
42
|
+
*credential*
|
|
43
|
+
*password*
|
|
44
|
+
|
|
45
|
+
# Private host settings and environment-specific tests (kept locally)
|
|
46
|
+
/unittest-v3/A00commonc.py
|
|
47
|
+
/unittest-v3/B00.spy
|
|
48
|
+
/unittest-v3/B03nametest.py
|
|
49
|
+
/unittest-v3/apnic_test.spy
|
|
50
|
+
/unittest-v3/checkiterate.spy
|
|
51
|
+
/unittest-v3/checkproc.spy
|
|
52
|
+
/unittest-v3/checkpty.spy
|
|
53
|
+
/unittest-v3/checktest.spy
|
|
54
|
+
/unittest-v3/checktwodollars.spy
|
|
55
|
+
/unittest-v3/checkupdownload.spy
|
|
56
|
+
/unittest-v3/hosts4iapdev.py
|
|
57
|
+
/unittest-v3/hosts4macpro.py
|
|
58
|
+
/unittest-v3/hosts4rms4.py
|
|
59
|
+
/unittest-v3/hosts4test.py
|
|
60
|
+
/unittest-v3/log/A01onedollar.spy-1791280028.log
|
|
61
|
+
/unittest-v3/log/A01onedollar.spy-1791280318.log
|
|
62
|
+
/unittest-v3/log/A02twodollars.spy-1791280344.log
|
|
63
|
+
/unittest-v3/log/B04withsession.spy-1791280368.log
|
|
64
|
+
/unittest-v3/log/B04withsession.spy-1791288350.log
|
|
65
|
+
/unittest-v3/nonenterpython.spy
|
|
66
|
+
/unittest-v3/test.py
|
|
67
|
+
/unittest-v3/test.spy
|
|
68
|
+
/unittest-v3/usecase/iapdev.spy
|
|
69
|
+
/unittest-v3/usecase/settings.py
|
|
70
|
+
/unittest/README.language-tests.md
|
|
71
|
+
/unittest/a.spy
|
|
72
|
+
/unittest/a2.spy
|
|
73
|
+
/unittest/advance.spy
|
|
74
|
+
/unittest/basic.spy
|
|
75
|
+
/unittest/basic_dollar.spy
|
|
76
|
+
/unittest/language.spy
|
|
77
|
+
|
|
78
|
+
# Legacy tests are private; public tests require explicit approval.
|
|
79
|
+
/unittest-v3/
|
|
80
|
+
/unittest/*
|
|
81
|
+
!/unittest/README.console-authentication.md
|
|
82
|
+
!/unittest/README.console-results.md
|
|
83
|
+
!/unittest/README.dollar-syntax-tests.md
|
|
84
|
+
!/unittest/README.module-tests.md
|
|
85
|
+
!/unittest/check_package_asserts.py
|
|
86
|
+
!/unittest/dollar_syntax.spy
|
|
87
|
+
!/unittest/dollar_syntax_fixture.spy
|
|
88
|
+
!/unittest/language_fixture.spy
|
|
89
|
+
!/unittest/test_channelgeneric_expect.py
|
|
90
|
+
!/unittest/test_check_file.py
|
|
91
|
+
!/unittest/test_command_api.py
|
|
92
|
+
!/unittest/test_command_job.py
|
|
93
|
+
!/unittest/test_console_authentication.py
|
|
94
|
+
!/unittest/test_native_console_authentication.py
|
|
95
|
+
!/unittest/test_native_auth_runner.py
|
|
96
|
+
!/unittest/test_console_results.py
|
|
97
|
+
!/unittest/test_console_job.py
|
|
98
|
+
!/unittest/test_dollar_command_escapes.py
|
|
99
|
+
!/unittest/test_file_transfer.py
|
|
100
|
+
!/unittest/test_logger_api.py
|
|
101
|
+
!/unittest/test_logger_integration.py
|
|
102
|
+
!/unittest/test_openssh_integration.py
|
|
103
|
+
!/unittest/test_production_contract.py
|
|
104
|
+
!/unittest/test_public_types.py
|
|
105
|
+
!/unittest/test_python_version.py
|
|
106
|
+
!/unittest/test_version_policy.py
|
|
107
|
+
!/unittest/test_release_inputs.py
|
|
108
|
+
!/unittest/test_recommended_examples.py
|
|
109
|
+
!/unittest/test_session_close_reporting.py
|
|
110
|
+
!/unittest/test_session_proxy_cleanup.py
|
|
111
|
+
!/unittest/test_session_settings.py
|
|
112
|
+
!/unittest/test_spy_source_mapping.py
|
|
113
|
+
!/unittest/test_spy_thread_session.py
|
|
114
|
+
!/unittest/test_ssh_config.py
|
|
115
|
+
!/unittest/test_ssh_security.py
|
|
116
|
+
!/unittest/test_sshscript_dollar_syntax.py
|
|
117
|
+
!/unittest/test_sshscript_module.py
|
|
118
|
+
!/unittest/test_stdio_dynamic_string.py
|
|
119
|
+
!/unittest/test_stdin_contract.py
|
|
120
|
+
!/unittest/test_syntax_error.spy
|
|
121
|
+
!/unittest/test_update_check.py
|