ciscoyoke 0.1.0a1__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 (120) hide show
  1. ciscoyoke-0.1.0a1/.gitignore +31 -0
  2. ciscoyoke-0.1.0a1/CHANGELOG.md +39 -0
  3. ciscoyoke-0.1.0a1/CONTRIBUTING.md +65 -0
  4. ciscoyoke-0.1.0a1/LICENSE +21 -0
  5. ciscoyoke-0.1.0a1/PKG-INFO +291 -0
  6. ciscoyoke-0.1.0a1/README.md +235 -0
  7. ciscoyoke-0.1.0a1/docs/ARCHITECTURE.md +92 -0
  8. ciscoyoke-0.1.0a1/docs/HARDWARE-TESTING.md +85 -0
  9. ciscoyoke-0.1.0a1/docs/SAFETY.md +76 -0
  10. ciscoyoke-0.1.0a1/docs/SPEC.md +1439 -0
  11. ciscoyoke-0.1.0a1/docs/THREAT-MODEL.md +359 -0
  12. ciscoyoke-0.1.0a1/pyproject.toml +102 -0
  13. ciscoyoke-0.1.0a1/src/ciscoyoke/__init__.py +7 -0
  14. ciscoyoke-0.1.0a1/src/ciscoyoke/capture.py +192 -0
  15. ciscoyoke-0.1.0a1/src/ciscoyoke/capturing.py +309 -0
  16. ciscoyoke-0.1.0a1/src/ciscoyoke/cli.py +570 -0
  17. ciscoyoke-0.1.0a1/src/ciscoyoke/cli_extra.py +461 -0
  18. ciscoyoke-0.1.0a1/src/ciscoyoke/commands.py +465 -0
  19. ciscoyoke-0.1.0a1/src/ciscoyoke/credentials.py +168 -0
  20. ciscoyoke-0.1.0a1/src/ciscoyoke/diagnose.py +200 -0
  21. ciscoyoke-0.1.0a1/src/ciscoyoke/doctor.py +235 -0
  22. ciscoyoke-0.1.0a1/src/ciscoyoke/identify/__init__.py +1 -0
  23. ciscoyoke-0.1.0a1/src/ciscoyoke/identify/facts.py +229 -0
  24. ciscoyoke-0.1.0a1/src/ciscoyoke/identify/memory.py +72 -0
  25. ciscoyoke-0.1.0a1/src/ciscoyoke/identify/probe.py +147 -0
  26. ciscoyoke-0.1.0a1/src/ciscoyoke/image/__init__.py +1 -0
  27. ciscoyoke-0.1.0a1/src/ciscoyoke/image/bootproof.py +237 -0
  28. ciscoyoke-0.1.0a1/src/ciscoyoke/image/compat.py +212 -0
  29. ciscoyoke-0.1.0a1/src/ciscoyoke/image/drivers.py +290 -0
  30. ciscoyoke-0.1.0a1/src/ciscoyoke/image/fingerprint.py +106 -0
  31. ciscoyoke-0.1.0a1/src/ciscoyoke/image/plan.py +408 -0
  32. ciscoyoke-0.1.0a1/src/ciscoyoke/image/tftp.py +226 -0
  33. ciscoyoke-0.1.0a1/src/ciscoyoke/imaging.py +473 -0
  34. ciscoyoke-0.1.0a1/src/ciscoyoke/interactive.py +360 -0
  35. ciscoyoke-0.1.0a1/src/ciscoyoke/journal/__init__.py +1 -0
  36. ciscoyoke-0.1.0a1/src/ciscoyoke/journal/converge.py +186 -0
  37. ciscoyoke-0.1.0a1/src/ciscoyoke/journal/lease.py +238 -0
  38. ciscoyoke-0.1.0a1/src/ciscoyoke/journal/model.py +273 -0
  39. ciscoyoke-0.1.0a1/src/ciscoyoke/journal/paths.py +74 -0
  40. ciscoyoke-0.1.0a1/src/ciscoyoke/journal/store.py +270 -0
  41. ciscoyoke-0.1.0a1/src/ciscoyoke/labs.py +229 -0
  42. ciscoyoke-0.1.0a1/src/ciscoyoke/lifecycle/__init__.py +1 -0
  43. ciscoyoke-0.1.0a1/src/ciscoyoke/lifecycle/archive.py +349 -0
  44. ciscoyoke-0.1.0a1/src/ciscoyoke/lifecycle/health.py +183 -0
  45. ciscoyoke-0.1.0a1/src/ciscoyoke/lifecycle/recover.py +179 -0
  46. ciscoyoke-0.1.0a1/src/ciscoyoke/lifecycle/rescue.py +231 -0
  47. ciscoyoke-0.1.0a1/src/ciscoyoke/lifecycle/reset.py +458 -0
  48. ciscoyoke-0.1.0a1/src/ciscoyoke/platform_profiles.py +203 -0
  49. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/__init__.py +1 -0
  50. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/base.py +380 -0
  51. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/human.py +227 -0
  52. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/ios_router.py +183 -0
  53. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/ios_switch.py +423 -0
  54. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/transfer.py +211 -0
  55. ciscoyoke-0.1.0a1/src/ciscoyoke/playbook/xmodem.py +316 -0
  56. ciscoyoke-0.1.0a1/src/ciscoyoke/report.py +223 -0
  57. ciscoyoke-0.1.0a1/src/ciscoyoke/result/__init__.py +1 -0
  58. ciscoyoke-0.1.0a1/src/ciscoyoke/result/exits.py +39 -0
  59. ciscoyoke-0.1.0a1/src/ciscoyoke/result/schema.py +112 -0
  60. ciscoyoke-0.1.0a1/src/ciscoyoke/session.py +273 -0
  61. ciscoyoke-0.1.0a1/src/ciscoyoke/stream/__init__.py +1 -0
  62. ciscoyoke-0.1.0a1/src/ciscoyoke/stream/buffer.py +70 -0
  63. ciscoyoke-0.1.0a1/src/ciscoyoke/stream/signals.py +261 -0
  64. ciscoyoke-0.1.0a1/src/ciscoyoke/stream/tracker.py +292 -0
  65. ciscoyoke-0.1.0a1/src/ciscoyoke/support.py +304 -0
  66. ciscoyoke-0.1.0a1/src/ciscoyoke/topology/__init__.py +1 -0
  67. ciscoyoke-0.1.0a1/src/ciscoyoke/topology/apply.py +194 -0
  68. ciscoyoke-0.1.0a1/src/ciscoyoke/topology/labfile.py +317 -0
  69. ciscoyoke-0.1.0a1/src/ciscoyoke/topology/verify.py +277 -0
  70. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/__init__.py +1 -0
  71. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/fake.py +219 -0
  72. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/recorder.py +60 -0
  73. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/replay.py +106 -0
  74. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/schema.py +170 -0
  75. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/scrub.py +302 -0
  76. ciscoyoke-0.1.0a1/src/ciscoyoke/transcript/writer.py +98 -0
  77. ciscoyoke-0.1.0a1/src/ciscoyoke/transport/__init__.py +1 -0
  78. ciscoyoke-0.1.0a1/src/ciscoyoke/transport/base.py +167 -0
  79. ciscoyoke-0.1.0a1/src/ciscoyoke/transport/identity.py +150 -0
  80. ciscoyoke-0.1.0a1/src/ciscoyoke/transport/labels.py +169 -0
  81. ciscoyoke-0.1.0a1/src/ciscoyoke/transport/rfc2217.py +152 -0
  82. ciscoyoke-0.1.0a1/src/ciscoyoke/transport/serial_.py +186 -0
  83. ciscoyoke-0.1.0a1/src/ciscoyoke/ui.py +120 -0
  84. ciscoyoke-0.1.0a1/tests/fixtures/README.md +55 -0
  85. ciscoyoke-0.1.0a1/tests/fixtures/hw-switch-2950-cold-boot-locked.ytx.pub +2 -0
  86. ciscoyoke-0.1.0a1/tests/fixtures/hw-switch-2950-recover-no-restore.ytx.pub +21 -0
  87. ciscoyoke-0.1.0a1/tests/fixtures/hw-switch-2950-recover-rename-hidden-by-syslog.ytx.pub +23 -0
  88. ciscoyoke-0.1.0a1/tests/fixtures/router-1760-intake.ytx.pub +11 -0
  89. ciscoyoke-0.1.0a1/tests/fixtures/router-1760-rommon.ytx.pub +3 -0
  90. ciscoyoke-0.1.0a1/tests/fixtures/switch-2950-bootloader.ytx.pub +7 -0
  91. ciscoyoke-0.1.0a1/tests/fixtures/switch-2950-locked.ytx.pub +4 -0
  92. ciscoyoke-0.1.0a1/tests/fixtures/switch-2950-recovery-disabled.ytx.pub +5 -0
  93. ciscoyoke-0.1.0a1/tests/test_archive.py +173 -0
  94. ciscoyoke-0.1.0a1/tests/test_capture.py +204 -0
  95. ciscoyoke-0.1.0a1/tests/test_chunk_invariance.py +107 -0
  96. ciscoyoke-0.1.0a1/tests/test_clean_reset.py +245 -0
  97. ciscoyoke-0.1.0a1/tests/test_cli.py +158 -0
  98. ciscoyoke-0.1.0a1/tests/test_credentials.py +167 -0
  99. ciscoyoke-0.1.0a1/tests/test_front_door.py +44 -0
  100. ciscoyoke-0.1.0a1/tests/test_hardware_fixtures.py +151 -0
  101. ciscoyoke-0.1.0a1/tests/test_image.py +394 -0
  102. ciscoyoke-0.1.0a1/tests/test_intake_replay.py +150 -0
  103. ciscoyoke-0.1.0a1/tests/test_interactive.py +206 -0
  104. ciscoyoke-0.1.0a1/tests/test_journal.py +290 -0
  105. ciscoyoke-0.1.0a1/tests/test_lease.py +147 -0
  106. ciscoyoke-0.1.0a1/tests/test_packaging.py +28 -0
  107. ciscoyoke-0.1.0a1/tests/test_platform_families.py +84 -0
  108. ciscoyoke-0.1.0a1/tests/test_playbook.py +408 -0
  109. ciscoyoke-0.1.0a1/tests/test_remote_support.py +290 -0
  110. ciscoyoke-0.1.0a1/tests/test_rescue.py +260 -0
  111. ciscoyoke-0.1.0a1/tests/test_round4_fixes.py +449 -0
  112. ciscoyoke-0.1.0a1/tests/test_round5_fixes.py +347 -0
  113. ciscoyoke-0.1.0a1/tests/test_scrub.py +130 -0
  114. ciscoyoke-0.1.0a1/tests/test_switch_recovery.py +198 -0
  115. ciscoyoke-0.1.0a1/tests/test_topology.py +304 -0
  116. ciscoyoke-0.1.0a1/tests/test_tracker.py +142 -0
  117. ciscoyoke-0.1.0a1/tests/test_transcript.py +161 -0
  118. ciscoyoke-0.1.0a1/tests/test_transport.py +135 -0
  119. ciscoyoke-0.1.0a1/tests/test_ui.py +87 -0
  120. ciscoyoke-0.1.0a1/tests/test_xmodem.py +274 -0
