fakesshagent 0.1__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 (43) hide show
  1. fakesshagent-0.1/.gitignore +7 -0
  2. fakesshagent-0.1/.gitmodules +4 -0
  3. fakesshagent-0.1/.vscode/settings.json +7 -0
  4. fakesshagent-0.1/CHANGELOG.md +1 -0
  5. fakesshagent-0.1/LICENSE.txt +13 -0
  6. fakesshagent-0.1/PKG-INFO +80 -0
  7. fakesshagent-0.1/README.md +35 -0
  8. fakesshagent-0.1/docs/Keep_a_changelog-E05735.svg +2 -0
  9. fakesshagent-0.1/docs/SemVer-3F4551.svg +2 -0
  10. fakesshagent-0.1/docs/changelog.md +53 -0
  11. fakesshagent-0.1/docs/explanation/faq-altered-versions.md +26 -0
  12. fakesshagent-0.1/docs/explanation/index.md +8 -0
  13. fakesshagent-0.1/docs/index.md +1 -0
  14. fakesshagent-0.1/docs/mkdocstrings_recommended_styles.css +35 -0
  15. fakesshagent-0.1/docs/pycompatibility.md +87 -0
  16. fakesshagent-0.1/docs/upgrade-notes.md +4 -0
  17. fakesshagent-0.1/docs/wishlist/index.md +45 -0
  18. fakesshagent-0.1/docs/wishlist/sans-io.md +32 -0
  19. fakesshagent-0.1/docs/wishlist/spec.md +92 -0
  20. fakesshagent-0.1/docs/wishlist_styling.css +94 -0
  21. fakesshagent-0.1/docs-overrides/main.html +12 -0
  22. fakesshagent-0.1/docs-overrides/partials/actions.html +28 -0
  23. fakesshagent-0.1/docs-overrides/partials/consent.html +0 -0
  24. fakesshagent-0.1/docs-overrides/partials/copyright.html +20 -0
  25. fakesshagent-0.1/docs-overrides/partials/header.html +0 -0
  26. fakesshagent-0.1/docs-overrides/partials/javascripts/announce.html +0 -0
  27. fakesshagent-0.1/docs-overrides/partials/javascripts/base.html +0 -0
  28. fakesshagent-0.1/docs-overrides/partials/javascripts/consent.html +0 -0
  29. fakesshagent-0.1/docs-overrides/partials/javascripts/content.html +0 -0
  30. fakesshagent-0.1/docs-overrides/partials/javascripts/outdated.html +0 -0
  31. fakesshagent-0.1/docs-overrides/partials/javascripts/palette.html +0 -0
  32. fakesshagent-0.1/docs-overrides/partials/search.html +0 -0
  33. fakesshagent-0.1/docs-overrides/redirect.html +15 -0
  34. fakesshagent-0.1/mkdocs.yml +148 -0
  35. fakesshagent-0.1/mkdocs_devsetup.yml +16 -0
  36. fakesshagent-0.1/mkdocs_offline.yml +14 -0
  37. fakesshagent-0.1/pyproject.toml +478 -0
  38. fakesshagent-0.1/src/fakesshagent/__init__.py +13 -0
  39. fakesshagent-0.1/src/fakesshagent/_types.py +87 -0
  40. fakesshagent-0.1/src/fakesshagent/data.py +837 -0
  41. fakesshagent-0.1/src/fakesshagent/machinery.py +468 -0
  42. fakesshagent-0.1/tests/__init__.py +3 -0
  43. fakesshagent-0.1/tests/test_000_testing_machinery.py +819 -0
