Metadata-Version: 2.5
Name: ciscoyoke
Version: 0.1.0a1
Summary: Rescue old Cisco hardware from the serial console: identify, preserve, recover and reset second-hand Catalysts and routers, with no management IP.
Project-URL: Homepage, https://github.com/Ryan-Clinton/ciscoyoke
Project-URL: Specification, https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SPEC.md
Project-URL: Changelog, https://github.com/Ryan-Clinton/ciscoyoke/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/Ryan-Clinton/ciscoyoke/issues
Project-URL: Hardware reports, https://github.com/Ryan-Clinton/ciscoyoke/issues/new?template=hardware-report.yml
Author: Ryan Clinton
License: MIT License
        
        Copyright (c) 2026 Ryan Clinton
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: catalyst,ccna,cisco,cisco-ios,console,homelab,network-automation,password-recovery,recovery,rommon,serial,serial-console,xmodem
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Recovery Tools
Requires-Python: >=3.11
Requires-Dist: platformdirs>=4.0
Requires-Dist: pyserial>=3.5
Requires-Dist: rich>=13.0
Provides-Extra: dev
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: tftpy>=0.8; extra == 'dev'
Provides-Extra: tftp
Requires-Dist: tftpy>=0.8; extra == 'tftp'
Description-Content-Type: text/markdown

# ciscoyoke