@@ -0,0 +1,31 @@
1
+ # Raw transcripts are private by definition: they can contain a previous
2
+ # owner's credentials, addressing and keys. Only scrubbed .ytx.pub fixtures
3
+ # belong in the repository. CI enforces this too.
4
+ *.ytx
5
+ !*.ytx.pub
6
+
7
+ # Salvaged configuration from second-hand gear is somebody else's network.
8
+ archives/
9
+ *.cfg.salvaged
10
+
11
+ # Operational state: journals and transport leases.
12
+ state.db
13
+ state.db-wal
14
+ state.db-shm
15
+ locks/
16
+
17
+ .venv/
18
+ __pycache__/
19
+ *.py[cod]
20
+ build/
21
+ dist/
22
+ *.egg-info/
23
+ .pytest_cache/
24
+ .mypy_cache/
25
+ .ruff_cache/
26
+ .hypothesis/
27
+ .coverage
28
+ htmlcov/
29
+
30
+ # Meta-documentation about building the project is not project documentation.
31
+ *.docx
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ All notable changes. Versions follow [PEP 440](https://peps.python.org/pep-0440/);
4
+ the format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.0a1] - 2026-09-30
9
+
10
+ First public alpha. Run end to end on a real Catalyst 2950; the 2960 family is
11
+ implemented from Cisco's documentation and wants testers.
12
+
13
+ ### Added
14
+ - `rescue`, `scan`, `intake`, `health`, `archive`, `doctor`, `capture`,
15
+ `sweep`: identify and preserve without changing anything. `scan` shows what
16
+ each device needs next.
17
+ - `recover access`: guided password recovery for Catalysts (Mode button) and
18
+ routers (break), with `--no-restore` for a clean device and `--platform` for
19
+ a locked one.
20
+ - `reset`: a clean lab baseline, deleting `vlan.dat` and stale configuration
21
+ files only after archiving them, and proving the deletions.
22
+ - `recover image`: XMODEM image rescue ending in boot proof.
23
+ - Platform profiles per Catalyst family, each labelled by the evidence behind
24
+ it (`hardware`, `documentation`, `generic`).
25
+ - `report` and `transcript replay`: a failed run on hardware nobody here owns
26
+ becomes a scrubbed report, then a replayed fixture and a failing test.
27
+ - Three scrubbed recordings from a real WS-C2950G-24-EI as test fixtures.
28
+
29
+ ### Fixed (found on first contact with real hardware)
30
+ - Bootloader prompts ending LF-CR were not recognised.
31
+ - A rename over an existing `config.old` failed silently, and the switch booted
32
+ back into its login.
33
+ - A console log message landing after an IOS question hid the question.
34
+ - Scrubbing missed secrets split across serial reads, a RADIUS key written
35
+ after `auth-port`/`acct-port`, banners naming the previous owner, and serial
36
+ numbers and MAC addresses.
37
+
38
+ [Unreleased]: https://github.com/Ryan-Clinton/ciscoyoke/compare/v0.1.0a1...HEAD
39
+ [0.1.0a1]: https://github.com/Ryan-Clinton/ciscoyoke/releases/tag/v0.1.0a1
@@ -0,0 +1,65 @@
1
+ # Contributing
2
+
3
+ **You don't need to write Python to help.** ciscoyoke's weakest point is the
4
+ hardware nobody here owns, and the most valuable contribution is evidence from
5
+ yours.
6
+
7
+ ## Ways to help, roughly in order of value
8
+
9
+ 1. **Test on hardware you own.** Anything in the
10
+ [wanted table](README.md#hardware-tested-and-wanted), or anything not in it.
11
+ `ciscoyoke rescue PORT` is read-only and a good start.
12
+ 2. **Send a report when it fails, or when it works on something new.**
13
+ `ciscoyoke report` builds one zip: the run scrubbed, with configuration output
14
+ removed. Read the transcript inside, then open a
15
+ [hardware report](https://github.com/Ryan-Clinton/ciscoyoke/issues/new?template=hardware-report.yml).
16
+ Include the model from the label and what the LEDs did. No recording holds
17
+ either.
18
+ 3. **Add a platform profile from Cisco's documentation.** One entry in
19
+ `src/ciscoyoke/platform_profiles.py`: when to release Mode, whether the
20
+ bootloader has `load_helper`, the console port, and the link to the Cisco
21
+ document you took it from. It's marked `documentation` until someone runs it.
22
+ 4. **Improve detection.** A prompt the tool didn't recognise is usually one
23
+ pattern in `src/ciscoyoke/stream/signals.py` plus a test built from the real
24
+ text.
25
+ 5. **Docs**: anything that confused you is a bug.
26
+ 6. **Code**: see below.
27
+
28
+ Issues labelled [good first issue](https://github.com/Ryan-Clinton/ciscoyoke/labels/good%20first%20issue)
29
+ and [help wanted](https://github.com/Ryan-Clinton/ciscoyoke/labels/help%20wanted)
30
+ are the places to start.
31
+
32
+ **Issues aren't assigned.** There's no need to ask to work on one: open a pull
33
+ request (a draft is fine, early is welcome) and it'll be reviewed. If two land
34
+ for the same issue, the first one that's ready gets merged. Hardware issues are
35
+ open to anyone who owns the device.
36
+
37
+ ## Two rules that aren't negotiable
38
+
39
+ - **Never commit a raw recording** (`.ytx`), and never commit one that read
40
+ somebody's configuration, however well it scrubs. CI refuses raw ones; the
41
+ second is on you. See [tests/fixtures/README.md](tests/fixtures/README.md).
42
+ - **Never claim support that isn't earned.** A ● needs a committed hardware
43
+ recording; documentation-derived work is ○. See
44
+ [docs/HARDWARE-TESTING.md](docs/HARDWARE-TESTING.md).
45
+
46
+ ## Working on the code
47
+
48
+ ```bash
49
+ git clone https://github.com/Ryan-Clinton/ciscoyoke
50
+ cd ciscoyoke
51
+ python -m venv .venv
52
+ .venv/bin/pip install -e ".[dev]" # Windows: .venv\Scripts\pip
53
+ .venv/bin/pytest # no hardware needed
54
+ .venv/bin/ruff check src tests && .venv/bin/mypy
55
+ ```
56
+
57
+ The suite runs against recorded device behaviour, so nothing needs to be plugged
58
+ in. A change to how the tool reads a console should come with a test built from
59
+ real device output where there is any: `ciscoyoke transcript replay` shows what
60
+ the tracker makes of a recording.
61
+
62
+ [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) is the quickest orientation;
63
+ [docs/SPEC.md](docs/SPEC.md) is the whole design.
64
+
65
+ Be decent to each other: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryan Clinton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,291 @@
1
+ Metadata-Version: 2.5
2
+ Name: ciscoyoke
3
+ Version: 0.1.0a1
4
+ Summary: Rescue old Cisco hardware from the serial console: identify, preserve, recover and reset second-hand Catalysts and routers, with no management IP.
5
+ Project-URL: Homepage, https://github.com/Ryan-Clinton/ciscoyoke
6
+ Project-URL: Specification, https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SPEC.md
7
+ Project-URL: Changelog, https://github.com/Ryan-Clinton/ciscoyoke/blob/main/CHANGELOG.md
8
+ Project-URL: Issues, https://github.com/Ryan-Clinton/ciscoyoke/issues
9
+ Project-URL: Hardware reports, https://github.com/Ryan-Clinton/ciscoyoke/issues/new?template=hardware-report.yml
10
+ Author: Ryan Clinton
11
+ License: MIT License
12
+
13
+ Copyright (c) 2026 Ryan Clinton
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in all
23
+ copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ SOFTWARE.
32
+ License-File: LICENSE
33
+ Keywords: catalyst,ccna,cisco,cisco-ios,console,homelab,network-automation,password-recovery,recovery,rommon,serial,serial-console,xmodem
34
+ Classifier: Development Status :: 3 - Alpha
35
+ Classifier: Environment :: Console
36
+ Classifier: Intended Audience :: System Administrators
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Topic :: System :: Networking
42
+ Classifier: Topic :: System :: Recovery Tools
43
+ Requires-Python: >=3.11
44
+ Requires-Dist: platformdirs>=4.0
45
+ Requires-Dist: pyserial>=3.5
46
+ Requires-Dist: rich>=13.0
47
+ Provides-Extra: dev
48
+ Requires-Dist: hypothesis>=6.100; extra == 'dev'
49
+ Requires-Dist: mypy>=1.10; extra == 'dev'
50
+ Requires-Dist: pytest>=8.0; extra == 'dev'
51
+ Requires-Dist: ruff>=0.5; extra == 'dev'
52
+ Requires-Dist: tftpy>=0.8; extra == 'dev'
53
+ Provides-Extra: tftp
54
+ Requires-Dist: tftpy>=0.8; extra == 'tftp'
55
+ Description-Content-Type: text/markdown
56
+
57
+ # ciscoyoke
58
+
59
+ [![CI](https://github.com/Ryan-Clinton/ciscoyoke/actions/workflows/ci.yml/badge.svg)](https://github.com/Ryan-Clinton/ciscoyoke/actions/workflows/ci.yml)
60
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
61
+ [![Licence: MIT](https://img.shields.io/badge/licence-MIT-green.svg)](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/LICENSE)
62
+ [![Status: early alpha](https://img.shields.io/badge/status-early%20alpha-orange.svg)](#hardware-tested-and-wanted)
63
+
64
+ **Rescue old Cisco hardware from the serial console.**
65
+
66
+ Bought a Catalyst on eBay? Inherited a switch with somebody else's password?
67
+ Found one in a store room that nobody has the login for? Got a `switch:` prompt
68
+ and no working IOS? Not even sure which COM port the cable is on?
69
+
70
+ ```
71
+ unknown / locked / broken known-good lab device
72
+ │ ▲
73
+ └──── console cable ──► ciscoyoke ────────────┘
74
+ no IP address needed
75
+ ```
76
+
77
+ <p align="center">
78
+ <img src="https://raw.githubusercontent.com/Ryan-Clinton/ciscoyoke/main/docs/demo/2950-recovery.svg" alt="A real Catalyst 2950 going from the Mode-button bootloader to an unlocked Switch# prompt, replayed from a committed hardware recording" width="100%">
79
+ </p>
80
+ <p align="center"><sub>Not a mock-up: a real WS-C2950G-24-EI, replayed from
81
+ <a href="https://github.com/Ryan-Clinton/ciscoyoke/blob/main/tests/fixtures/hw-switch-2950-recover-no-restore.ytx.pub">its committed recording</a>
82
+ with the long silences shortened. Serial numbers and MAC scrubbed.</sub></p>
83
+
84
+ > **Early alpha.** Run end to end on a real Catalyst 2950; the 2960 family is
85
+ > implemented from Cisco's documentation and **wants testers**. See
86
+ > [hardware](#hardware-tested-and-wanted).
87
+
88
+ ## Try it
89
+
90
+ ```bash
91
+ pipx install git+https://github.com/Ryan-Clinton/ciscoyoke # works today
92
+ # pipx install ciscoyoke # from PyPI, once 0.1.0a1 is released
93
+
94
+ ciscoyoke doctor # is the cable and adapter OK?
95
+ ciscoyoke scan # what is on every serial port?
96
+ ciscoyoke rescue COM4 # what is this device, and what does it need?
97
+ ```
98
+
99
+ **Most people only need `ciscoyoke rescue`.** It identifies the device, works
100
+ out its state, preserves whatever it can read, and tells you the safest next
101
+ command — then stops, because everything after that changes the device and is
102
+ your decision.
103
+
104
+ ## Three real sessions
105
+
106
+ These are real output from the bench 2950, abridged.
107
+
108
+ **A switch nobody knows anything about**
109
+
110
+ ```
111
+ $ ciscoyoke intake COM4
112
+
113
+ State: user_exec (observed/high)
114
+ Model: WS-C2950G-24-EI
115
+ IOS version: 12.1(9)EA1
116
+ Config reg: 0xF
117
+
118
+ identified from show version
119
+ No destructive action taken.
120
+ ```
121
+
122
+ **A locked switch**, with a previous owner's console login and enable secret:
123
+
124
+ ```
125
+ $ ciscoyoke recover access COM4 --no-restore --confirm
126
+
127
+ Platform from memory: WS-C2950G-24-EI (seen on this adapter, from intake)
128
+
129
+ HUMAN ACTION REQUIRED
130
+ Unplug the switch. Hold the MODE button down, plug the power back in,
131
+ and release it when the STAT LED goes out (about 5 seconds).
132
+ ✓ observed: bootloader
133
+
134
+ IOS loads config.text (the default); it will be renamed to config.text.ciscoyoke
135
+
136
+ Access recovered, with the previous configuration left aside as
137
+ flash:config.text.ciscoyoke and not loaded. The device is unconfigured and
138
+ at a privileged prompt.
139
+ ```
140
+
141
+ **Then a clean baseline**, with everything it deletes read into an archive first:
142
+
143
+ ```
144
+ $ ciscoyoke reset COM4 --confirm
145
+
146
+ ✓ file_backup.cfg ✓ file_config.old ✓ file_config.text.ciscoyoke
147
+
148
+ ! delete flash:vlan.dat (destroys the VLAN database)
149
+ ! delete flash:backup.cfg (a previous owner's configuration)
150
+ ! delete flash:config.old (a previous owner's configuration)
151
+ ! delete flash:config.text.ciscoyoke (a previous owner's configuration)
152
+ dir flash: (confirm every deletion)
153
+
154
+ Reset complete.
155
+ ```
156
+
157
+ A fourth, **image rescue** for a device with no bootable IOS (XMODEM transfer,
158
+ then proof that IOS actually boots), is implemented but has not met hardware yet.
159
+
160
+ ## Where it fits
161
+
162
+ ciscoyoke doesn't replace network automation. It gets equipment *into* it.
163
+
164
+ ```
165
+ dead / unknown / locked
166
+ │
167
+ ▼
168
+ ciscoyoke serial console, no IP required
169
+ │
170
+ ▼
171
+ known device with an IP
172
+ │
173
+ ├── Netmiko
174
+ ├── Nornir
175
+ ├── Ansible
176
+ └── scrapli SSH / telnet, IP required
177
+ ```
178
+
179
+ Every mainstream tool assumes the device already has an address, a reachable
180
+ management interface and credentials that work. A second-hand box has none of
181
+ those, and everything between "arrived from eBay" and "automation can reach it"
182
+ is usually done by hand with a terminal emulator and a Cisco tech note from 2007.
183
+
184
+ ## Hardware: tested and wanted
185
+
186
+ Support is claimed only when it's earned, and every mark says how:
187
+
188
+ ```
189
+ ● Hardware verified run against a real device; the recording is committed
190
+ ○ Documentation-derived implemented from Cisco's published procedure, never run
191
+ — Not yet attempted
192
+ ```
193
+
194
+ | Device | Identify | Password recovery | Reset | We need |
195
+ | --- | --- | --- | --- | --- |
196
+ | Catalyst 2950 | ● | ● | — ¹ | more variants |
197
+ | Catalyst 2960 | ○ | ○ | ○ | **a tester** |
198
+ | Catalyst 2960-S / X / Plus | ○ | ○ | ○ | **a tester** (USB console too) |
199
+ | Catalyst 3550 / 3560 / 3750 | — | — | — | **a tester**, or a profile from Cisco's docs ² |
200
+ | Cisco 1700 / 1800 / 1841 routers | — | — | — | **a tester** |
201
+
202
+ ¹ Reset has run end to end on the 2950, but its only recording held a previous
203
+ owner's configuration, so it isn't published and the mark isn't claimed.
204
+ ² No model-specific profile yet: these get Cisco's general procedure with
205
+ longer waits, and destructive commands ask for `--accept-unverified`.
206
+ Per-mark evidence: [docs/HARDWARE-TESTING.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/HARDWARE-TESTING.md).
207
+
208
+ **Got one of these?** Run `ciscoyoke rescue COM4`. If anything goes wrong:
209
+
210
+ ```
211
+ ciscoyoke report # one zip: the run scrubbed, configuration output removed,
212
+ # what it expected, what it saw, and your adapter
213
+ ```
214
+
215
+ and attach it to a [hardware report](https://github.com/Ryan-Clinton/ciscoyoke/issues/new?template=hardware-report.yml).
216
+ That's the most useful contribution there is, and it needs no Python.
217
+
218
+ ## Real sessions become tests
219
+
220
+ ```
221
+ real Cisco hardware
222
+ │
223
+ ▼
224
+ serial transcript recorded by every destructive run
225
+ │
226
+ ▼
227
+ scrub secrets passwords, keys, addresses, serials; config output removed
228
+ │
229
+ ▼
230
+ fixture committed tests/fixtures/hw-*.ytx.pub
231
+ │
232
+ ▼
233
+ CI replays it forever on Windows, macOS and Linux, with nothing plugged in
234
+ ```
235
+
236
+ 309 tests passed before the first real switch was connected. It still found
237
+ defects none of them could — LF-CR line endings, a rename that failed silently,
238
+ a log message hiding an IOS question — and each now has a test built from what
239
+ the real switch sent, most of them replaying its recording directly.
240
+
241
+ ## Designed not to brick your switch
242
+
243
+ - Destructive commands are **dry runs** until you add `--confirm`.
244
+ - Configuration is **read into an archive before anything deletes it**, and the
245
+ archive says plainly what it couldn't read.
246
+ - Every change is **journalled before it's sent**, so an interrupted run can be
247
+ reconciled against the device (`ciscoyoke resolve`).
248
+ - Renames and deletions are **proven from a fresh flash listing**, not assumed
249
+ from the prompt coming back.
250
+ - An image rescue **isn't a success until IOS boots** the image you supplied.
251
+ - Recordings stay **private until scrubbed**; CI refuses a raw one.
252
+
253
+ More: [docs/SAFETY.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SAFETY.md) · [threat model](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/THREAT-MODEL.md) ·
254
+ [architecture](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/ARCHITECTURE.md) · [specification](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SPEC.md)
255
+
256
+ ## Commands
257
+
258
+ | Look, change nothing | |
259
+ | --- | --- |
260
+ | `ciscoyoke rescue PORT` | **start here**: identify, preserve, recommend |
261
+ | `ciscoyoke scan` | every serial port: state, model, and what each needs next |
262
+ | `ciscoyoke doctor` | cable, adapter, permissions and driver checks |
263
+ | `ciscoyoke intake PORT` / `health PORT` / `archive PORT` | identify / check / preserve one device |
264
+ | `ciscoyoke capture PORT -o F` / `sweep PORT` | record a boot / find the line speed |
265
+ | `ciscoyoke report` | package the last run for a bug report |
266
+
267
+ | Change the device (dry run unless `--confirm`) | |
268
+ | --- | --- |
269
+ | `ciscoyoke recover access PORT` | password recovery, guided through the Mode button or break |
270
+ | `ciscoyoke reset PORT` | erase to a clean lab baseline |
271
+ | `ciscoyoke recover image PORT --image F` | XMODEM rescue for a device with no bootable IOS |
272
+ | `ciscoyoke lab apply LABFILE` | push per-device lab configuration |
273
+
274
+ Every option is in [docs/SAFETY.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SAFETY.md) and `ciscoyoke <command> --help`.
275
+
276
+ ## Contributing
277
+
278
+ You don't need to write Python. Testing on hardware you own, sending a
279
+ `ciscoyoke report`, or adding a platform profile from Cisco's documentation are
280
+ all real contributions. See [CONTRIBUTING.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/CONTRIBUTING.md).
281
+
282
+ ## Firmware
283
+
284
+ ciscoyoke **never hosts, mirrors, searches for or redistributes Cisco IOS
285
+ images**, and no feature accepts a URL to fetch one from. It accepts an image
286
+ you supply and automates transport and verification. Lawful entitlement to any
287
+ image is your responsibility.
288
+
289
+ ## Licence
290
+
291
+ MIT.