@@ -0,0 +1,7 @@
1
+ html/
2
+ .mypy_cache/
3
+ .pytest_cache/
4
+ __pycache__/
5
+ *.swp
6
+ .coverage*
7
+ .hypothesis/
@@ -0,0 +1,4 @@
1
+ [submodule "docs/wishlist"]
2
+ path = docs/wishlist
3
+ url = ./
4
+ branch = wishlist
@@ -0,0 +1,7 @@
1
+ {
2
+ "python.testing.pytestArgs": [
3
+ "tests"
4
+ ],
5
+ "python.testing.unittestEnabled": false,
6
+ "python.testing.pytestEnabled": true
7
+ }
@@ -0,0 +1 @@
1
+ (See docs/ directory.)
@@ -0,0 +1,13 @@
1
+ zlib License
2
+
3
+ Copyright 2026 Marco Ricci <software@the13thletter.info>
4
+
5
+ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
6
+
7
+ Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
8
+
9
+ 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
10
+
11
+ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
12
+
13
+ 3. This notice may not be removed or altered from any source distribution.
@@ -0,0 +1,80 @@
1
+ Metadata-Version: 2.5
2
+ Name: fakesshagent
3
+ Version: 0.1
4
+ Summary: A non-hardened implementation of the SSH agent protocol, for use in testing.
5
+ Project-URL: Documentation, https://the13thletter.info/fakesshagent/
6
+ Project-URL: Issues, https://the13thletter.info/fakesshagent/latest/wishlist/
7
+ Project-URL: Source, https://git.schokokeks.org/fakesshagent.git
8
+ Author-email: Marco Ricci <software@the13thletter.info>
9
+ License-Expression: Zlib
10
+ License-File: LICENSE.txt
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
22
+ Classifier: Programming Language :: Python :: Implementation :: CPython
23
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
24
+ Classifier: Topic :: Software Development :: Testing
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.9
27
+ Requires-Dist: derivepassphrase-sshagentsocketprovider>=1.0
28
+ Requires-Dist: typing-extensions
29
+ Provides-Extra: dev
30
+ Requires-Dist: coverage-enable-subprocess>=1.0; extra == 'dev'
31
+ Requires-Dist: coverage[toml]>=7.4; extra == 'dev'
32
+ Requires-Dist: hatch>=1.10; extra == 'dev'
33
+ Requires-Dist: hypothesis!=6.130.13,!=6.131.*,!=6.132.*,!=6.133.*,!=6.134.*,!=6.135.0,!=6.135.1; (python_version < '3.10') and extra == 'dev'
34
+ Requires-Dist: hypothesis<6.156; (platform_python_implementation == 'PyPy' and python_version < '3.11') and extra == 'dev'
35
+ Requires-Dist: hypothesis>=6.131.0; extra == 'dev'
36
+ Requires-Dist: mypy>=1.0; extra == 'dev'
37
+ Requires-Dist: packaging; extra == 'dev'
38
+ Requires-Dist: pytest-randomly>=3.15; extra == 'dev'
39
+ Requires-Dist: pytest-xdist>=3.6.0; extra == 'dev'
40
+ Requires-Dist: pytest-xdist[psutil]>=3.6.0; (platform_python_implementation != 'PyPy') and extra == 'dev'
41
+ Requires-Dist: pytest<8.4; (python_version < '3.10') and extra == 'dev'
42
+ Requires-Dist: pytest>=8.2; extra == 'dev'
43
+ Requires-Dist: ruff>=0.16.0; extra == 'dev'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # fakesshagent
47
+
48
+ [![PyPI - Version](https://img.shields.io/pypi/v/fakesshagent.svg)](https://pypi.org/project/fakesshagent)
49
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/fakesshagent.svg)](https://pypi.org/project/fakesshagent)
50
+
51
+ A non-hardened implementation of the SSH agent protocol, for use in testing.
52
+
53
+ `fakesshagent` was originally written to test [`derivepassphrase`][DERIVEPASSPHRASE]'s SSH agent interactions.
54
+ As such, `fakesshagent` also registers as an abstract SSH agent socket provider for [`derivepassphrase`][DERIVEPASSPHRASE].
55
+ (The implementation is based on memory buffers, not external I/O with sockets.)
56
+
57
+ In this first release, `fakesshagent` provides exactly the operations needed for use with `derivepassphrase`:
58
+ listing available keys, and deterministically signing a fixed message (if possible with this key type), for a set of known test keys.
59
+ See the wishlist for planned features of subsequent releases.
60
+
61
+ [DERIVEPASSPHRASE]: https://the13thletter.info/derivepassphrase/
62
+
63
+ -----
64
+
65
+ ## Installation
66
+
67
+ `fakesshagent` is a pure Python package, and may be easily installed with any `pip`-compatible Python package manager such as `pip`, `pipx`, or `uv`.
68
+
69
+ ```console
70
+ pip install fakesshagent
71
+ ```
72
+
73
+ `fakesshagent` requires Python 3.9 or higher as well as the [typing-extensions package][TYPING_EXTENSIONS] and the [`derivepassphrase-sshagentsocketprovider` package][SASP] for its core functionality and programmatic interface.
74
+
75
+ [TYPING_EXTENSIONS]: https://pypi.org/project/typing-extensions/
76
+ [SASP]: https://pypi.org/project/derivepassphrase-sshagentsocketprovider/
77
+
78
+ ## License
79
+
80
+ `fakesshagent` is distributed under the terms of the [zlib/libpng](https://spdx.org/licenses/Zlib.html) license.
@@ -0,0 +1,35 @@
1
+ # fakesshagent
2
+
3
+ [![PyPI - Version](https://img.shields.io/pypi/v/fakesshagent.svg)](https://pypi.org/project/fakesshagent)
4
+ [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/fakesshagent.svg)](https://pypi.org/project/fakesshagent)
5
+
6
+ A non-hardened implementation of the SSH agent protocol, for use in testing.
7
+
8
+ `fakesshagent` was originally written to test [`derivepassphrase`][DERIVEPASSPHRASE]'s SSH agent interactions.
9
+ As such, `fakesshagent` also registers as an abstract SSH agent socket provider for [`derivepassphrase`][DERIVEPASSPHRASE].
10
+ (The implementation is based on memory buffers, not external I/O with sockets.)
11
+
12
+ In this first release, `fakesshagent` provides exactly the operations needed for use with `derivepassphrase`:
13
+ listing available keys, and deterministically signing a fixed message (if possible with this key type), for a set of known test keys.
14
+ See the wishlist for planned features of subsequent releases.
15
+
16
+ [DERIVEPASSPHRASE]: https://the13thletter.info/derivepassphrase/
17
+
18
+ -----
19
+
20
+ ## Installation
21
+
22
+ `fakesshagent` is a pure Python package, and may be easily installed with any `pip`-compatible Python package manager such as `pip`, `pipx`, or `uv`.
23
+
24
+ ```console
25
+ pip install fakesshagent
26
+ ```
27
+
28
+ `fakesshagent` requires Python 3.9 or higher as well as the [typing-extensions package][TYPING_EXTENSIONS] and the [`derivepassphrase-sshagentsocketprovider` package][SASP] for its core functionality and programmatic interface.
29
+
30
+ [TYPING_EXTENSIONS]: https://pypi.org/project/typing-extensions/
31
+ [SASP]: https://pypi.org/project/derivepassphrase-sshagentsocketprovider/
32
+
33
+ ## License
34
+
35
+ `fakesshagent` is distributed under the terms of the [zlib/libpng](https://spdx.org/licenses/Zlib.html) license.
@@ -0,0 +1,2 @@
1
+ <!-- Originally downloaded from https://img.shields.io/badge/Keep-a-changelog-E05735?logoColor=fff&logo=keepachangelog&logoSize=auto on 2024-07-21. Used under CC0, as per https://github.com/badges/shields/blob/1e4c8f54d7743381e723a1ca3f79db7868c2f95e/LICENSE . -->
2
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="127.21161107182145" height="20" role="img" aria-label="Keep a changelog"><title>Keep a changelog</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="127.21161107182145" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="0" height="20" fill="#555"/><rect x="0" width="127.21161107182145" height="20" fill="#e05735"/><rect width="127.21161107182145" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14.21161107182145" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjZmZmIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyMy42NDI3NjMyMTAwOTQ4NjYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPktlZXAgYSBDaGFuZ2Vsb2c8L3RpdGxlPjxwYXRoIGQ9Ik05LjgwMzEgMC4wMDAzQzkuMTA4MSAtMC4wMDQ3IDguNDEzMSAwLjA2MTMgNy43MjAxIDAuMjAxM0M1LjYzOTEgMC42MTgzIDMuOTc0MSAxLjY0OTMgMi43NzAxIDMuMjY2M0MxLjIzMjEgNS4zMzYzIDAuMzY3MSA3Ljg5MzMgMC4wNDkxIDExLjMxMzNDLTAuMDc1OSAxMi42NjYzIDAuMDU3MSAxNC4wMjQzIDAuMjMwMSAxNS41MjkzQzAuNDI4MyAxNy40MzczIDEuMTcyNyAxOS4yNDc3IDIuMzc0MSAyMC43NDMzQzMuMzA3MSAyMS45MDAzIDQuMzc4MSAyMi42NjAzIDUuNjQ2MSAyMy4wNjczQzYuNzI1MyAyMy40MTU2IDcuODQ4NiAyMy42MDg5IDguOTgyMSAyMy42NDEzQzkuMjQ3NiAyMy42NDcxIDkuNTEzMSAyMy42MzU4IDkuNzc3MSAyMy42MDczTDEwLjE5MzEgMjMuNTY2M0MxMC43Njc0IDIzLjUwOTYgMTEuMzQxMSAyMy40NDc2IDExLjkxNDEgMjMuMzgwM0MxNC40OTUgMjMuMDgyNyAxNy4wMDAxIDIyLjMxNzkgMTkuMzA3MSAyMS4xMjMzQzIxLjMxNDEgMjAuMDc1MyAyMi43MTcxIDE4LjUyOTMgMjMuNDc3MSAxNi41MjYzQzIzLjgzMTEgMTUuNTk2MyAyNC4wMDAxIDE0LjgxMzMgMjQuMDAwMSAxNC4wODEzQzI0IDEzLjgyNTkgMjMuOTc4NiAxMy41NzEgMjMuOTM2MSAxMy4zMTkzQzIzLjUzMTEgMTAuOTQwMyAyMi43MDExIDguODkxMyAyMS4zODExIDcuMDU1M0MxOS43NDcxIDQuNzc5MyAxOC4wOTMxIDMuMTc3MyAxNi4xNzkxIDIuMDEwM0MxMy45OTMxIDAuNjgxMyAxMS44OTAxIDAuMDE0MyA5LjgwMzEgMC4wMDEzWk05LjM2NDEgMS4wNjQzQzEwLjEzNDEgMS4wNDMzIDEwLjkyNDEgMS4xMjIzIDExLjc0MDEgMS4zMDEzSDExLjczOTFDMTQuNDY5MSAxLjg5ODMgMTYuODc2MSAzLjMwMzMgMTguODkzMSA1LjQ3NDNDMjEuMTgxMSA3LjkzNDMgMjIuNDg0MSAxMC41MTkzIDIyLjg4MTEgMTMuMzczM0MyMi45NTIxIDEzLjkwMTMgMjIuODY4MSAxNC40ODczIDIyLjc4NTEgMTQuOTk1M0MyMi4zOTcxIDE3LjMyMjMgMjEuMTIyMSAxOS4wNTgzIDE4Ljk5OTEgMjAuMTU1M0MxNi43NjA1IDIxLjMwNjIgMTQuMzMzMyAyMi4wNDUzIDExLjgzMzEgMjIuMzM3M0MxMS4yNzUxIDIyLjQwMzMgMTAuNzEzMSAyMi40NjAzIDEwLjA3NjEgMjIuNTI0M0w5Ljk4ODEgMjIuNTM0M0M5LjQzNjMgMjIuNTkxNSA4Ljg3OTUgMjIuNTgxNSA4LjMzMDEgMjIuNTA0M0M3LjY0MDEgMjIuNDA2MyA2Ljg1ODEgMjIuMjk0MyA2LjEwNjEgMjIuMTE1M0M0LjMzOTEgMjEuNjk1MyAzLjAzNzEgMjAuNDkzMyAyLjEyODEgMTguNDU3M0MxLjQ0NDEgMTYuOTE5MyAxLjA5MDEgMTUuMjEyMyAxLjA0NzEgMTMuMjI0M0MwLjk4NjUgMTAuOTA1MiAxLjM3NjcgOC41OTY1IDIuMTk2MSA2LjQyNjNDMi44MTYxIDQuNzg1MyAzLjcxMzEgMi45NzMzIDUuNjU4MSAyLjAwODNDNi44MDg3IDEuNDI0MSA4LjA3NDMgMS4xMDE3IDkuMzY0MSAxLjA2NDNaTTEwLjQ3MjEgMi41MzQzQzkuNzA5MyAyLjU1OTggOC45NTQ1IDIuNjk4IDguMjMyMSAyLjk0NDNDNi42MzIxIDMuNDY5MyA1LjUxNDEgNC4yNDgzIDQuNzA5MSA1LjM4MjNDMy4yMTAxIDcuNTAwMyAyLjQzNDEgOS45NjIzIDIuMzk5MSAxMi43MDczQzIuMzM3MiAxNC4yMTE0IDIuNjExNSAxNS43MTA1IDMuMjAyMSAxNy4wOTUzQzQuMjgzMSAxOS42NjQzIDYuMjU1MSAyMS4xNTkzIDguOTA5MSAyMS40MjEzQzExLjcwNTEgMjEuNjkxMyAxNC40NTIxIDIxLjA0MDMgMTcuMDg3MSAxOS40ODQzQzE4LjIwNjUgMTguODQyMiAxOS4xNTY3IDE3Ljk0MjcgMTkuODU5MSAxNi44NjAzQzIwLjYxMzIgMTUuNzEzNCAyMS4wMTg4IDE0LjM3MjcgMjEuMDI3MSAxMy4wMDAzQzIxLjAyNzEgMTAuODM4MyAyMC4wMTIxIDguNTMwMyAxNy45NzgxIDYuMTM4M0MxNy43NjIyIDUuODg0NiAxNy41MjY4IDUuNjQ4MyAxNy4yNzQxIDUuNDMxM0MxNC45NDExIDMuNDI1MyAxMi43MDcxIDIuNDY1MyAxMC40NzIxIDIuNTMzM1pNMTAuNTcxMSAzLjU2OTNDMTIuMDYzMSAzLjU0NzMgMTMuNTg2MSA0LjA0NDMgMTUuMjQzMSA1LjA3NzNDMTcuMDI2MSA2LjE5NDMgMTguNDA0MSA3Ljg0MDMgMTkuMzM0MSA5Ljk4NjNDMjAuMjIxMSAxMi4wMDYzIDIwLjIzOTEgMTMuOTI0MyAxOS4zOTIxIDE1LjY4MjNDMTguNzU5NCAxNi45NTc3IDE3Ljc0MjcgMTguMDAyNyAxNi40ODUxIDE4LjY3MDNDMTQuMjMyMSAxOS45MDIzIDEyLjE3MDEgMjAuNDQ2MyAxMC4wMjcxIDIwLjM4MzNIMTAuMDA1MUM4LjQ1NTEgMjAuNDQzMyA3LjExNTEgMjAuMDYzMyA1LjkwNzEgMTkuMjIwM0M1LjIwNzEgMTguNzMyMyA0LjY2NjEgMTguMDE4MyA0LjI1MjEgMTcuMDM3M0MzLjY3NzYgMTUuNjg1OSAzLjM4MTEgMTQuMjMyNyAzLjM4MDEgMTIuNzY0M0MzLjM5NzkgMTEuMDk0OSAzLjc0NTkgOS40NDU1IDQuNDA0MSA3LjkxMTNDNC42NTQgNy4zNDkzIDQuOTQ2MiA2LjgwNyA1LjI3ODEgNi4yODkzTDUuNDQxMSA2LjAxOTNDNi4xMTExIDQuOTExMyA3LjE2NjEgNC4zODAzIDguNTQ0MSAzLjkyMDNDOS4xOTggMy43MDA4IDkuODgxNiAzLjU4MjggMTAuNTcxMSAzLjU3MDNaTTEwLjYwMTEgNS4xODkzQzkuNDIxMSA1LjIyNjMgOC4zMjExIDUuNjU0MyA3LjMxMjEgNi40NzIzQzUuOTE3MSA3LjYwMjMgNS4wODIxIDkuMTkyMyA0LjY4MjEgMTEuNDY1M0M0LjM5MjcgMTMuMDM1NCA0LjYzMDQgMTQuNjU3MiA1LjM1ODEgMTYuMDc4M0M2LjQyMDEgMTguMTMyMyA4LjE1ODEgMTkuMTg4MyAxMC4zODQxIDE5LjEyODNIMTAuMzkyMUMxMy4zNTAxIDE4Ljk3MzMgMTUuNTAyMSAxNy44NzkzIDE2Ljk2NTEgMTUuNzgxM0MxNy42NDczIDE0LjgzNjEgMTguMDE3OCAxMy43MDE4IDE4LjAyNTEgMTIuNTM2M0MxOC4wMjMxIDExLjk4MTIgMTcuOTQxNiAxMS40MjkyIDE3Ljc4MzEgMTAuODk3M0MxNy4wNjMxIDguNDYyMyAxNS42MjIxIDYuNzUyMyAxMy40OTMxIDUuODEyM0MxMi40ODQxIDUuMzY3MyAxMS41MTkxIDUuMTYwMyAxMC42MDExIDUuMTg4M1pNMTAuOTEzMSA2LjI1MzNDMTEuNjgzMSA2LjI2MTMgMTIuNDYwMSA2LjQ0NDMgMTMuMjYzMSA2LjgwMzNDMTUuMTI1MSA3LjYzNjMgMTYuMzM2MSA5LjEzNTMgMTYuODYxMSAxMS4yNjUzQzE3LjM4NzEgMTMuMzk1MyAxNi41OTExIDE1LjQ3MDMgMTQuNzk1MSAxNi42ODgzQzEzLjMxNjEgMTcuNjg3MyAxMS44NjUxIDE4LjEzNTMgMTAuMzU3MSAxOC4wNTUzSDEwLjMxNzFDOS4zMTMxIDE4LjEzNTMgOC4zMjMxIDE3LjgyOTMgNy4zNzQxIDE3LjE0NTNDNi43ODIgMTYuNzEzNyA2LjMzMjcgMTYuMTE0NiA2LjA4NDEgMTUuNDI1M0M1Ljc0NzggMTQuNTU1MyA1LjU3MzYgMTMuNjMxIDUuNTcwMSAxMi42OTgzQzUuNTgzOSAxMS41MzIyIDUuODM4MiAxMC4zODE1IDYuMzE3MSA5LjMxODNDNi45OTMxIDcuNzYyMyA4LjA0MTEgNi44MTUzIDkuNTMyMSA2LjQyNTNDOS45OTIxIDYuMzA1MyAxMC40NTExIDYuMjQ3MyAxMC45MTIxIDYuMjUzM1pNOS40NTUxIDguNTc5M1YxNS40NjEzSDEwLjYxMDFWMTMuNTUzM0wxMi4yOTAxIDE1LjQ2MTNIMTMuNzUyMUwxMS40NzkxIDEyLjk2MTNMMTMuMzUwMSAxMS4wMDMzSDExLjg0MTFMMTAuNjEwMSAxMi4zNDAzVjguNTc5M1oiLz48L3N2Zz4="/><text aria-hidden="true" x="727.1161107182145" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="990">Keep a changelog</text><text x="727.1161107182145" y="140" transform="scale(.1)" fill="#fff" textLength="990">Keep a changelog</text></g></svg>
@@ -0,0 +1,2 @@
1
+ <!-- Originally downloaded from https://img.shields.io/badge/SemVer-3F4551?logoColor=fff&logo=semver&logoSize=auto on 2024-07-21. Used under CC0, as per https://github.com/badges/shields/blob/1e4c8f54d7743381e723a1ca3f79db7868c2f95e/LICENSE . -->
2
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="71.00018479842694" height="20" role="img" aria-label="SemVer"><title>SemVer</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="71.00018479842694" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="0" height="20" fill="#555"/><rect x="0" width="71.00018479842694" height="20" fill="#3f4551"/><rect width="71.00018479842694" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14.00018479842695" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNC4wMDAzNzU5MjkyNjAxNTUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPlNlbVZlcjwvdGl0bGU+PHBhdGggZD0iTTAuMzU3IDkuMDI0NkMtMC41OTQzIDEyLjg0ODcgMC4zODExIDE2Ljg5NjUgMi45NyAxOS44Njc2QzUuNTU4IDIyLjgzNjkgOS40MzM5IDI0LjM1NCAxMy4zNSAyMy45MzA2QzIxLjExOCAyMy4yMjc2IDI2LjQzNiAxNC4xMzE2IDIyLjg2NyA3LjEzMDZDMjIuNDUxIDUuOTQwNiAyMC43OTcgNi43NjI2IDIwLjk2NCA3LjcyNjZDMjEuMjUxIDguNDI2NiAyMS40OSA5LjE0NzYgMjEuNjc3IDkuODgxNkMyMi41MzI1IDEzLjc3NTcgMjAuOTg5IDE3LjgwNTQgMTcuNzUxIDIwLjEzMTZDMTIuNzA2NiAyMy43NTI1IDUuNjE0OSAyMS45MjgyIDIuOTQ0IDE2LjMyMjZDMS4yMjY3IDEyLjcyNDMgMS44MTQ4IDguNDQ5NCA0LjQ0IDUuNDQ4NkM1LjcyNDEgMy45ODE0IDcuNDEwNCAyLjkyMyA5LjI5IDIuNDA0NkMxMS42Mjc4IDEuNzQzNSAxNC4xMjc0IDEuOTY4MiAxNi4zMSAzLjAzNTZDMTYuNDY2OCAzLjExNTIgMTYuNTM0NyAzLjMwMzEgMTYuNDY1IDMuNDY0NkwxMi41MDMgMTQuMDg0NkMxMi4zOTYgMTQuODk0NiAxMS44MTMgMTQuODcwNiAxMS43MDYgMTQuMDg0Nkw5LjMyNiA2LjcxNDZDOS4yMTY1IDYuMjkyMiA4LjkzNjYgNS45MzQ0IDguNTUzIDUuNzI2NkM3LjM2MyA1LjE2NjYgNS40NiA2LjM5MzYgNi4xNzQgNy44ODE2TDEwLjA4OCAxOC4zMjI2QzEwLjYxMiAxOS43MTU2IDExLjExMSAyMC4xNTY2IDEyLjE0NiAyMC4xNTY2UzEzLjY4MSAxOS43MTY2IDE0LjIwNCAxOC4zMjI2TDIwIDMuOTQwNkMyMC4xNTU5IDMuNTA2IDIwLjAwNTQgMy4wMjA3IDE5LjYzMSAyLjc1MDZDMTMuMSAtMi45MDY0IDIuMzIgMC42NDE2IDAuMzU3IDkuMDIzNloiLz48L3N2Zz4="/><text aria-hidden="true" x="445.0018479842695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">SemVer</text><text x="445.0018479842695" y="140" transform="scale(.1)" fill="#fff" textLength="430">SemVer</text></g></svg>
@@ -0,0 +1,53 @@
1
+ # Changelog for `fakesshagent`
2
+
3
+ [![Keeping a changelog][CHANGELOG_BADGE]][KEEP_A_CHANGELOG]
4
+ [![Using Semantic Versioning][SEMVER_BADGE]][SEMANTIC_VERSIONING]
5
+
6
+ [CHANGELOG_BADGE]: Keep_a_changelog-E05735.svg
7
+ [SEMVER_BADGE]: SemVer-3F4551.svg
8
+ [KEEP_A_CHANGELOG]: https://keepachangelog.com/en/1.1.0/ 'Keeping a changelog'
9
+ [SEMANTIC_VERSIONING]: https://semver.org/ 'Using Semantic Versioning'
10
+
11
+ ??? info "Definition: the <q>public API</q> of `fakesshagent`"
12
+
13
+ The <dfn>public API</dfn>, as defined by Semantic Versioning, is
14
+ outlined in the Reference section: the set of documented
15
+ modules, classes, attributes, methods, functions and function
16
+ parameters, and the documented behavior, options and arguments of the
17
+ command-line tools.
18
+
19
+ Certain **exceptions to this rule** are explicitly and prominently
20
+ marked as implementation details/not part of the public API.
21
+
22
+ ??? info "Interpretation of the version number"
23
+
24
+ The terminology <b>major</b>, <b>minor</b> and <b>patch</b> follows the
25
+ Semantic Versioning and Keep a Changelog definitions.
26
+
27
+ * For version numbers with major version zero, *any* new release may
28
+ effectively constitute a new <b>major</b> release.
29
+ * For version numbers with major version one or higher,
30
+ * <b>Fixed</b> entries justify a <b>patch</b> release;
31
+ * <b>Added</b> and <b>Deprecated</b> entries justify
32
+ a <b>minor</b> release;
33
+ * <b>Changed</b> and <b>Removed</b> entries justify a <b>major</b>
34
+ release.
35
+ * <b>Security</b> can justify any type of release; if <b>major</b>
36
+ or <b>minor</b>, these are accompanied by corresponding entries
37
+ of the respective types above.
38
+
39
+ !!! abstract inline end "Legend: symbols"
40
+
41
+ <ul style="list-style-type: none;">
42
+ <li>:material-bug: --- a related bug entry from the wishlist page
43
+ <li>:material-file-document-plus-outline: --- a related wishlist entry from the wishlist page
44
+ </ul>
45
+
46
+ <aside markdown><small>
47
+ (All entries are from the perspective of a user of the program or the API.
48
+ As an exception, entries partaining to developers of `fakesshagent` are
49
+ specifically marked as such.)
50
+ </small></aside>
51
+
52
+ <!-- scriv changelog start -->
53
+
@@ -0,0 +1,26 @@
1
+ # How to comply with the "altered versions" clause of the license
2
+
3
+ !!! abstract inline end "Local version identifiers reserved by upstream `fakesshagent`"
4
+
5
+ * `jvm` -- Indicates a build of `fakesshagent` running on the Java Virtual Machine.
6
+
7
+ **Short answer:** change the package name and/or include a [PEP 440][] "local version identifier" in the version number.
8
+ If `fakesshagent` ever rebrands, this applies to rebranded names too.
9
+ We try not to clash with anyone else, and will yank our offending releases if we do.
10
+
11
+ **Long answer:** We, upstream `fakesshagent`, reserve the name `fakesshagent` and certain version numbers for ourselves.
12
+ Specifically, our version numbers adhere to [PEP 440][] (or newer revisions) and generally do not include a "local version identifier" (except for the reserved ones mentioned in the info box).
13
+ To mark an altered version, we thus recommend that you change the software package name `fakesshagent`, or use a version number with a different local version identifier.
14
+ If we (upstream) decide to use a new local version identifier, we will avoid all clashing local version identifiers we are aware of, and if informed of a clashing local version identifier after our release, will yank our offending version(s).
15
+
16
+ Should we (upstream) change the package name, we shall apply the same guidelines and checks concerning local version identifiers to the new package name.
17
+ A change of package name does *not* by itself imply permission to use the old package name for future releases of altered versions without marking them.
18
+
19
+ ---
20
+
21
+ See also [the zlib project's take on how to mark altered versions (question #24)][ZLIB_FAQ].
22
+ Like them, we recommend keeping our upstream Changelog (up to the point where you introduced modifications) and describing your modifications both there and in the README, in the appropriate level of detail.
23
+ We also request (but do not require) that you provide clear instructions in the README (and potentially other suitable places) on where and how to report problems that stem from your modifications, not from the upstream software package.
24
+
25
+ [PEP 440]: https://peps.python.org/pep-0440/
26
+ [ZLIB_FAQ]: https://github.com/madler/zlib/blob/v1.3.1/FAQ
@@ -0,0 +1,8 @@
1
+ ---
2
+ title: Explanation overview
3
+ ---
4
+
5
+ * [How to comply with the "altered versions" clause of the
6
+ license][FAQ_ALTERED_VERSIONS]
7
+
8
+ [FAQ_ALTERED_VERSIONS]: faq-altered-versions.md
@@ -0,0 +1 @@
1
+ --8<-- "README.md"
@@ -0,0 +1,35 @@
1
+ /* Indentation. */
2
+ div.doc-contents:not(.first) {
3
+ padding-left: 25px;
4
+ border-left: .05rem solid var(--md-typeset-table-color);
5
+ }
6
+
7
+ /* Mark external links as such. */
8
+ div[data-md-component="content"] a:not(.md-icon):is([href^="https://"], [href^="http://"], [href^="//"])::after,
9
+ a.external::after,
10
+ a.autorefs-external::after {
11
+ /* https://primer.style/octicons/arrow-up-right-24 */
12
+ mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.25 15.5a.75.75 0 00.75-.75v-9a.75.75 0 00-.75-.75h-9a.75.75 0 000 1.5h7.19L6.22 16.72a.75.75 0 101.06 1.06L17.5 7.56v7.19c0 .414.336.75.75.75z"></path></svg>');
13
+ -webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.25 15.5a.75.75 0 00.75-.75v-9a.75.75 0 00-.75-.75h-9a.75.75 0 000 1.5h7.19L6.22 16.72a.75.75 0 101.06 1.06L17.5 7.56v7.19c0 .414.336.75.75.75z"></path></svg>');
14
+ content: ' ';
15
+
16
+ display: inline-block;
17
+ vertical-align: middle;
18
+ position: relative;
19
+
20
+ height: 1em;
21
+ width: 1em;
22
+ background-color: currentColor;
23
+ }
24
+
25
+ /* ... but don't mark badges as external */
26
+ div[data-md-component="content"] a:not(.md-icon):is([href^="https://"], [href^="http://"], [href^="//"]):has(img[src^="https://img.shields.io/"], img[src="Keep_a_changelog-E05735.svg"], img[src="../Keep_a_changelog-E05735.svg"], img[src="SemVer-3F4551.svg"], img[src="../SemVer-3F4551.svg"])::after {
27
+ content: '';
28
+ width: 0em;
29
+ height: 0em;
30
+ }
31
+
32
+ a.external:hover::after,
33
+ a.autorefs-external:hover::after {
34
+ background-color: var(--md-accent-fg-color);
35
+ }
@@ -0,0 +1,87 @@
1
+ # Compatibility of `fakesshagent` with different Python versions
2
+
3
+ ## Python 3.15 {#py3.15}
4
+
5
+ Currently supported without any known issues.
6
+
7
+ ## Python 3.14 {#py3.14}
8
+
9
+ Currently supported without any known issues.
10
+
11
+ ### After end-of-life {#after-eol-py3.14}
12
+
13
+ After Python 3.14 reaches end-of-life, future `fakesshagent` versions may make use of the following Python functionality:
14
+
15
+ * lazy imports
16
+ * the `frozendict` type
17
+
18
+ The declared minimum required Python version will then be updated accordingly.
19
+
20
+ ## Python 3.13 {#py3.13}
21
+
22
+ Currently supported without any known issues.
23
+
24
+ ### After end-of-life {#after-eol-py3.13}
25
+
26
+ After Python 3.13 reaches end-of-life, future `fakesshagent` versions may make use of the following Python functionality:
27
+
28
+ * template strings
29
+
30
+ The declared minimum required Python version will then be updated accordingly.
31
+
32
+ ## Python 3.12 {#py3.12}
33
+
34
+ Currently supported without any known issues.
35
+
36
+ ### After end-of-life {#after-eol-py3.12}
37
+
38
+ Python 3.13 does not offer significantly different functionality than Python 3.12.
39
+ There are thus no plans to make use of additional functionality once Python 3.12 reaches end-of-life.
40
+
41
+ ## Python 3.11 {#py3.11}
42
+
43
+ Currently supported without any known issues.
44
+
45
+ ### After end-of-life {#after-eol-py3.11}
46
+
47
+ After Python 3.11 reaches end-of-life, future `fakesshagent` versions may make use of the following Python functionality:
48
+
49
+ * complex expressions in f-strings
50
+ * type parameter syntax and the `type` statement
51
+
52
+ The declared minimum required Python version will then be updated accordingly.
53
+
54
+ ## Python 3.10 {#py3.10}
55
+
56
+ Currently supported without any known issues.
57
+
58
+ ### After end-of-life {#after-eol-py3.10}
59
+
60
+ After Python 3.10 reaches end-of-life, future `fakesshagent` versions may make use of the following Python functionality:
61
+
62
+ * exception groups
63
+ * exception notes
64
+ * [`contextlib.chdir`][]
65
+
66
+ The declared minimum required Python version will be then updated accordingly.
67
+
68
+ ## Python 3.9 {#py3.9}
69
+
70
+ End-of-life since October 2025, but still supported at least until `fakesshagent` v1.0, without any known issues.
71
+
72
+ ### After end-of-life {#after-eol-py3.9}
73
+
74
+ After Python 3.9 reaches end-of-life, future `fakesshagent` versions may make use of the following Python functionality:
75
+
76
+ * structural pattern matching (`match`/`case` blocks)
77
+ * parenthesized `with` statements
78
+
79
+ The declared minimum required Python version will be then updated accordingly.
80
+
81
+ ## Python 3.8 and below {#py3.8-and-below}
82
+
83
+ These versions were never explicitly supported, neither in CPython nor in PyPy.
84
+
85
+ ## PyPy
86
+
87
+ As per the respective CPython version above.
@@ -0,0 +1,4 @@
1
+ # Upgrade notes for `fakesshagent`
2
+
3
+ (Nothing yet.
4
+ Once there is something, this will be listed here, oldest version first.)
@@ -0,0 +1,45 @@
1
+ # Bugs & wishlist items
2
+
3
+ <small>(… a.k.a. "things to fix" and "things to add".)</small>
4
+
5
+ !!! abstract inline end "Legend: Formatting"
6
+ - [scheduled for next release](index.md){: .scheduled-next }
7
+ - [scheduled for some future release](index.md){: .scheduled }
8
+ - [yet to be scheduled](index.md){: .unscheduled }
9
+
10
+ ???+ bug "things to fix"
11
+ <i>no entries</i>
12
+
13
+ ???+ wish "things to add"
14
+ - [sans-io][]{: .scheduled-next }
15
+
16
+ ??? bug-success "things fixed"
17
+ <i>no entries</i>
18
+
19
+ ??? wish-success "things added"
20
+ <i>no entries</i>
21
+
22
+ ??? note "About this wishlist"
23
+
24
+ This is the list of bugs and wishes for `fakesshagent`.
25
+ It uses the same terminology and style as [PuTTY's wishlist][PUTTY_WISHLIST].
26
+ By design, the list distinguishes solely between bugs and wishes, and focuses strongly on the facts, not on the plans for implementation.[^bug-tracking-concerns]
27
+ The entries are named, not numbered, and the summaries are written by hand.
28
+
29
+ The list is built statically; there is no interactive way to submit entries or commentary on an entry, or to run search queries against the entry database.
30
+ To submit entries or commentary, contact the authors directly; see the website imprint and the embedded author info in version control.
31
+ To run search queries or other automated queries against the entry database, check out the `wishlist` branch from version control and parse the entry files directly.
32
+
33
+ See also the [entry format specification][ENTRY_SPEC].
34
+
35
+ [^bug-tracking-concerns]:
36
+ See also the essay [Separation of concerns in a bug tracker][BUG_TRACKING_CONCERNS] by PuTTY's principal author, Simon Tatham.
37
+ Like PuTTY, `fakesshagent` is a "more serious free-software hobby project" developed by one principal author who also cannot definitively commit to any specific time plan.
38
+ As such, `fakesshagent` also does not have a formal plans table (beyond the very coarse <b>Priority</b> field).
39
+
40
+ [sans-io]: sans-io.md
41
+
42
+ [ENTRY_SPEC]: spec.md
43
+
44
+ [PUTTY_WISHLIST]: https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ "PuTTY Known Bugs and Wish List"
45
+ [BUG_TRACKING_CONCERNS]: https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/bugtracker-separate/ 'Simon Tatham: "Separation of concerns in a bug tracker"'
@@ -0,0 +1,32 @@
1
+ # `fakesshagent` wish sans-io
2
+
3
+ ???+ wish "Wish details: `fakesshagent` should be a Sans-I/O implementation of the SSH agent protocol"
4
+ <table id="bug-summary" markdown>
5
+ <tr><th scope=col>Class<td><i>wish</i><td>This is a request for an enhancement.
6
+ <tr><th scope=col>Priority<td><i>high</i><td>This should be fixed in the next release.
7
+ <tr><th scope=col>Difficulty<td><i>fun</i><td>Just needs tuits, and not many of them.
8
+ <tr><th scope=col>Requested-in<td colspan=2>0.1
9
+ </table>
10
+
11
+ The fake/stub SSH agent in version 0.1 of `fakesshagent` is almost a [Sans-I/O][SANS_IO] protocol parser.[^sans-io]
12
+ However, it currently neither has separate business logic---the "stub" part is intertwined with the "parser" part---nor does it implement a Sans-I/O-style "stream of events" interface (because the business logic is not yet separate).
13
+ It should have/do both.
14
+
15
+ Actually separating the business logic from the parser, Sans-I/O-style, would also enable porting the remaining SSH test double of [`derivepassphrase`][DERIVEPASSPHRASE]: the `AgentRequestResponseQueue`, which maps protocol requests to a list of protocol responses.[^difference-queue-and-stub-agent]
16
+ The queue thus already operates on (a primitive version of) the event-based interface.
17
+
18
+ * * *
19
+
20
+ <b>Therefore</b>, rewrite the fake/stub agent into a parser and a (proper) stub agent, and have the parser expose a Sans-I/O-style "stream of events" interface.
21
+
22
+ [^sans-io]:
23
+ In a Sans-I/O network protocol parser, the parser and the network I/O machinery are completely separate, enabling the parser to be used under all kinds of different I/O paradigms.
24
+ Porting I/O paradigms is usually practically infeasible, and if the protocol parser were intertwined with the I/O, then the parser would likely need to be rewritten from scratch.
25
+
26
+ [^difference-queue-and-stub-agent]:
27
+ The `AgentRequestResponseQueue` differs from the fake/stub agent in that the queue only understands the protocol framing, not the protocol contents.
28
+ The queue requires and enforces well-formed requests and responses, and will always answer the same request in the same way, irrespective of session state.
29
+ It is thus less flexible, but also easier to set up.
30
+
31
+ [DERIVEPASSPHRASE]: https://the13thletter.info/derivepassphrase/
32
+ [SANS_IO]: https://sans-io.readthedocs.io/
@@ -0,0 +1,92 @@
1
+ # bug and wish entry specification
2
+
3
+ All bug and wish entries consist of a <dfn>header</dfn>, describing the properties of this entry, and a <dfn>summary</dfn> below.
4
+
5
+ The system is mostly compatible with PuTTY's wishlist; differences are marked below.
6
+ Unlike PuTTY, the entry files are not RFC822-like plain text, but rather Markdown files (with some raw HTML parts), to cleanly integrate with the rest of the documentation.
7
+ (The Markdown+HTML files are still very regular, and thus should still be reasonably parsable.)
8
+
9
+ ## The header
10
+
11
+ The header is a table with fixed keys.
12
+ For some of the keys, if they have only a fixed amount of values they can take on, then they have a specific interpretation text that accompanies them.
13
+ In the order of appearance:
14
+
15
+ Summary
16
+ : A brief description of the bug, in plain text.
17
+ Comparable to subject lines in e-mail.
18
+
19
+ Class
20
+ : What kind of entry is this?[^distinguishing-between-bugs-and-wishes]
21
+
22
+ | value | interpretation |
23
+ | ------ | ------------------------------------------------ |
24
+ | `bug` | This is clearly an actual problem we want fixed. |
25
+ | `wish` | This is a request for an enhancement. |
26
+
27
+ (Unlike PuTTY, we do not further differentiate between `semi-bug`, `vulnerability` and `bug` at the class level.)
28
+
29
+ Priority
30
+ : How urgent is this entry?
31
+ An anchored ordinal scale with subjective interpretation.
32
+
33
+ | value | interpretation |
34
+ | ---------------------------------- | ----------------------------------------------------------------------------- |
35
+ | `high` | This should be fixed in the next release. |
36
+ | `medium` | This should be fixed one day. |
37
+ | `low` | We aren't sure whether to fix this or not. |
38
+ | `historic` (bug), `dormant` (wish) | This issue is old and we don't think it still has value on the main wishlist. |
39
+ | `never` | We don't ever intend to fix this. |
40
+
41
+ Difficulty
42
+ : How difficult is this entry to fix/implement?
43
+ An anchored ordinal scale with subjective interpretation.
44
+
45
+ | value | interpretation |
46
+ | -------- | ---------------------------------------------------------- |
47
+ | `fun` | Just needs tuits, and not many of them. |
48
+ | `tricky` | Needs many tuits. |
49
+ | `taxing` | Needs external things we don't have (standards, users etc) |
50
+ | `mayhem` | Probably impossible |
51
+
52
+ Present-in:
53
+ : For bugs only: A space-separated list of version numbers (for releases), dates or version control commit IDs (for snapshots) that the bug has been observed in.
54
+ Dates are formatted as ISO 8601 `YYYY-MM-DD` dates, version numbers and commit IDs in their natural format without additional adornments.
55
+
56
+ (PuTTY also factually uses <b>Present-in</b> for wishes.)
57
+
58
+ Absent-in:
59
+ : For bugs only: A space-separated list of version numbers (for releases), dates or version control commit IDs (for snapshots) that the bug has been observed *not* in.
60
+ Same formatting as for <b>Present-in</b>.
61
+
62
+ Requested-in:
63
+ : For wishes only: A space-separated list of version numbers (for releases) or version control commit IDs (for snapshots), or a single date that the wish was requested in/on.
64
+
65
+ (PuTTY uses <b>Present-in</b> for this purpose.)
66
+
67
+ Fixed-in:
68
+ : A space-separated list of version numbers (for releases), dates or version control commit IDs (for snapshots) that the bug was fixed in or the wish was implemented in.
69
+ Same formatting as for <b>Present-in</b>.
70
+ Version control commit IDs may be prefixed with `~` to indicate that the bug/wish was confirmed fixed/implemented in this commit <i>or an ancestor commit</i>.
71
+
72
+ Depends:
73
+ : A space-separated list of other bug/wish entry names that must be fixed/implemented first.
74
+
75
+ Blocks:
76
+ : A space-separated list of other bug/wish entry names that are waiting for this entry to be fixed/implemented.
77
+
78
+ (Not documented in PuTTY's wishlist entry specification, but in use across that wishlist.)
79
+
80
+ [^distinguishing-between-bugs-and-wishes]:
81
+ A bug is specifically an entry describing an aspect of this software that, if not fixed, impedes or prohibits the user from accomplishing their goal with or within this software.
82
+ Every other entry is a wish.
83
+
84
+ ## The summary
85
+
86
+ The summary is a free-form prose summary of the bug or wish.
87
+ It is intended to be easily scannable, like a good commit message, and likely benefits from many of the same writing conventions.
88
+ In particular, the summary *should not* be a chronological listing of events or messages related to this bug or wish, but rather a proper summarization of those events, messages, and related facts and opinions.
89
+
90
+ Specific to this system, the summary always contains a paragraph beginning with <b>Therefore</b> that describes the action to take for this entry.
91
+ If applicable, a sentence beginning with <b>Until then</b> within that paragraph contains workarounds or partial solutions that will be applied or have already been applied.
92
+ Except for optional historical context that may follow this paragraph and is then hidden by default, the <b>Therefore</b> paragraph is the *last* paragraph of the summary.