[![CI](https://github.com/Ryan-Clinton/ciscoyoke/actions/workflows/ci.yml/badge.svg)](https://github.com/Ryan-Clinton/ciscoyoke/actions/workflows/ci.yml)
[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
[![Licence: MIT](https://img.shields.io/badge/licence-MIT-green.svg)](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/LICENSE)
[![Status: early alpha](https://img.shields.io/badge/status-early%20alpha-orange.svg)](#hardware-tested-and-wanted)

**Rescue old Cisco hardware from the serial console.**

Bought a Catalyst on eBay? Inherited a switch with somebody else's password?
Found one in a store room that nobody has the login for? Got a `switch:` prompt
and no working IOS? Not even sure which COM port the cable is on?

```
   unknown / locked / broken                       known-good lab device
            │                                               ▲
            └──── console cable ──►  ciscoyoke  ────────────┘
                                   no IP address needed
```

<p align="center">
  <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%">
</p>
<p align="center"><sub>Not a mock-up: a real WS-C2950G-24-EI, replayed from
<a href="https://github.com/Ryan-Clinton/ciscoyoke/blob/main/tests/fixtures/hw-switch-2950-recover-no-restore.ytx.pub">its committed recording</a>
with the long silences shortened. Serial numbers and MAC scrubbed.</sub></p>

> **Early alpha.** Run end to end on a real Catalyst 2950; the 2960 family is
> implemented from Cisco's documentation and **wants testers**. See
> [hardware](#hardware-tested-and-wanted).

## Try it

```bash
pipx install git+https://github.com/Ryan-Clinton/ciscoyoke   # works today
# pipx install ciscoyoke                                      # from PyPI, once 0.1.0a1 is released

ciscoyoke doctor          # is the cable and adapter OK?
ciscoyoke scan            # what is on every serial port?
ciscoyoke rescue COM4     # what is this device, and what does it need?
```

**Most people only need `ciscoyoke rescue`.** It identifies the device, works
out its state, preserves whatever it can read, and tells you the safest next
command — then stops, because everything after that changes the device and is
your decision.

## Three real sessions

These are real output from the bench 2950, abridged.

**A switch nobody knows anything about**

```
$ ciscoyoke intake COM4

State:        user_exec (observed/high)
Model:        WS-C2950G-24-EI
IOS version:  12.1(9)EA1
Config reg:   0xF

identified from show version
No destructive action taken.
```

**A locked switch**, with a previous owner's console login and enable secret:

```
$ ciscoyoke recover access COM4 --no-restore --confirm

Platform from memory: WS-C2950G-24-EI (seen on this adapter, from intake)

HUMAN ACTION REQUIRED
  Unplug the switch. Hold the MODE button down, plug the power back in,
  and release it when the STAT LED goes out (about 5 seconds).
  ✓ observed: bootloader

  IOS loads config.text (the default); it will be renamed to config.text.ciscoyoke

Access recovered, with the previous configuration left aside as
flash:config.text.ciscoyoke and not loaded. The device is unconfigured and
at a privileged prompt.
```

**Then a clean baseline**, with everything it deletes read into an archive first:

```
$ ciscoyoke reset COM4 --confirm

  ✓ file_backup.cfg        ✓ file_config.old        ✓ file_config.text.ciscoyoke

  ! delete flash:vlan.dat (destroys the VLAN database)
  ! delete flash:backup.cfg (a previous owner's configuration)
  ! delete flash:config.old (a previous owner's configuration)
  ! delete flash:config.text.ciscoyoke (a previous owner's configuration)
    dir flash: (confirm every deletion)

Reset complete.
```

A fourth, **image rescue** for a device with no bootable IOS (XMODEM transfer,
then proof that IOS actually boots), is implemented but has not met hardware yet.

## Where it fits

ciscoyoke doesn't replace network automation. It gets equipment *into* it.

```
dead / unknown / locked
         │
         ▼
     ciscoyoke           serial console, no IP required
         │
         ▼
known device with an IP
         │
         ├── Netmiko
         ├── Nornir
         ├── Ansible
         └── scrapli     SSH / telnet, IP required
```

Every mainstream tool assumes the device already has an address, a reachable
management interface and credentials that work. A second-hand box has none of
those, and everything between "arrived from eBay" and "automation can reach it"
is usually done by hand with a terminal emulator and a Cisco tech note from 2007.

## Hardware: tested and wanted

Support is claimed only when it's earned, and every mark says how:

```
● Hardware verified      run against a real device; the recording is committed
○ Documentation-derived  implemented from Cisco's published procedure, never run
— Not yet attempted
```

| Device | Identify | Password recovery | Reset | We need |
| --- | --- | --- | --- | --- |
| Catalyst 2950 | ● | ● | — ¹ | more variants |
| Catalyst 2960 | ○ | ○ | ○ | **a tester** |
| Catalyst 2960-S / X / Plus | ○ | ○ | ○ | **a tester** (USB console too) |
| Catalyst 3550 / 3560 / 3750 | — | — | — | **a tester**, or a profile from Cisco's docs ² |
| Cisco 1700 / 1800 / 1841 routers | — | — | — | **a tester** |

¹ Reset has run end to end on the 2950, but its only recording held a previous
owner's configuration, so it isn't published and the mark isn't claimed.
² No model-specific profile yet: these get Cisco's general procedure with
longer waits, and destructive commands ask for `--accept-unverified`.
Per-mark evidence: [docs/HARDWARE-TESTING.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/HARDWARE-TESTING.md).

**Got one of these?** Run `ciscoyoke rescue COM4`. If anything goes wrong:

```
ciscoyoke report     # one zip: the run scrubbed, configuration output removed,
                     # what it expected, what it saw, and your adapter
```

and attach it to a [hardware report](https://github.com/Ryan-Clinton/ciscoyoke/issues/new?template=hardware-report.yml).
That's the most useful contribution there is, and it needs no Python.

## Real sessions become tests

```
real Cisco hardware
       │
       ▼
serial transcript        recorded by every destructive run
       │
       ▼
scrub secrets            passwords, keys, addresses, serials; config output removed
       │
       ▼
fixture committed        tests/fixtures/hw-*.ytx.pub
       │
       ▼
CI replays it forever    on Windows, macOS and Linux, with nothing plugged in
```

309 tests passed before the first real switch was connected. It still found
defects none of them could — LF-CR line endings, a rename that failed silently,
a log message hiding an IOS question — and each now has a test built from what
the real switch sent, most of them replaying its recording directly.

## Designed not to brick your switch

- Destructive commands are **dry runs** until you add `--confirm`.
- Configuration is **read into an archive before anything deletes it**, and the
  archive says plainly what it couldn't read.
- Every change is **journalled before it's sent**, so an interrupted run can be
  reconciled against the device (`ciscoyoke resolve`).
- Renames and deletions are **proven from a fresh flash listing**, not assumed
  from the prompt coming back.
- An image rescue **isn't a success until IOS boots** the image you supplied.
- Recordings stay **private until scrubbed**; CI refuses a raw one.

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) ·
[architecture](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/ARCHITECTURE.md) · [specification](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SPEC.md)

## Commands

| Look, change nothing | |
| --- | --- |
| `ciscoyoke rescue PORT` | **start here**: identify, preserve, recommend |
| `ciscoyoke scan` | every serial port: state, model, and what each needs next |
| `ciscoyoke doctor` | cable, adapter, permissions and driver checks |
| `ciscoyoke intake PORT` / `health PORT` / `archive PORT` | identify / check / preserve one device |
| `ciscoyoke capture PORT -o F` / `sweep PORT` | record a boot / find the line speed |
| `ciscoyoke report` | package the last run for a bug report |

| Change the device (dry run unless `--confirm`) | |
| --- | --- |
| `ciscoyoke recover access PORT` | password recovery, guided through the Mode button or break |
| `ciscoyoke reset PORT` | erase to a clean lab baseline |
| `ciscoyoke recover image PORT --image F` | XMODEM rescue for a device with no bootable IOS |
| `ciscoyoke lab apply LABFILE` | push per-device lab configuration |

Every option is in [docs/SAFETY.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/docs/SAFETY.md) and `ciscoyoke <command> --help`.

## Contributing

You don't need to write Python. Testing on hardware you own, sending a
`ciscoyoke report`, or adding a platform profile from Cisco's documentation are
all real contributions. See [CONTRIBUTING.md](https://github.com/Ryan-Clinton/ciscoyoke/blob/main/CONTRIBUTING.md).

## Firmware

ciscoyoke **never hosts, mirrors, searches for or redistributes Cisco IOS
images**, and no feature accepts a URL to fetch one from. It accepts an image
you supply and automates transport and verification. Lawful entitlement to any
image is your responsibility.

## Licence

MIT.
